From 3e3dbbc62f8fb12b499d47ea19dae43702e9f137 Mon Sep 17 00:00:00 2001 From: qubka Date: Thu, 11 Sep 2025 13:02:40 +0100 Subject: [PATCH 01/10] fix: replace static by reinterpret cast --- include/plg/plugin.hpp | 36 +++++++++---------- .../external/plugify/include/plg/plugin.hpp | 36 +++++++++---------- .../external/plugify/include/plg/plugin.hpp | 36 +++++++++---------- .../external/plugify/include/plg/plugin.hpp | 36 +++++++++---------- 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/include/plg/plugin.hpp b/include/plg/plugin.hpp index 7498a8c..76f2286 100644 --- a/include/plg/plugin.hpp +++ b/include/plg/plugin.hpp @@ -116,24 +116,24 @@ namespace plg { return kApiVersion; \ } \ size_t i = 0; \ - GetMethodPtr = static_cast(api[i++]); \ - GetMethodPtr2 = static_cast(api[i++]); \ - GetBaseDir = static_cast(api[i++]); \ - GetExtensionsDir = static_cast(api[i++]); \ - GetConfigsDir = static_cast(api[i++]); \ - GetDataDir = static_cast(api[i++]); \ - GetLogsDir = static_cast(api[i++]); \ - GetCacheDir = static_cast(api[i++]); \ - IsExtensionLoaded = static_cast(api[i++]); \ - plugin::GetId = static_cast(api[i++]); \ - plugin::GetName = static_cast(api[i++]); \ - plugin::GetDescription = static_cast(api[i++]); \ - plugin::GetVersion = static_cast(api[i++]); \ - plugin::GetAuthor = static_cast(api[i++]); \ - plugin::GetWebsite = static_cast(api[i++]); \ - plugin::GetLicense = static_cast(api[i++]); \ - plugin::GetLocation = static_cast(api[i++]); \ - plugin::GetDependencies = static_cast(api[i++]); \ + GetMethodPtr = reinterpret_cast(api[i++]); \ + GetMethodPtr2 = reinterpret_cast(api[i++]); \ + GetBaseDir = reinterpret_cast(api[i++]); \ + GetExtensionsDir = reinterpret_cast(api[i++]); \ + GetConfigsDir = reinterpret_cast(api[i++]); \ + GetDataDir = reinterpret_cast(api[i++]); \ + GetLogsDir = reinterpret_cast(api[i++]); \ + GetCacheDir = reinterpret_cast(api[i++]); \ + IsExtensionLoaded = reinterpret_cast(api[i++]); \ + plugin::GetId = reinterpret_cast(api[i++]); \ + plugin::GetName = reinterpret_cast(api[i++]); \ + plugin::GetDescription = reinterpret_cast(api[i++]); \ + plugin::GetVersion = reinterpret_cast(api[i++]); \ + plugin::GetAuthor = reinterpret_cast(api[i++]); \ + plugin::GetWebsite = reinterpret_cast(api[i++]); \ + plugin::GetLicense = reinterpret_cast(api[i++]); \ + plugin::GetLocation = reinterpret_cast(api[i++]); \ + plugin::GetDependencies = reinterpret_cast(api[i++]); \ plugin::handle = handle; \ return 0; \ } \ diff --git a/test/cross_call_master/external/plugify/include/plg/plugin.hpp b/test/cross_call_master/external/plugify/include/plg/plugin.hpp index 7498a8c..76f2286 100644 --- a/test/cross_call_master/external/plugify/include/plg/plugin.hpp +++ b/test/cross_call_master/external/plugify/include/plg/plugin.hpp @@ -116,24 +116,24 @@ namespace plg { return kApiVersion; \ } \ size_t i = 0; \ - GetMethodPtr = static_cast(api[i++]); \ - GetMethodPtr2 = static_cast(api[i++]); \ - GetBaseDir = static_cast(api[i++]); \ - GetExtensionsDir = static_cast(api[i++]); \ - GetConfigsDir = static_cast(api[i++]); \ - GetDataDir = static_cast(api[i++]); \ - GetLogsDir = static_cast(api[i++]); \ - GetCacheDir = static_cast(api[i++]); \ - IsExtensionLoaded = static_cast(api[i++]); \ - plugin::GetId = static_cast(api[i++]); \ - plugin::GetName = static_cast(api[i++]); \ - plugin::GetDescription = static_cast(api[i++]); \ - plugin::GetVersion = static_cast(api[i++]); \ - plugin::GetAuthor = static_cast(api[i++]); \ - plugin::GetWebsite = static_cast(api[i++]); \ - plugin::GetLicense = static_cast(api[i++]); \ - plugin::GetLocation = static_cast(api[i++]); \ - plugin::GetDependencies = static_cast(api[i++]); \ + GetMethodPtr = reinterpret_cast(api[i++]); \ + GetMethodPtr2 = reinterpret_cast(api[i++]); \ + GetBaseDir = reinterpret_cast(api[i++]); \ + GetExtensionsDir = reinterpret_cast(api[i++]); \ + GetConfigsDir = reinterpret_cast(api[i++]); \ + GetDataDir = reinterpret_cast(api[i++]); \ + GetLogsDir = reinterpret_cast(api[i++]); \ + GetCacheDir = reinterpret_cast(api[i++]); \ + IsExtensionLoaded = reinterpret_cast(api[i++]); \ + plugin::GetId = reinterpret_cast(api[i++]); \ + plugin::GetName = reinterpret_cast(api[i++]); \ + plugin::GetDescription = reinterpret_cast(api[i++]); \ + plugin::GetVersion = reinterpret_cast(api[i++]); \ + plugin::GetAuthor = reinterpret_cast(api[i++]); \ + plugin::GetWebsite = reinterpret_cast(api[i++]); \ + plugin::GetLicense = reinterpret_cast(api[i++]); \ + plugin::GetLocation = reinterpret_cast(api[i++]); \ + plugin::GetDependencies = reinterpret_cast(api[i++]); \ plugin::handle = handle; \ return 0; \ } \ diff --git a/test/cross_call_worker/external/plugify/include/plg/plugin.hpp b/test/cross_call_worker/external/plugify/include/plg/plugin.hpp index 7498a8c..76f2286 100644 --- a/test/cross_call_worker/external/plugify/include/plg/plugin.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/plugin.hpp @@ -116,24 +116,24 @@ namespace plg { return kApiVersion; \ } \ size_t i = 0; \ - GetMethodPtr = static_cast(api[i++]); \ - GetMethodPtr2 = static_cast(api[i++]); \ - GetBaseDir = static_cast(api[i++]); \ - GetExtensionsDir = static_cast(api[i++]); \ - GetConfigsDir = static_cast(api[i++]); \ - GetDataDir = static_cast(api[i++]); \ - GetLogsDir = static_cast(api[i++]); \ - GetCacheDir = static_cast(api[i++]); \ - IsExtensionLoaded = static_cast(api[i++]); \ - plugin::GetId = static_cast(api[i++]); \ - plugin::GetName = static_cast(api[i++]); \ - plugin::GetDescription = static_cast(api[i++]); \ - plugin::GetVersion = static_cast(api[i++]); \ - plugin::GetAuthor = static_cast(api[i++]); \ - plugin::GetWebsite = static_cast(api[i++]); \ - plugin::GetLicense = static_cast(api[i++]); \ - plugin::GetLocation = static_cast(api[i++]); \ - plugin::GetDependencies = static_cast(api[i++]); \ + GetMethodPtr = reinterpret_cast(api[i++]); \ + GetMethodPtr2 = reinterpret_cast(api[i++]); \ + GetBaseDir = reinterpret_cast(api[i++]); \ + GetExtensionsDir = reinterpret_cast(api[i++]); \ + GetConfigsDir = reinterpret_cast(api[i++]); \ + GetDataDir = reinterpret_cast(api[i++]); \ + GetLogsDir = reinterpret_cast(api[i++]); \ + GetCacheDir = reinterpret_cast(api[i++]); \ + IsExtensionLoaded = reinterpret_cast(api[i++]); \ + plugin::GetId = reinterpret_cast(api[i++]); \ + plugin::GetName = reinterpret_cast(api[i++]); \ + plugin::GetDescription = reinterpret_cast(api[i++]); \ + plugin::GetVersion = reinterpret_cast(api[i++]); \ + plugin::GetAuthor = reinterpret_cast(api[i++]); \ + plugin::GetWebsite = reinterpret_cast(api[i++]); \ + plugin::GetLicense = reinterpret_cast(api[i++]); \ + plugin::GetLocation = reinterpret_cast(api[i++]); \ + plugin::GetDependencies = reinterpret_cast(api[i++]); \ plugin::handle = handle; \ return 0; \ } \ diff --git a/test/example_plugin/external/plugify/include/plg/plugin.hpp b/test/example_plugin/external/plugify/include/plg/plugin.hpp index 7498a8c..76f2286 100644 --- a/test/example_plugin/external/plugify/include/plg/plugin.hpp +++ b/test/example_plugin/external/plugify/include/plg/plugin.hpp @@ -116,24 +116,24 @@ namespace plg { return kApiVersion; \ } \ size_t i = 0; \ - GetMethodPtr = static_cast(api[i++]); \ - GetMethodPtr2 = static_cast(api[i++]); \ - GetBaseDir = static_cast(api[i++]); \ - GetExtensionsDir = static_cast(api[i++]); \ - GetConfigsDir = static_cast(api[i++]); \ - GetDataDir = static_cast(api[i++]); \ - GetLogsDir = static_cast(api[i++]); \ - GetCacheDir = static_cast(api[i++]); \ - IsExtensionLoaded = static_cast(api[i++]); \ - plugin::GetId = static_cast(api[i++]); \ - plugin::GetName = static_cast(api[i++]); \ - plugin::GetDescription = static_cast(api[i++]); \ - plugin::GetVersion = static_cast(api[i++]); \ - plugin::GetAuthor = static_cast(api[i++]); \ - plugin::GetWebsite = static_cast(api[i++]); \ - plugin::GetLicense = static_cast(api[i++]); \ - plugin::GetLocation = static_cast(api[i++]); \ - plugin::GetDependencies = static_cast(api[i++]); \ + GetMethodPtr = reinterpret_cast(api[i++]); \ + GetMethodPtr2 = reinterpret_cast(api[i++]); \ + GetBaseDir = reinterpret_cast(api[i++]); \ + GetExtensionsDir = reinterpret_cast(api[i++]); \ + GetConfigsDir = reinterpret_cast(api[i++]); \ + GetDataDir = reinterpret_cast(api[i++]); \ + GetLogsDir = reinterpret_cast(api[i++]); \ + GetCacheDir = reinterpret_cast(api[i++]); \ + IsExtensionLoaded = reinterpret_cast(api[i++]); \ + plugin::GetId = reinterpret_cast(api[i++]); \ + plugin::GetName = reinterpret_cast(api[i++]); \ + plugin::GetDescription = reinterpret_cast(api[i++]); \ + plugin::GetVersion = reinterpret_cast(api[i++]); \ + plugin::GetAuthor = reinterpret_cast(api[i++]); \ + plugin::GetWebsite = reinterpret_cast(api[i++]); \ + plugin::GetLicense = reinterpret_cast(api[i++]); \ + plugin::GetLocation = reinterpret_cast(api[i++]); \ + plugin::GetDependencies = reinterpret_cast(api[i++]); \ plugin::handle = handle; \ return 0; \ } \ From 23fce3eb3793e967bf225334219f30ac36cfa7e4 Mon Sep 17 00:00:00 2001 From: qubka Date: Fri, 12 Sep 2025 01:18:10 +0100 Subject: [PATCH 02/10] fix: update string hasher --- external/plugify | 2 +- include/plg/hash.hpp | 9 +++++++-- .../external/plugify/include/plg/hash.hpp | 9 +++++++-- .../external/plugify/include/plg/hash.hpp | 9 +++++++-- .../example_plugin/external/plugify/include/plg/hash.hpp | 9 +++++++-- 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/external/plugify b/external/plugify index 672952c..17f13ed 160000 --- a/external/plugify +++ b/external/plugify @@ -1 +1 @@ -Subproject commit 672952c8932b86f1a53a66d92c54a2ab85fa2815 +Subproject commit 17f13eddb49999617122cc9e6c0d3ca885817fd4 diff --git a/include/plg/hash.hpp b/include/plg/hash.hpp index 53f37bf..98c9a27 100644 --- a/include/plg/hash.hpp +++ b/include/plg/hash.hpp @@ -1,8 +1,10 @@ #pragma once +#include #include #include -#include + +#include "plg/string.hpp" namespace plg { // std::hash not in the C++20 standard by default @@ -15,7 +17,7 @@ namespace plg { struct string_hash { using is_transparent = void; // Enables heterogeneous lookup - auto operator()(const char *txt) const { + auto operator()(const char* txt) const { return std::hash{}(txt); } auto operator()(std::string_view txt) const { @@ -24,6 +26,9 @@ namespace plg { auto operator()(const std::string& txt) const { return std::hash{}(txt); } + auto operator()(const plg::string& txt) const { + return std::hash{}(txt); + } }; struct case_insensitive_hash { diff --git a/test/cross_call_master/external/plugify/include/plg/hash.hpp b/test/cross_call_master/external/plugify/include/plg/hash.hpp index 53f37bf..98c9a27 100644 --- a/test/cross_call_master/external/plugify/include/plg/hash.hpp +++ b/test/cross_call_master/external/plugify/include/plg/hash.hpp @@ -1,8 +1,10 @@ #pragma once +#include #include #include -#include + +#include "plg/string.hpp" namespace plg { // std::hash not in the C++20 standard by default @@ -15,7 +17,7 @@ namespace plg { struct string_hash { using is_transparent = void; // Enables heterogeneous lookup - auto operator()(const char *txt) const { + auto operator()(const char* txt) const { return std::hash{}(txt); } auto operator()(std::string_view txt) const { @@ -24,6 +26,9 @@ namespace plg { auto operator()(const std::string& txt) const { return std::hash{}(txt); } + auto operator()(const plg::string& txt) const { + return std::hash{}(txt); + } }; struct case_insensitive_hash { diff --git a/test/cross_call_worker/external/plugify/include/plg/hash.hpp b/test/cross_call_worker/external/plugify/include/plg/hash.hpp index 53f37bf..98c9a27 100644 --- a/test/cross_call_worker/external/plugify/include/plg/hash.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/hash.hpp @@ -1,8 +1,10 @@ #pragma once +#include #include #include -#include + +#include "plg/string.hpp" namespace plg { // std::hash not in the C++20 standard by default @@ -15,7 +17,7 @@ namespace plg { struct string_hash { using is_transparent = void; // Enables heterogeneous lookup - auto operator()(const char *txt) const { + auto operator()(const char* txt) const { return std::hash{}(txt); } auto operator()(std::string_view txt) const { @@ -24,6 +26,9 @@ namespace plg { auto operator()(const std::string& txt) const { return std::hash{}(txt); } + auto operator()(const plg::string& txt) const { + return std::hash{}(txt); + } }; struct case_insensitive_hash { diff --git a/test/example_plugin/external/plugify/include/plg/hash.hpp b/test/example_plugin/external/plugify/include/plg/hash.hpp index 53f37bf..98c9a27 100644 --- a/test/example_plugin/external/plugify/include/plg/hash.hpp +++ b/test/example_plugin/external/plugify/include/plg/hash.hpp @@ -1,8 +1,10 @@ #pragma once +#include #include #include -#include + +#include "plg/string.hpp" namespace plg { // std::hash not in the C++20 standard by default @@ -15,7 +17,7 @@ namespace plg { struct string_hash { using is_transparent = void; // Enables heterogeneous lookup - auto operator()(const char *txt) const { + auto operator()(const char* txt) const { return std::hash{}(txt); } auto operator()(std::string_view txt) const { @@ -24,6 +26,9 @@ namespace plg { auto operator()(const std::string& txt) const { return std::hash{}(txt); } + auto operator()(const plg::string& txt) const { + return std::hash{}(txt); + } }; struct case_insensitive_hash { From eb1a5801d94a94431fda88783f5b125a3bbb52e5 Mon Sep 17 00:00:00 2001 From: qubka Date: Sun, 14 Sep 2025 22:29:23 +0100 Subject: [PATCH 03/10] fix: update clang format --- .clang-format | 148 +++++++++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 61 deletions(-) diff --git a/.clang-format b/.clang-format index ac2c721..36e77ba 100644 --- a/.clang-format +++ b/.clang-format @@ -1,66 +1,92 @@ -# Generated from CLion C/C++ Code Style settings -BasedOnStyle: LLVM -AccessModifierOffset: -4 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: None -AlignOperands: Align +BasedOnStyle: Mozilla +Language: Cpp +Standard: c++20 + +AccessModifierOffset: "-4" +AlignAfterOpenBracket: BlockIndent +AlignEscapedNewlinesLeft: "false" AllowAllArgumentsOnNextLine: false -AllowAllConstructorInitializersOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: Always -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortIfStatementsOnASingleLine: Always -AllowShortLambdasOnASingleLine: All -AllowShortLoopsOnASingleLine: true -AlwaysBreakAfterReturnType: None -AlwaysBreakTemplateDeclarations: Yes -BreakBeforeBraces: Custom -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: Never - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: true -BreakBeforeBinaryOperators: None -BreakBeforeTernaryOperators: true -BreakConstructorInitializers: BeforeColon -BreakInheritanceList: BeforeColon -ColumnLimit: 0 -CompactNamespaces: false -ContinuationIndentWidth: 8 -IndentCaseLabels: true -IndentPPDirectives: None -IndentWidth: 4 -KeepEmptyLinesAtTheStartOfBlocks: true -MaxEmptyLinesToKeep: 2 +AllowShortBlocksOnASingleLine: "false" +AllowShortCaseLabelsOnASingleLine: "false" +AllowShortFunctionsOnASingleLine: "false" +AllowShortIfStatementsOnASingleLine: "false" +AllowShortLoopsOnASingleLine: "false" +AlwaysBreakTemplateDeclarations: "true" +BreakAfterReturnType: ExceptShortType +BinPackArguments: false +BinPackParameters: false +BreakAfterAttributes: Leave +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: "true" +BreakConstructorInitializersBeforeComma: "true" +BreakStringLiterals: "false" +ColumnLimit: "100" +ConstructorInitializerAllOnOneLineOrOnePerLine: "false" +ConstructorInitializerIndentWidth: "4" +ContinuationIndentWidth: "4" +Cpp11BracedListStyle: "false" +DerivePointerAlignment: "false" +DisableFormat: "false" +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: Always +ExperimentalAutoDetectBinPacking: "true" +IncludeBlocks: Regroup +IncludeCategories: + - Regex: <[^.]+> + Priority: -3 + - Regex: + Priority: -1 + - Regex: <.+> + Priority: -2 + - Regex: '"plugify/.+"' + Priority: 0 + - Regex: '"glaze/.+"' + Priority: 0 + - Regex: '"asmjit/.+"' + Priority: 0 + - Regex: '".+/.+"' + Priority: 1 + - Regex: '".+"' + Priority: 2 +IndentCaseLabels: "true" +IndentWidth: "4" +IndentWrappedFunctionNames: "false" +InsertBraces: true # Experimental +KeepEmptyLinesAtTheStartOfBlocks: "false" +MaxEmptyLinesToKeep: "2" NamespaceIndentation: All -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true +ObjCBlockIndentWidth: "4" +ObjCSpaceAfterProperty: "false" +ObjCSpaceBeforeProtocolList: "false" +PackConstructorInitializers: Never +PenaltyBreakAssignment: 100000 +PenaltyBreakBeforeFirstCallParameter: 0 +PenaltyBreakComment: 10 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakTemplateDeclaration: 0 +PenaltyExcessCharacter: 10 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 10 PointerAlignment: Left -ReflowComments: false -SpaceAfterCStyleCast: true -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true +ReferenceAlignment: Left +QualifierAlignment: Custom # Experimental +QualifierOrder: [inline, static, constexpr, const, volatile, type] +ReflowComments: "true" +SeparateDefinitionBlocks: Always +SortIncludes: CaseInsensitive +SortUsingDeclarations: Never +SpaceAfterCStyleCast: "true" +SpaceAfterTemplateKeyword: "true" +SpaceBeforeAssignmentOperators: "true" SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: false -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 0 -SpacesInAngles: false -SpacesInCStyleCastParentheses: false -SpacesInContainerLiterals: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -TabWidth: 4 -UseTab: Always \ No newline at end of file +SpaceInEmptyParentheses: "false" +SpacesBeforeTrailingComments: "2" +SpacesInAngles: "false" +SpacesInCStyleCastParentheses: "false" +SpacesInContainerLiterals: "false" +SpacesInParentheses: "false" +SpacesInSquareBrackets: "false" +TabWidth: "4" +UseTab: "ForIndentation" \ No newline at end of file From dd3746fce37aae3baf8c56bf614d4cb6240507d9 Mon Sep 17 00:00:00 2001 From: qubka Date: Sun, 14 Sep 2025 22:29:32 +0100 Subject: [PATCH 04/10] fix: update deps --- test/cross_call_master/.clang-format | 92 + test/cross_call_master/.clang-tidy | 159 + .../external/plugify/include/plg/enum.hpp | 231 +- .../external/plugify/include/plg/flat_map.hpp | 4 +- .../external/plugify/include/plg/hash.hpp | 40 +- .../external/plugify/include/plg/path.hpp | 74 +- .../external/plugify/include/plg/string.hpp | 137 +- .../external/plugify/include/plg/vector.hpp | 36 +- .../external/plugify/include/plg/version.hpp | 1990 +++--- .../plugify/include/pps/cross_call_worker.hpp | 6165 ++++++++-------- test/cross_call_master/plugin.cpp | 4315 ++++++------ test/cross_call_master/simple_tests.cpp | 86 +- test/cross_call_master/simple_tests.hpp | 43 +- test/cross_call_worker/.clang-format | 92 + test/cross_call_worker/.clang-tidy | 159 + .../external/plugify/include/plg/enum.hpp | 231 +- .../external/plugify/include/plg/flat_map.hpp | 4 +- .../external/plugify/include/plg/hash.hpp | 40 +- .../external/plugify/include/plg/path.hpp | 74 +- .../external/plugify/include/plg/string.hpp | 137 +- .../external/plugify/include/plg/vector.hpp | 36 +- .../external/plugify/include/plg/version.hpp | 1990 +++--- .../plugify/include/pps/cross_call_master.hpp | 6236 +++++++++-------- test/cross_call_worker/plugin.cpp | 1967 ++++-- test/example_plugin/.clang-format | 92 + test/example_plugin/.clang-tidy | 159 + .../external/plugify/include/plg/enum.hpp | 231 +- .../external/plugify/include/plg/flat_map.hpp | 4 +- .../external/plugify/include/plg/hash.hpp | 40 +- .../external/plugify/include/plg/path.hpp | 74 +- .../external/plugify/include/plg/string.hpp | 137 +- .../external/plugify/include/plg/vector.hpp | 36 +- .../external/plugify/include/plg/version.hpp | 1990 +++--- test/example_plugin/plugin.cpp | 26 +- 34 files changed, 14443 insertions(+), 12684 deletions(-) create mode 100644 test/cross_call_master/.clang-format create mode 100644 test/cross_call_master/.clang-tidy create mode 100644 test/cross_call_worker/.clang-format create mode 100644 test/cross_call_worker/.clang-tidy create mode 100644 test/example_plugin/.clang-format create mode 100644 test/example_plugin/.clang-tidy diff --git a/test/cross_call_master/.clang-format b/test/cross_call_master/.clang-format new file mode 100644 index 0000000..36e77ba --- /dev/null +++ b/test/cross_call_master/.clang-format @@ -0,0 +1,92 @@ +BasedOnStyle: Mozilla +Language: Cpp +Standard: c++20 + +AccessModifierOffset: "-4" +AlignAfterOpenBracket: BlockIndent +AlignEscapedNewlinesLeft: "false" +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: "false" +AllowShortCaseLabelsOnASingleLine: "false" +AllowShortFunctionsOnASingleLine: "false" +AllowShortIfStatementsOnASingleLine: "false" +AllowShortLoopsOnASingleLine: "false" +AlwaysBreakTemplateDeclarations: "true" +BreakAfterReturnType: ExceptShortType +BinPackArguments: false +BinPackParameters: false +BreakAfterAttributes: Leave +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: "true" +BreakConstructorInitializersBeforeComma: "true" +BreakStringLiterals: "false" +ColumnLimit: "100" +ConstructorInitializerAllOnOneLineOrOnePerLine: "false" +ConstructorInitializerIndentWidth: "4" +ContinuationIndentWidth: "4" +Cpp11BracedListStyle: "false" +DerivePointerAlignment: "false" +DisableFormat: "false" +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: Always +ExperimentalAutoDetectBinPacking: "true" +IncludeBlocks: Regroup +IncludeCategories: + - Regex: <[^.]+> + Priority: -3 + - Regex: + Priority: -1 + - Regex: <.+> + Priority: -2 + - Regex: '"plugify/.+"' + Priority: 0 + - Regex: '"glaze/.+"' + Priority: 0 + - Regex: '"asmjit/.+"' + Priority: 0 + - Regex: '".+/.+"' + Priority: 1 + - Regex: '".+"' + Priority: 2 +IndentCaseLabels: "true" +IndentWidth: "4" +IndentWrappedFunctionNames: "false" +InsertBraces: true # Experimental +KeepEmptyLinesAtTheStartOfBlocks: "false" +MaxEmptyLinesToKeep: "2" +NamespaceIndentation: All +ObjCBlockIndentWidth: "4" +ObjCSpaceAfterProperty: "false" +ObjCSpaceBeforeProtocolList: "false" +PackConstructorInitializers: Never +PenaltyBreakAssignment: 100000 +PenaltyBreakBeforeFirstCallParameter: 0 +PenaltyBreakComment: 10 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakTemplateDeclaration: 0 +PenaltyExcessCharacter: 10 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 10 +PointerAlignment: Left +ReferenceAlignment: Left +QualifierAlignment: Custom # Experimental +QualifierOrder: [inline, static, constexpr, const, volatile, type] +ReflowComments: "true" +SeparateDefinitionBlocks: Always +SortIncludes: CaseInsensitive +SortUsingDeclarations: Never +SpaceAfterCStyleCast: "true" +SpaceAfterTemplateKeyword: "true" +SpaceBeforeAssignmentOperators: "true" +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: "false" +SpacesBeforeTrailingComments: "2" +SpacesInAngles: "false" +SpacesInCStyleCastParentheses: "false" +SpacesInContainerLiterals: "false" +SpacesInParentheses: "false" +SpacesInSquareBrackets: "false" +TabWidth: "4" +UseTab: "ForIndentation" \ No newline at end of file diff --git a/test/cross_call_master/.clang-tidy b/test/cross_call_master/.clang-tidy new file mode 100644 index 0000000..09fd31b --- /dev/null +++ b/test/cross_call_master/.clang-tidy @@ -0,0 +1,159 @@ +# Generated from CLion Inspection settings +--- +Checks: '-*, +bugprone-argument-comment, +bugprone-assert-side-effect, +bugprone-bad-signal-to-kill-thread, +bugprone-branch-clone, +bugprone-copy-constructor-init, +bugprone-dangling-handle, +bugprone-dynamic-static-initializers, +bugprone-fold-init-type, +bugprone-forward-declaration-namespace, +bugprone-forwarding-reference-overload, +bugprone-inaccurate-erase, +bugprone-incorrect-roundings, +bugprone-integer-division, +bugprone-lambda-function-name, +bugprone-macro-parentheses, +bugprone-macro-repeated-side-effects, +bugprone-misplaced-operator-in-strlen-in-alloc, +bugprone-misplaced-pointer-arithmetic-in-alloc, +bugprone-misplaced-widening-cast, +bugprone-move-forwarding-reference, +bugprone-multiple-statement-macro, +bugprone-no-escape, +bugprone-parent-virtual-call, +bugprone-posix-return, +bugprone-reserved-identifier, +bugprone-sizeof-container, +bugprone-sizeof-expression, +bugprone-spuriously-wake-up-functions, +bugprone-string-constructor, +bugprone-string-integer-assignment, +bugprone-string-literal-with-embedded-nul, +bugprone-suspicious-enum-usage, +bugprone-suspicious-include, +bugprone-suspicious-memset-usage, +bugprone-suspicious-missing-comma, +bugprone-suspicious-semicolon, +bugprone-suspicious-string-compare, +bugprone-suspicious-memory-comparison, +bugprone-suspicious-realloc-usage, +bugprone-swapped-arguments, +bugprone-terminating-continue, +bugprone-throw-keyword-missing, +bugprone-too-small-loop-variable, +bugprone-undefined-memory-manipulation, +bugprone-undelegated-constructor, +bugprone-unhandled-self-assignment, +bugprone-unused-raii, +bugprone-unused-return-value, +bugprone-use-after-move, +bugprone-virtual-near-miss, +cert-dcl21-cpp, +cert-dcl58-cpp, +cert-err34-c, +cert-err52-cpp, +cert-err60-cpp, +cert-flp30-c, +cert-msc50-cpp, +cert-msc51-cpp, +cert-str34-c, +cppcoreguidelines-interfaces-global-init, +cppcoreguidelines-narrowing-conversions, +cppcoreguidelines-pro-type-member-init, +cppcoreguidelines-pro-type-static-cast-downcast, +cppcoreguidelines-slicing, +google-default-arguments, +google-explicit-constructor, +google-runtime-operator, +hicpp-exception-baseclass, +hicpp-multiway-paths-covered, +misc-misplaced-const, +misc-new-delete-overloads, +misc-no-recursion, +misc-non-copyable-objects, +misc-throw-by-value-catch-by-reference, +misc-unconventional-assign-operator, +misc-uniqueptr-reset-release, +modernize-avoid-bind, +modernize-concat-nested-namespaces, +modernize-deprecated-headers, +modernize-deprecated-ios-base-aliases, +modernize-loop-convert, +modernize-make-shared, +modernize-make-unique, +modernize-pass-by-value, +modernize-raw-string-literal, +modernize-redundant-void-arg, +modernize-replace-auto-ptr, +modernize-replace-disallow-copy-and-assign-macro, +modernize-replace-random-shuffle, +modernize-return-braced-init-list, +modernize-shrink-to-fit, +modernize-unary-static-assert, +modernize-use-auto, +modernize-use-bool-literals, +modernize-use-emplace, +modernize-use-equals-default, +modernize-use-equals-delete, +modernize-use-nodiscard, +modernize-use-noexcept, +modernize-use-nullptr, +modernize-use-override, +modernize-use-transparent-functors, +modernize-use-uncaught-exceptions, +mpi-buffer-deref, +mpi-type-mismatch, +openmp-use-default-none, +performance-faster-string-find, +performance-for-range-copy, +performance-implicit-conversion-in-loop, +performance-inefficient-algorithm, +performance-inefficient-string-concatenation, +performance-inefficient-vector-operation, +performance-move-const-arg, +performance-move-constructor-init, +performance-no-automatic-move, +performance-noexcept-move-constructor, +performance-trivially-destructible, +performance-type-promotion-in-math-fn, +performance-unnecessary-copy-initialization, +performance-unnecessary-value-param, +portability-simd-intrinsics, +readability-avoid-const-params-in-decls, +readability-const-return-type, +readability-container-size-empty, +readability-convert-member-functions-to-static, +readability-delete-null-pointer, +readability-deleted-default, +readability-inconsistent-declaration-parameter-name, +readability-make-member-function-const, +readability-misleading-indentation, +readability-misplaced-array-index, +readability-non-const-parameter, +readability-redundant-control-flow, +readability-redundant-declaration, +readability-redundant-function-ptr-dereference, +readability-redundant-smartptr-get, +readability-redundant-string-cstr, +readability-redundant-string-init, +readability-simplify-subscript-expr, +readability-static-accessed-through-instance, +readability-static-definition-in-anonymous-namespace, +readability-string-compare, +readability-uniqueptr-delete-release, +readability-use-anyofallof +readability-identifier-naming' +CheckOptions: + - key: readability-identifier-naming.FunctionCase + value: CamelCase + - key: readability-identifier-naming.MethodCase + value: CamelCase + - key: readability-identifier-naming.MemberCase + value: camelBack + - key: readability-identifier-naming.MemberPrefix + value: '_' + - key: readability-identifier-naming.PrivateMemberPrefix + value: '' \ No newline at end of file diff --git a/test/cross_call_master/external/plugify/include/plg/enum.hpp b/test/cross_call_master/external/plugify/include/plg/enum.hpp index 84f6d23..f8780e1 100644 --- a/test/cross_call_master/external/plugify/include/plg/enum.hpp +++ b/test/cross_call_master/external/plugify/include/plg/enum.hpp @@ -1,121 +1,130 @@ #pragma once +#include #include +#include #include #include -#include -#include #include "plg/macro.hpp" -// from https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ +// from +// https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ namespace plg { - constexpr auto ENUM_MIN_VALUE = -128; - constexpr auto ENUM_MAX_VALUE = 128; - - template - struct static_string { - constexpr static_string(std::string_view sv) noexcept { - std::copy(sv.begin(), sv.end(), content.begin()); - } - constexpr operator std::string_view() const noexcept { return { content.data(), N }; } - - private: - std::array content{}; - }; - - constexpr auto is_pretty(char ch) noexcept { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); - } - - constexpr auto pretty_name(std::string_view sv) noexcept { - for (std::size_t n = sv.size() - 1; n > 0; --n) { - if (!is_pretty(sv[n])) { - sv.remove_prefix(n + 1); - break; - } - } - return sv; - } - - template - constexpr auto n() noexcept { - #if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG - return pretty_name({ __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2 }); - #elif PLUGIFY_COMPILER_MSVC - return pretty_name({ __FUNCSIG__, sizeof(__FUNCSIG__) - 17 }); - #endif - } - - template - constexpr auto is_valid() { - [[maybe_unused]] constexpr E v = static_cast(V); - return !n().empty(); - } - - template - constexpr auto value(std::size_t v) { - return static_cast(ENUM_MIN_VALUE + static_cast(v)); - } - - template - constexpr auto count_values(const bool (&valid)[N]) { - std::size_t count = 0; - for (std::size_t n = 0; n < N; ++n) - if (valid[n]) ++count; - return count; - } - - template - constexpr auto values(std::index_sequence) noexcept { - constexpr bool valid[sizeof...(I)] = { is_valid(I)>()... }; - constexpr auto num_valid = count_values(valid); - static_assert(num_valid > 0, "no support for empty enums"); - - std::array values = {}; - for(std::size_t offset = 0, n = 0; n < num_valid; ++offset) { - if (valid[offset]) { - values[n] = value(offset); - ++n; - } - } - - return values; - } - - template - constexpr auto values() noexcept { - constexpr auto enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1; - return values(std::make_index_sequence({})); - } - - template - inline constexpr auto values_v = values(); - - template - constexpr auto enum_name() { - constexpr auto name = n(); - return static_string(name); - } - - template - inline constexpr auto enum_name_v = enum_name(); - - template - constexpr auto entries(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {{ values_v[I], enum_name_v[I]>}...} - }; - } - - template - inline constexpr auto entries_v = entries(std::make_index_sequence.size()>()); - - template - constexpr std::string_view enum_to_string(E value) { - for (const auto& [ key, name ]: entries_v) { - if (value == key) return name; - } - return {}; - } + constexpr auto ENUM_MIN_VALUE = -128; + constexpr auto ENUM_MAX_VALUE = 128; + + template + struct static_string { + constexpr static_string(std::string_view sv) noexcept { + std::copy(sv.begin(), sv.end(), content.begin()); + } + + constexpr operator std::string_view() const noexcept { + return { content.data(), N }; + } + + private: + std::array content{}; + }; + + constexpr auto is_pretty(char ch) noexcept { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); + } + + constexpr auto pretty_name(std::string_view sv) noexcept { + for (std::size_t n = sv.size() - 1; n > 0; --n) { + if (!is_pretty(sv[n])) { + sv.remove_prefix(n + 1); + break; + } + } + return sv; + } + + template + constexpr auto n() noexcept { +#if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG + return pretty_name({ __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2 }); +#elif PLUGIFY_COMPILER_MSVC + return pretty_name({ __FUNCSIG__, sizeof(__FUNCSIG__) - 17 }); +#endif + } + + template + constexpr auto is_valid() { + [[maybe_unused]] constexpr E v = static_cast(V); + return !n().empty(); + } + + template + constexpr auto value(std::size_t v) { + return static_cast(ENUM_MIN_VALUE + static_cast(v)); + } + + template + constexpr auto count_values(const bool (&valid)[N]) { + std::size_t count = 0; + for (std::size_t n = 0; n < N; ++n) { + if (valid[n]) { + ++count; + } + } + return count; + } + + template + constexpr auto values(std::index_sequence) noexcept { + constexpr bool valid[sizeof...(I)] = { is_valid(I)>()... }; + constexpr auto num_valid = count_values(valid); + static_assert(num_valid > 0, "no support for empty enums"); + + std::array values = {}; + for (std::size_t offset = 0, n = 0; n < num_valid; ++offset) { + if (valid[offset]) { + values[n] = value(offset); + ++n; + } + } + + return values; + } + + template + constexpr auto values() noexcept { + constexpr auto enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1; + return values(std::make_index_sequence({})); + } + + template + inline constexpr auto values_v = values(); + + template + constexpr auto enum_name() { + constexpr auto name = n(); + return static_string(name); + } + + template + inline constexpr auto enum_name_v = enum_name(); + + template + constexpr auto entries(std::index_sequence) noexcept { + return std::array, sizeof...(I)>{ + { { values_v[I], enum_name_v[I]> }... } + }; + } + + template + inline constexpr auto entries_v = entries(std::make_index_sequence.size()>()); + + template + constexpr std::string_view enum_to_string(E value) { + for (const auto& [key, name] : entries_v) { + if (value == key) { + return name; + } + } + return {}; + } } diff --git a/test/cross_call_master/external/plugify/include/plg/flat_map.hpp b/test/cross_call_master/external/plugify/include/plg/flat_map.hpp index 9912431..7b5f7b7 100644 --- a/test/cross_call_master/external/plugify/include/plg/flat_map.hpp +++ b/test/cross_call_master/external/plugify/include/plg/flat_map.hpp @@ -5,8 +5,8 @@ #ifdef __cpp_lib_flat_map #include namespace plg { - template> - using flat_map = std::flat_map; + template> + using flat_map = std::flat_map; } #else #include "plg/vector.hpp" diff --git a/test/cross_call_master/external/plugify/include/plg/hash.hpp b/test/cross_call_master/external/plugify/include/plg/hash.hpp index 98c9a27..296436a 100644 --- a/test/cross_call_master/external/plugify/include/plg/hash.hpp +++ b/test/cross_call_master/external/plugify/include/plg/hash.hpp @@ -15,29 +15,32 @@ namespace plg { }; struct string_hash { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup auto operator()(const char* txt) const { return std::hash{}(txt); } + auto operator()(std::string_view txt) const { return std::hash{}(txt); } + auto operator()(const std::string& txt) const { return std::hash{}(txt); } - auto operator()(const plg::string& txt) const { + + auto operator()(const plg::string& txt) const { return std::hash{}(txt); } }; struct case_insensitive_hash { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup - template + template auto operator()(const T& str_like) const noexcept { std::string_view str = str_like; - std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis + std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis for (char c : str) { hash ^= static_cast(std::tolower(static_cast(c))); hash *= 0x100000001b3; @@ -47,26 +50,29 @@ namespace plg { }; struct case_insensitive_equal { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup - template + template bool operator()(const T1& lhs_like, const T2& rhs_like) const noexcept { std::string_view lhs = lhs_like; std::string_view rhs = rhs_like; - if (lhs.size() != rhs.size()) + if (lhs.size() != rhs.size()) { return false; + } for (size_t i = 0; i < lhs.size(); ++i) { - if (std::tolower(static_cast(lhs[i])) != - std::tolower(static_cast(rhs[i]))) + if (std::tolower(static_cast(lhs[i])) + != std::tolower(static_cast(rhs[i]))) { return false; + } } return true; } }; - inline void hash_combine(size_t&) { } + inline void hash_combine(size_t&) { + } template inline void hash_combine(std::size_t& seed, const T& v) { @@ -78,15 +84,15 @@ namespace plg { template inline std::size_t hash_combine_all(const Ts&... args) { std::size_t seed = 0; - (hash_combine(seed, args), ...); // fold expression + (hash_combine(seed, args), ...); // fold expression return seed; } - template - struct pair_hash { - size_t operator()(std::pair const& p) const { - return hash_combine_all(p.first, p.second); - } + template + struct pair_hash { + size_t operator()(const std::pair& p) const { + return hash_combine_all(p.first, p.second); + } }; } diff --git a/test/cross_call_master/external/plugify/include/plg/path.hpp b/test/cross_call_master/external/plugify/include/plg/path.hpp index 61343f3..afc3d6e 100644 --- a/test/cross_call_master/external/plugify/include/plg/path.hpp +++ b/test/cross_call_master/external/plugify/include/plg/path.hpp @@ -1,14 +1,14 @@ #pragma once #include -#include #include +#include namespace plg { - using path_view = std::basic_string_view; - using path_string = std::filesystem::path::string_type; - using path_char = path_string::value_type; - using path_diff_t = path_string::difference_type; + using path_view = std::basic_string_view; + using path_string = std::filesystem::path::string_type; + using path_char = path_string::value_type; + using path_diff_t = path_string::difference_type; #if _WIN32 #define PLUGIFY_PATH_LITERAL(x) L##x @@ -16,37 +16,41 @@ namespace plg { #define PLUGIFY_PATH_LITERAL(x) x #endif - template - bool insensitive_equals(const path_char lhs, const path_char rhs) { - if constexpr (std::is_same_v) { - return std::towlower(lhs) == rhs; // NOLINT - } else { - return std::tolower(lhs) == rhs; - } - } - - inline bool insensitive_equals(const path_view lhs, const path_view rhs) { - return lhs.size() == rhs.size() && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); - } - - inline path_view extension_view(const std::filesystem::path& path) { - constexpr path_diff_t extension_size = 4; - if (!path.has_extension()) { return {}; } - const path_string& path_str = path.native(); - const auto offset = static_cast(path_str.size()) - extension_size; - if (offset <= 0) { return {}; } - return { path_str.cbegin() + offset, path_str.cend() }; - } - - inline bool has_extension(const std::filesystem::path& path, const path_view extension) { - return insensitive_equals(extension_view(path), extension); - } - - inline auto as_string(const std::filesystem::path& p) { + template + bool insensitive_equals(const path_char lhs, const path_char rhs) { + if constexpr (std::is_same_v) { + return std::towlower(lhs) == rhs; // NOLINT + } else { + return std::tolower(lhs) == rhs; + } + } + + inline bool insensitive_equals(const path_view lhs, const path_view rhs) { + return lhs.size() == rhs.size() + && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); + } + + inline path_view extension_view(const std::filesystem::path& path, size_t extension_size) { + if (!path.has_extension()) { + return {}; + } + const path_string& path_str = path.native(); + const auto offset = static_cast(path_str.size() - extension_size); + if (offset <= 0) { + return {}; + } + return { path_str.cbegin() + offset, path_str.cend() }; // NOLINT(*-dangling-handle) + } + + inline bool has_extension(const std::filesystem::path& path, const path_view extension) { + return insensitive_equals(extension_view(path, extension.size()), extension); + } + + inline auto as_string(const std::filesystem::path& p) { #if _WIN32 - return p.string(); // returns std::string by value + return p.string(); // returns std::string by value #else - return p.native(); // returns const std::string& + return p.native(); // returns const std::string& #endif - } + } } diff --git a/test/cross_call_master/external/plugify/include/plg/string.hpp b/test/cross_call_master/external/plugify/include/plg/string.hpp index 175bed2..830f168 100644 --- a/test/cross_call_master/external/plugify/include/plg/string.hpp +++ b/test/cross_call_master/external/plugify/include/plg/string.hpp @@ -19,6 +19,7 @@ #include // for std::numeric_limits #include // for std::to_chars + #include #include #include @@ -44,63 +45,63 @@ namespace plg { namespace detail { - template - concept is_allocator = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; - - template - concept is_char_traits = requires { - // Required type definitions - typename Traits::char_type; - typename Traits::int_type; - typename Traits::off_type; - typename Traits::pos_type; - typename Traits::state_type; - } && requires( - typename Traits::char_type c1, - typename Traits::char_type c2, - typename Traits::char_type& cr, - const typename Traits::char_type& ccr, - typename Traits::char_type* p, - const typename Traits::char_type* cp, - typename Traits::int_type i1, - typename Traits::int_type i2, - std::size_t n - ) { - // Character operations - { Traits::assign(cr, ccr) } -> std::same_as; - { Traits::eq(ccr, ccr) } -> std::convertible_to; - { Traits::lt(ccr, ccr) } -> std::convertible_to; - - // String operations - { Traits::compare(cp, cp, n) } -> std::convertible_to; - { Traits::length(cp) } -> std::convertible_to; - { Traits::find(cp, n, ccr) } -> std::convertible_to; - - // Memory operations - { Traits::move(p, cp, n) } -> std::same_as; - { Traits::copy(p, cp, n) } -> std::same_as; - { Traits::assign(p, n, c1) } -> std::same_as; - - // int_type operations - { Traits::not_eof(i1) } -> std::same_as; - { Traits::to_char_type(i1) } -> std::same_as; - { Traits::to_int_type(c1) } -> std::same_as; - { Traits::eq_int_type(i1, i2) } -> std::convertible_to; - { Traits::eof() } -> std::same_as; - }; + template + concept is_allocator = requires(Alloc& a, std::size_t n) { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; + + { std::allocator_traits::allocate(a, n) } + -> std::convertible_to::pointer>; + + requires requires(typename std::allocator_traits::pointer p) { + std::allocator_traits::deallocate(a, p, n); + }; + }; + + template + concept is_char_traits = requires { + // Required type definitions + typename Traits::char_type; + typename Traits::int_type; + typename Traits::off_type; + typename Traits::pos_type; + typename Traits::state_type; + } && requires( + typename Traits::char_type c1, + typename Traits::char_type c2, + typename Traits::char_type& cr, + const typename Traits::char_type& ccr, + typename Traits::char_type* p, + const typename Traits::char_type* cp, + typename Traits::int_type i1, + typename Traits::int_type i2, + std::size_t n + ) { + // Character operations + { Traits::assign(cr, ccr) } -> std::same_as; + { Traits::eq(ccr, ccr) } -> std::convertible_to; + { Traits::lt(ccr, ccr) } -> std::convertible_to; + + // String operations + { Traits::compare(cp, cp, n) } -> std::convertible_to; + { Traits::length(cp) } -> std::convertible_to; + { Traits::find(cp, n, ccr) } -> std::convertible_to; + + // Memory operations + { Traits::move(p, cp, n) } -> std::same_as; + { Traits::copy(p, cp, n) } -> std::same_as; + { Traits::assign(p, n, c1) } -> std::same_as; + + // int_type operations + { Traits::not_eof(i1) } -> std::same_as; + { Traits::to_char_type(i1) } -> std::same_as; + { Traits::to_int_type(c1) } -> std::same_as; + { Traits::eq_int_type(i1, i2) } -> std::convertible_to; + { Traits::eof() } -> std::same_as; + }; struct uninitialized_size_tag {}; @@ -909,9 +910,9 @@ namespace plg { // const size_type alignment = 16; // size_type m = allocator_traits::max_size(_allocator); // if (m <= std::numeric_limits::max() / 2) - // return m - alignment; + // return m - alignment; // else - //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; + //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; return (allocator_traits::max_size(_allocator) - 1) / 2; } @@ -1973,21 +1974,21 @@ namespace std { template std::ostream& operator<<(std::ostream& os, const plg::basic_string& str) { - os << str.c_str(); - return os; + os << str.c_str(); + return os; } #ifndef PLUGIFY_STRING_NO_STD_FORMAT #include namespace plg { - namespace detail { - // Concept to match string-like types including char* and const char* - template - concept is_string_like = requires(T v) { - { std::string_view(v) }; - }; - } + namespace detail { + // Concept to match string-like types including char* and const char* + template + concept is_string_like = requires(T v) { + { std::string_view(v) }; + }; + } template constexpr string join(const Range& range, std::string_view separator) { diff --git a/test/cross_call_master/external/plugify/include/plg/vector.hpp b/test/cross_call_master/external/plugify/include/plg/vector.hpp index 3ec8750..11aada1 100644 --- a/test/cross_call_master/external/plugify/include/plg/vector.hpp +++ b/test/cross_call_master/external/plugify/include/plg/vector.hpp @@ -27,30 +27,30 @@ #include "plg/allocator.hpp" namespace plg { - namespace detail { - template - concept is_alloc = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; + namespace detail { + template + concept is_alloc = requires(Alloc& a, std::size_t n) { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; + { std::allocator_traits::allocate(a, n) } + -> std::convertible_to::pointer>; - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; + requires requires(typename std::allocator_traits::pointer p) { + std::allocator_traits::deallocate(a, p, n); + }; + }; - struct initialized_value_tag {}; + struct initialized_value_tag {}; #if PLUGIFY_VECTOR_CONTAINERS_RANGES - template - concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; + template + concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; #endif - } // namespace detail + } // namespace detail template struct vector_iterator { diff --git a/test/cross_call_master/external/plugify/include/plg/version.hpp b/test/cross_call_master/external/plugify/include/plg/version.hpp index b12ac87..6089f12 100644 --- a/test/cross_call_master/external/plugify/include/plg/version.hpp +++ b/test/cross_call_master/external/plugify/include/plg/version.hpp @@ -24,1021 +24,1021 @@ // from https://github.com/Neargye/semver namespace plg { - namespace detail { - template - struct resize_uninitialized { - constexpr static auto resize(T& str, std::size_t size) -> std::void_t { - str.resize(size); - } - }; - - template - struct resize_uninitialized().__resize_default_init(42))>> { - constexpr static void resize(T& str, std::size_t size) { - str.__resize_default_init(size); - } - }; - - template - constexpr std::size_t length(Int n) noexcept { - std::size_t digits = 0; - do { - digits++; - n /= 10; - } while (n != 0); - return digits; - } - - template - constexpr OutputIt to_chars(OutputIt dest, Int n) noexcept { - do { - *(--dest) = static_cast('0' + (n % 10)); - n /= 10; - } while (n != 0); - return dest; - } - - enum struct prerelease_identifier_type { - numeric, - alphanumeric - }; - - struct prerelease_identifier { - prerelease_identifier_type type; - string identifier; - }; - - class version_parser; - class prerelease_comparator; - } - - template - class version { - friend class detail::version_parser; - friend class detail::prerelease_comparator; - - public: - constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase - constexpr version(const version&) = default; - constexpr version(version&&) = default; - constexpr ~version() = default; - - constexpr version& operator=(const version&) = default; - constexpr version& operator=(version&&) = default; - - constexpr I1 major() const noexcept { return major_; } - constexpr I2 minor() const noexcept { return minor_; } - constexpr I3 patch() const noexcept { return patch_; } - - constexpr const string& prerelease_tag() const { return prerelease_tag_; } - constexpr const string& build_metadata() const { return build_metadata_; } - - constexpr string to_string() const; - - private: - I1 major_ = 0; - I2 minor_ = 1; - I3 patch_ = 0; - string prerelease_tag_; - string build_metadata_; - - vector prerelease_identifiers; - - constexpr std::size_t length() const noexcept { - return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 - + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) - + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); - } - - constexpr void clear() noexcept { - major_ = 0; - minor_ = 1; - patch_ = 0; - - prerelease_tag_.clear(); - prerelease_identifiers.clear(); - build_metadata_.clear(); - } - }; - - template - constexpr string version::to_string() const { - string result; - detail::resize_uninitialized{}.resize(result, length()); - - auto it = result.end(); - if (!build_metadata_.empty()) { - it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); - *(--it) = '+'; - } - - if (!prerelease_tag_.empty()) { - it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); - *(--it) = '-'; - } - - it = detail::to_chars(it, patch_); - *(--it) = '.'; - - it = detail::to_chars(it, minor_); - *(--it) = '.'; - - it = detail::to_chars(it, major_); - - return result; - } + namespace detail { + template + struct resize_uninitialized { + constexpr static auto resize(T& str, std::size_t size) -> std::void_t { + str.resize(size); + } + }; + + template + struct resize_uninitialized().__resize_default_init(42))>> { + constexpr static void resize(T& str, std::size_t size) { + str.__resize_default_init(size); + } + }; + + template + constexpr std::size_t length(Int n) noexcept { + std::size_t digits = 0; + do { + digits++; + n /= 10; + } while (n != 0); + return digits; + } + + template + constexpr OutputIt to_chars(OutputIt dest, Int n) noexcept { + do { + *(--dest) = static_cast('0' + (n % 10)); + n /= 10; + } while (n != 0); + return dest; + } + + enum struct prerelease_identifier_type { + numeric, + alphanumeric + }; + + struct prerelease_identifier { + prerelease_identifier_type type; + string identifier; + }; + + class version_parser; + class prerelease_comparator; + } + + template + class version { + friend class detail::version_parser; + friend class detail::prerelease_comparator; + + public: + constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase + constexpr version(const version&) = default; + constexpr version(version&&) = default; + constexpr ~version() = default; + + constexpr version& operator=(const version&) = default; + constexpr version& operator=(version&&) = default; + + constexpr I1 major() const noexcept { return major_; } + constexpr I2 minor() const noexcept { return minor_; } + constexpr I3 patch() const noexcept { return patch_; } + + constexpr const string& prerelease_tag() const { return prerelease_tag_; } + constexpr const string& build_metadata() const { return build_metadata_; } + + constexpr string to_string() const; + + private: + I1 major_ = 0; + I2 minor_ = 1; + I3 patch_ = 0; + string prerelease_tag_; + string build_metadata_; + + vector prerelease_identifiers; + + constexpr std::size_t length() const noexcept { + return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 + + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) + + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); + } + + constexpr void clear() noexcept { + major_ = 0; + minor_ = 1; + patch_ = 0; + + prerelease_tag_.clear(); + prerelease_identifiers.clear(); + build_metadata_.clear(); + } + }; + + template + constexpr string version::to_string() const { + string result; + detail::resize_uninitialized{}.resize(result, length()); + + auto it = result.end(); + if (!build_metadata_.empty()) { + it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); + *(--it) = '+'; + } + + if (!prerelease_tag_.empty()) { + it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); + *(--it) = '-'; + } + + it = detail::to_chars(it, patch_); + *(--it) = '.'; + + it = detail::to_chars(it, minor_); + *(--it) = '.'; + + it = detail::to_chars(it, major_); + + return result; + } #if __has_include() - struct from_chars_result : std::from_chars_result { - [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } - }; + struct from_chars_result : std::from_chars_result { + [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } + }; #else - struct from_chars_result { - const char* ptr; - std::errc ec; + struct from_chars_result { + const char* ptr; + std::errc ec; - [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } - }; + [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } + }; #endif - enum class version_compare_option : std::uint8_t { - exclude_prerelease, - include_prerelease - }; - - namespace detail { - constexpr from_chars_result success(const char* ptr) noexcept { - return from_chars_result{ ptr, std::errc{} }; - } - - constexpr from_chars_result failure(const char* ptr, std::errc error_code = std::errc::invalid_argument) noexcept { - return from_chars_result{ ptr, error_code }; - } - - constexpr bool is_digit(char c) noexcept { - return c >= '0' && c <= '9'; - } - - constexpr bool is_letter(char c) noexcept { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); - } - - constexpr std::uint8_t to_digit(char c) noexcept { - return static_cast(c - '0'); - } - - constexpr char to_char(int i) noexcept { - return '0' + (char)i; - } - - template - constexpr bool cmp_less(T t, U u) noexcept - { - if constexpr (std::is_signed_v == std::is_signed_v) - return t < u; + enum class version_compare_option : std::uint8_t { + exclude_prerelease, + include_prerelease + }; + + namespace detail { + constexpr from_chars_result success(const char* ptr) noexcept { + return from_chars_result{ ptr, std::errc{} }; + } + + constexpr from_chars_result failure(const char* ptr, std::errc error_code = std::errc::invalid_argument) noexcept { + return from_chars_result{ ptr, error_code }; + } + + constexpr bool is_digit(char c) noexcept { + return c >= '0' && c <= '9'; + } + + constexpr bool is_letter(char c) noexcept { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + + constexpr std::uint8_t to_digit(char c) noexcept { + return static_cast(c - '0'); + } + + constexpr char to_char(int i) noexcept { + return '0' + (char)i; + } + + template + constexpr bool cmp_less(T t, U u) noexcept + { + if constexpr (std::is_signed_v == std::is_signed_v) + return t < u; else if constexpr (std::is_signed_v) - return t < 0 || std::make_unsigned_t(t) < u; + return t < 0 || std::make_unsigned_t(t) < u; else - return u >= 0 && t < std::make_unsigned_t(u); + return u >= 0 && t < std::make_unsigned_t(u); } - template - constexpr bool cmp_less_equal(T t, U u) noexcept - { - return !cmp_less(u, t); - } + template + constexpr bool cmp_less_equal(T t, U u) noexcept + { + return !cmp_less(u, t); + } - template - constexpr bool cmp_greater_equal(T t, U u) noexcept - { - return !cmp_less(t, u); - } + template + constexpr bool cmp_greater_equal(T t, U u) noexcept + { + return !cmp_less(t, u); + } - template - constexpr bool number_in_range(T t) noexcept { - return cmp_greater_equal(t, std::numeric_limits::min()) && cmp_less_equal(t, std::numeric_limits::max()); - } + template + constexpr bool number_in_range(T t) noexcept { + return cmp_greater_equal(t, std::numeric_limits::min()) && cmp_less_equal(t, std::numeric_limits::max()); + } - constexpr int compare(std::string_view lhs, std::string_view rhs) { + constexpr int compare(std::string_view lhs, std::string_view rhs) { #if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) - // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html - // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html - constexpr bool workaround = true; + // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html + constexpr bool workaround = true; #else - constexpr bool workaround = false; + constexpr bool workaround = false; #endif - if constexpr (workaround) { - const auto size = std::min(lhs.size(), rhs.size()); - for (std::size_t i = 0; i < size; ++i) { - if (lhs[i] < rhs[i]) { - return -1; - } else if (lhs[i] > rhs[i]) { - return 1; - } - } - - return static_cast(lhs.size() - rhs.size()); - } else { - return lhs.compare(rhs); - } - } - - constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { - // assume that strings don't have leading zeros (we've already checked it at parsing stage). - - if (lhs.size() != rhs.size()) { - return static_cast(lhs.size() - rhs.size()); - } - - for (std::size_t i = 0; i < lhs.size(); ++i) { - int a = lhs[i] - '0'; - int b = rhs[i] - '0'; - if (a != b) { - return a - b; - } - } - - return 0; - } - - enum class token_type : std::uint8_t { - eol, - space, - dot, - plus, - hyphen, - letter, - digit, - range_operator, - logical_or - }; - - enum class range_operator : std::uint8_t { - less, - less_or_equal, - greater, - greater_or_equal, - equal - }; - - struct token { - using value_t = std::variant; - token_type type; - value_t value; - const char* lexeme; - }; - - class token_stream { - public: - constexpr token_stream() = default; - constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} - - constexpr void push(const token& token) noexcept { - tokens_.push_back(token); - } - - constexpr token advance() noexcept { - const token token = get(current_); - ++current_; - return token; - } - - constexpr token peek(std::size_t k = 0) const noexcept { - return get(current_ + k); - } - - constexpr token previous() const noexcept { - return get(current_ - 1); - } - - constexpr bool advanceIfMatch(token& token, token_type type) noexcept { - if (get(current_).type != type) { - return false; - } - - token = advance(); - return true; - } - - constexpr bool advanceIfMatch(token_type type) noexcept { - token token; - return advanceIfMatch(token, type); - } - - constexpr bool consume(token_type type) noexcept { - return advance().type == type; - } - - constexpr bool check(token_type type) const noexcept { - return peek().type == type; - } - - private: - std::size_t current_ = 0; - vector tokens_; - - constexpr token get(std::size_t i) const noexcept { - return tokens_[i]; - } - }; - - class lexer { - public: - explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} - - constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { - from_chars_result result{ text_.data(), std::errc{} }; - - while (!is_eol()) { - result = scan_token(token_stream); - if (!result) { - return result; - } - } - - token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); - - return result; - } - - private: - std::string_view text_; - std::size_t current_pos_; - - constexpr from_chars_result scan_token(token_stream& stream) noexcept { - const char c = advance(); - - switch (c) { - case ' ': - add_token(stream, token_type::space); - break; - case '.': - add_token(stream, token_type::dot); - break; - case '-': - add_token(stream, token_type::hyphen); - break; - case '+': - add_token(stream, token_type::plus); - break; - case '|': - if (advanceIfMatch('|')) { - add_token(stream, token_type::logical_or); - break; - } - return failure(get_prev_symbol()); - case '<': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); - break; - case '>': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); - break; - case '=': - add_token(stream, token_type::range_operator, range_operator::equal); - break; - default: - if (is_digit(c)) { - add_token(stream, token_type::digit, to_digit(c)); - break; - } - else if (is_letter(c)) { - add_token(stream, token_type::letter, c); - break; - } - return failure(get_prev_symbol()); - } - - return success(get_prev_symbol()); - } - - constexpr void add_token(token_stream& stream, token_type type, token::value_t value = {}) noexcept { - const char* lexeme = get_prev_symbol(); - stream.push({ type, value, lexeme}); - } - - constexpr char advance() noexcept { - char c = text_[current_pos_]; - current_pos_ += 1; - return c; - } - - constexpr bool advanceIfMatch(char c) noexcept { - if (is_eol()) { - return false; - } - - if (text_[current_pos_] != c) { - return false; - } - - current_pos_ += 1; - - return true; - } - - constexpr const char* get_prev_symbol() const noexcept { - return text_.data() + current_pos_ - 1; - } - - constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } - }; - - class prerelease_comparator { - public: - template - [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { - if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { - return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); - } - - const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); - - for (std::size_t i = 0; i < count; ++i) { - const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); - if (compare_result != 0) { - return compare_result; - } - } - - return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); - } - - private: - [[nodiscard]] constexpr int compare_identifier(const prerelease_identifier& lhs, const prerelease_identifier& rhs) const noexcept { - if (lhs.type == prerelease_identifier_type::numeric && rhs.type == prerelease_identifier_type::numeric) { - return compare_numerically(lhs.identifier, rhs.identifier); - } else if (lhs.type == prerelease_identifier_type::alphanumeric && rhs.type == prerelease_identifier_type::alphanumeric) { - return detail::compare(lhs.identifier, rhs.identifier); - } - - return lhs.type == prerelease_identifier_type::alphanumeric ? 1 : -1; - } - }; - - class version_parser { - public: - constexpr explicit version_parser(token_stream& stream) : stream_{stream} { - } - - template - constexpr from_chars_result parse(version& out) noexcept { - out.clear(); - - from_chars_result result = parse_number(out.major_); - if (!result) { - return result; - } - - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); - } - - result = parse_number(out.minor_); - if (!result) { - return result; - } - - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); - } - - result = parse_number(out.patch_); - if (!result) { - return result; - } - - if (stream_.advanceIfMatch(token_type::hyphen)) { - result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); - if (!result) { - return result; - } - } - - if (stream_.advanceIfMatch(token_type::plus)) { - result = parse_build_metadata(out.build_metadata_); - if (!result) { - return result; - } - } - - return result; - } - - - private: - token_stream& stream_; - - template - constexpr from_chars_result parse_number(Int& out) { - token token = stream_.advance(); - - if (!is_digit(token)) { - return failure(token.lexeme); - } - - const auto first_digit = std::get(token.value); - std::uint64_t result = first_digit; - - if (first_digit == 0) { - out = static_cast(result); - return success(stream_.peek().lexeme); - } - - while (stream_.advanceIfMatch(token, token_type::digit)) { - result = result * 10 + std::get(token.value); - } - - if (detail::number_in_range(result)) { - out = static_cast(result); - return success(stream_.peek().lexeme); - } - - return failure(token.lexeme, std::errc::result_out_of_range); - } - - constexpr from_chars_result parse_prerelease_tag(string& out, vector& out_identifiers) { - string result; - - do { - if (!result.empty()) { - result.push_back('.'); - } - - string identifier; - if (const auto res = parse_prerelease_identifier(identifier); !res) { - return res; - } - - result.append(identifier); - out_identifiers.push_back(make_prerelease_identifier(identifier)); - - } while (stream_.advanceIfMatch(token_type::dot)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr from_chars_result parse_build_metadata(string& out) { - string result; - - do { - if (!result.empty()) { - result.push_back('.'); - } - - string identifier; - if (const auto res = parse_build_identifier(identifier); !res) { - return res; - } - - result.append(identifier); - } while (stream_.advanceIfMatch(token_type::dot)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr from_chars_result parse_prerelease_identifier(string& out) { - string result; - token token = stream_.advance(); - - do { - switch (token.type) { - case token_type::hyphen: - result.push_back('-'); - break; - case token_type::letter: - result.push_back(std::get(token.value)); - break; - case token_type::digit: - { - const auto digit = std::get(token.value); - - // numerical prerelease identifier doesn't allow leading zero - // 1.2.3-1.alpha is valid, - // 1.2.3-01b is valid as well, but - // 1.2.3-01.alpha is not valid - - // Only check for leading zero when digit is the first character of the - // prerelease identifier. - if (result.empty() && is_leading_zero(digit)) { - return failure(token.lexeme); - } - - result.push_back(to_char(digit)); - break; - } - default: - return failure(token.lexeme); - } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { - auto type = detail::prerelease_identifier_type::numeric; - for (char c : identifier) { - if (c == '-' || detail::is_letter(c)) { - type = detail::prerelease_identifier_type::alphanumeric; - break; - } - } - return detail::prerelease_identifier{ type, identifier }; - } - - constexpr from_chars_result parse_build_identifier(string& out) { - string result; - token token = stream_.advance(); - - do { - switch (token.type) { - case token_type::hyphen: - result.push_back('-'); - break; - case token_type::letter: - result.push_back(std::get(token.value)); - break; - case token_type::digit: - { - const auto digit = std::get(token.value); - result.push_back(to_char(digit)); - break; - } - default: - return failure(token.lexeme); - } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr bool is_leading_zero(int digit) noexcept { - if (digit != 0) { - return false; - } - - size_t k = 0; - int alpha_numerics = 0; - int digits = 0; - - while (true) { - const token token = stream_.peek(k); - - if (!is_alphanumeric(token)) { - break; - } - - ++alpha_numerics; - - if (is_digit(token)) { - ++digits; - } - - ++k; - } - - return digits > 0 && digits == alpha_numerics; - } - - constexpr bool is_digit(const token& token) const noexcept { - return token.type == token_type::digit; - } - - constexpr bool is_eol(const token& token) const noexcept { - return token.type == token_type::eol; - } - - constexpr bool is_alphanumeric(const token& token) const noexcept { - return token.type == token_type::hyphen || token.type == token_type::letter || token.type == token_type::digit; - } - }; - - template - constexpr int compare_prerelease(const version& lhs, const version& rhs) noexcept { - return prerelease_comparator{}.compare(lhs, rhs); - } - - template - constexpr int compare_parsed(const version& lhs, const version& rhs, version_compare_option compare_option) { - int result = lhs.major() - rhs.major(); - if (result != 0) { - return result; - } - - result = lhs.minor() - rhs.minor(); - if (result != 0) { - return result; - } - - result = lhs.patch() - rhs.patch(); - if (result != 0) { - return result; - } - - if (compare_option == version_compare_option::include_prerelease) { - result = detail::compare_prerelease(lhs, rhs); - } - - return result; - } - - template - constexpr from_chars_result parse(std::string_view str, version& out) { - token_stream token_stream; - from_chars_result result = lexer{ str }.scan_tokens(token_stream); - if (!result) { - return result; - } - - result = version_parser{ token_stream }.parse(out); - if (!result) { - return result; - } - - if (!token_stream.consume(token_type::eol)) { - return failure(token_stream.previous().lexeme); - } - - return success(token_stream.previous().lexeme); - } - - } // namespace semver::detail - - template - [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) == 0; - } - - template - [[nodiscard]] constexpr bool operator!=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) != 0; - } - - template - [[nodiscard]] constexpr bool operator>(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) > 0; - } - - template - [[nodiscard]] constexpr bool operator>=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) >= 0; - } - - template - [[nodiscard]] constexpr bool operator<(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) < 0; - } - - template - [[nodiscard]] constexpr bool operator<=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; - } + if constexpr (workaround) { + const auto size = std::min(lhs.size(), rhs.size()); + for (std::size_t i = 0; i < size; ++i) { + if (lhs[i] < rhs[i]) { + return -1; + } else if (lhs[i] > rhs[i]) { + return 1; + } + } + + return static_cast(lhs.size() - rhs.size()); + } else { + return lhs.compare(rhs); + } + } + + constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { + // assume that strings don't have leading zeros (we've already checked it at parsing stage). + + if (lhs.size() != rhs.size()) { + return static_cast(lhs.size() - rhs.size()); + } + + for (std::size_t i = 0; i < lhs.size(); ++i) { + int a = lhs[i] - '0'; + int b = rhs[i] - '0'; + if (a != b) { + return a - b; + } + } + + return 0; + } + + enum class token_type : std::uint8_t { + eol, + space, + dot, + plus, + hyphen, + letter, + digit, + range_operator, + logical_or + }; + + enum class range_operator : std::uint8_t { + less, + less_or_equal, + greater, + greater_or_equal, + equal + }; + + struct token { + using value_t = std::variant; + token_type type; + value_t value; + const char* lexeme; + }; + + class token_stream { + public: + constexpr token_stream() = default; + constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} + + constexpr void push(const token& token) noexcept { + tokens_.push_back(token); + } + + constexpr token advance() noexcept { + const token token = get(current_); + ++current_; + return token; + } + + constexpr token peek(std::size_t k = 0) const noexcept { + return get(current_ + k); + } + + constexpr token previous() const noexcept { + return get(current_ - 1); + } + + constexpr bool advanceIfMatch(token& token, token_type type) noexcept { + if (get(current_).type != type) { + return false; + } + + token = advance(); + return true; + } + + constexpr bool advanceIfMatch(token_type type) noexcept { + token token; + return advanceIfMatch(token, type); + } + + constexpr bool consume(token_type type) noexcept { + return advance().type == type; + } + + constexpr bool check(token_type type) const noexcept { + return peek().type == type; + } + + private: + std::size_t current_ = 0; + vector tokens_; + + constexpr token get(std::size_t i) const noexcept { + return tokens_[i]; + } + }; + + class lexer { + public: + explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} + + constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { + from_chars_result result{ text_.data(), std::errc{} }; + + while (!is_eol()) { + result = scan_token(token_stream); + if (!result) { + return result; + } + } + + token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); + + return result; + } + + private: + std::string_view text_; + std::size_t current_pos_; + + constexpr from_chars_result scan_token(token_stream& stream) noexcept { + const char c = advance(); + + switch (c) { + case ' ': + add_token(stream, token_type::space); + break; + case '.': + add_token(stream, token_type::dot); + break; + case '-': + add_token(stream, token_type::hyphen); + break; + case '+': + add_token(stream, token_type::plus); + break; + case '|': + if (advanceIfMatch('|')) { + add_token(stream, token_type::logical_or); + break; + } + return failure(get_prev_symbol()); + case '<': + add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); + break; + case '>': + add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); + break; + case '=': + add_token(stream, token_type::range_operator, range_operator::equal); + break; + default: + if (is_digit(c)) { + add_token(stream, token_type::digit, to_digit(c)); + break; + } + else if (is_letter(c)) { + add_token(stream, token_type::letter, c); + break; + } + return failure(get_prev_symbol()); + } + + return success(get_prev_symbol()); + } + + constexpr void add_token(token_stream& stream, token_type type, token::value_t value = {}) noexcept { + const char* lexeme = get_prev_symbol(); + stream.push({ type, value, lexeme}); + } + + constexpr char advance() noexcept { + char c = text_[current_pos_]; + current_pos_ += 1; + return c; + } + + constexpr bool advanceIfMatch(char c) noexcept { + if (is_eol()) { + return false; + } + + if (text_[current_pos_] != c) { + return false; + } + + current_pos_ += 1; + + return true; + } + + constexpr const char* get_prev_symbol() const noexcept { + return text_.data() + current_pos_ - 1; + } + + constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } + }; + + class prerelease_comparator { + public: + template + [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { + if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { + return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); + } + + const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); + + for (std::size_t i = 0; i < count; ++i) { + const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); + if (compare_result != 0) { + return compare_result; + } + } + + return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); + } + + private: + [[nodiscard]] constexpr int compare_identifier(const prerelease_identifier& lhs, const prerelease_identifier& rhs) const noexcept { + if (lhs.type == prerelease_identifier_type::numeric && rhs.type == prerelease_identifier_type::numeric) { + return compare_numerically(lhs.identifier, rhs.identifier); + } else if (lhs.type == prerelease_identifier_type::alphanumeric && rhs.type == prerelease_identifier_type::alphanumeric) { + return detail::compare(lhs.identifier, rhs.identifier); + } + + return lhs.type == prerelease_identifier_type::alphanumeric ? 1 : -1; + } + }; + + class version_parser { + public: + constexpr explicit version_parser(token_stream& stream) : stream_{stream} { + } + + template + constexpr from_chars_result parse(version& out) noexcept { + out.clear(); + + from_chars_result result = parse_number(out.major_); + if (!result) { + return result; + } + + if (!stream_.consume(token_type::dot)) { + return failure(stream_.previous().lexeme); + } + + result = parse_number(out.minor_); + if (!result) { + return result; + } + + if (!stream_.consume(token_type::dot)) { + return failure(stream_.previous().lexeme); + } + + result = parse_number(out.patch_); + if (!result) { + return result; + } + + if (stream_.advanceIfMatch(token_type::hyphen)) { + result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); + if (!result) { + return result; + } + } + + if (stream_.advanceIfMatch(token_type::plus)) { + result = parse_build_metadata(out.build_metadata_); + if (!result) { + return result; + } + } + + return result; + } + + + private: + token_stream& stream_; + + template + constexpr from_chars_result parse_number(Int& out) { + token token = stream_.advance(); + + if (!is_digit(token)) { + return failure(token.lexeme); + } + + const auto first_digit = std::get(token.value); + std::uint64_t result = first_digit; + + if (first_digit == 0) { + out = static_cast(result); + return success(stream_.peek().lexeme); + } + + while (stream_.advanceIfMatch(token, token_type::digit)) { + result = result * 10 + std::get(token.value); + } + + if (detail::number_in_range(result)) { + out = static_cast(result); + return success(stream_.peek().lexeme); + } + + return failure(token.lexeme, std::errc::result_out_of_range); + } + + constexpr from_chars_result parse_prerelease_tag(string& out, vector& out_identifiers) { + string result; + + do { + if (!result.empty()) { + result.push_back('.'); + } + + string identifier; + if (const auto res = parse_prerelease_identifier(identifier); !res) { + return res; + } + + result.append(identifier); + out_identifiers.push_back(make_prerelease_identifier(identifier)); + + } while (stream_.advanceIfMatch(token_type::dot)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr from_chars_result parse_build_metadata(string& out) { + string result; + + do { + if (!result.empty()) { + result.push_back('.'); + } + + string identifier; + if (const auto res = parse_build_identifier(identifier); !res) { + return res; + } + + result.append(identifier); + } while (stream_.advanceIfMatch(token_type::dot)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr from_chars_result parse_prerelease_identifier(string& out) { + string result; + token token = stream_.advance(); + + do { + switch (token.type) { + case token_type::hyphen: + result.push_back('-'); + break; + case token_type::letter: + result.push_back(std::get(token.value)); + break; + case token_type::digit: + { + const auto digit = std::get(token.value); + + // numerical prerelease identifier doesn't allow leading zero + // 1.2.3-1.alpha is valid, + // 1.2.3-01b is valid as well, but + // 1.2.3-01.alpha is not valid + + // Only check for leading zero when digit is the first character of the + // prerelease identifier. + if (result.empty() && is_leading_zero(digit)) { + return failure(token.lexeme); + } + + result.push_back(to_char(digit)); + break; + } + default: + return failure(token.lexeme); + } + } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { + auto type = detail::prerelease_identifier_type::numeric; + for (char c : identifier) { + if (c == '-' || detail::is_letter(c)) { + type = detail::prerelease_identifier_type::alphanumeric; + break; + } + } + return detail::prerelease_identifier{ type, identifier }; + } + + constexpr from_chars_result parse_build_identifier(string& out) { + string result; + token token = stream_.advance(); + + do { + switch (token.type) { + case token_type::hyphen: + result.push_back('-'); + break; + case token_type::letter: + result.push_back(std::get(token.value)); + break; + case token_type::digit: + { + const auto digit = std::get(token.value); + result.push_back(to_char(digit)); + break; + } + default: + return failure(token.lexeme); + } + } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr bool is_leading_zero(int digit) noexcept { + if (digit != 0) { + return false; + } + + size_t k = 0; + int alpha_numerics = 0; + int digits = 0; + + while (true) { + const token token = stream_.peek(k); + + if (!is_alphanumeric(token)) { + break; + } + + ++alpha_numerics; + + if (is_digit(token)) { + ++digits; + } + + ++k; + } + + return digits > 0 && digits == alpha_numerics; + } + + constexpr bool is_digit(const token& token) const noexcept { + return token.type == token_type::digit; + } + + constexpr bool is_eol(const token& token) const noexcept { + return token.type == token_type::eol; + } + + constexpr bool is_alphanumeric(const token& token) const noexcept { + return token.type == token_type::hyphen || token.type == token_type::letter || token.type == token_type::digit; + } + }; + + template + constexpr int compare_prerelease(const version& lhs, const version& rhs) noexcept { + return prerelease_comparator{}.compare(lhs, rhs); + } + + template + constexpr int compare_parsed(const version& lhs, const version& rhs, version_compare_option compare_option) { + int result = lhs.major() - rhs.major(); + if (result != 0) { + return result; + } + + result = lhs.minor() - rhs.minor(); + if (result != 0) { + return result; + } + + result = lhs.patch() - rhs.patch(); + if (result != 0) { + return result; + } + + if (compare_option == version_compare_option::include_prerelease) { + result = detail::compare_prerelease(lhs, rhs); + } + + return result; + } + + template + constexpr from_chars_result parse(std::string_view str, version& out) { + token_stream token_stream; + from_chars_result result = lexer{ str }.scan_tokens(token_stream); + if (!result) { + return result; + } + + result = version_parser{ token_stream }.parse(out); + if (!result) { + return result; + } + + if (!token_stream.consume(token_type::eol)) { + return failure(token_stream.previous().lexeme); + } + + return success(token_stream.previous().lexeme); + } + + } // namespace semver::detail + + template + [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) == 0; + } + + template + [[nodiscard]] constexpr bool operator!=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) != 0; + } + + template + [[nodiscard]] constexpr bool operator>(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) > 0; + } + + template + [[nodiscard]] constexpr bool operator>=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) >= 0; + } + + template + [[nodiscard]] constexpr bool operator<(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) < 0; + } + + template + [[nodiscard]] constexpr bool operator<=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; + } #if __cpp_impl_three_way_comparison >= 201907L - template - [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { - int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); - if (compare == 0) - return std::strong_ordering::equal; + template + [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { + int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); + if (compare == 0) + return std::strong_ordering::equal; if (compare > 0) - return std::strong_ordering::greater; + return std::strong_ordering::greater; return std::strong_ordering::less; - } + } #endif - template - constexpr from_chars_result parse(std::string_view str, version& output) { - return detail::parse(str, output); - } - - constexpr bool valid(std::string_view str) { - version v{}; - return detail::parse(str, v); - } - - namespace detail { - template - class range_comparator { - public: - constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} - - constexpr bool contains(const version& other) const noexcept { - switch (op_) { - case range_operator::less: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; - case range_operator::less_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; - case range_operator::greater: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; - case range_operator::greater_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; - case range_operator::equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; - } - return false; - } - - constexpr const version& get_version() const noexcept { return v_; } - - constexpr range_operator get_operator() const noexcept { return op_; } - - constexpr string to_string() const { - string result; - switch (op_) { - case range_operator::less: result += "<"; break; - case range_operator::less_or_equal: result += "<="; break; - case range_operator::greater: result += ">"; break; - case range_operator::greater_or_equal: result += ">="; break; - case range_operator::equal: result += "="; break; - } - result += v_.to_string(); - return result; - } - - private: - version v_; - range_operator op_; - }; - - class range_parser; - - template - class range { - public: - friend class detail::range_parser; - - constexpr bool contains(const version& v, version_compare_option option) const noexcept { - if (option == version_compare_option::exclude_prerelease) { - if (!match_at_least_one_comparator_with_prerelease(v)) { - return false; - } - } - - return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { - return ranges_comparator.contains(v); - }); - } - - constexpr auto begin() const noexcept { - return ranges_comparators_.begin(); - } - - constexpr auto end() const noexcept { - return ranges_comparators_.end(); - } - - constexpr std::size_t size() const noexcept { - return ranges_comparators_.size(); - } - - constexpr bool empty() const noexcept { - return ranges_comparators_.empty(); - } - - constexpr string to_string() const { - return join(ranges_comparators_, " "); - } - - private: - vector> ranges_comparators_; - - constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { - if (v.prerelease_tag().empty()) { - return true; - } - - return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { - const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); - const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; - return has_prerelease && equal_without_prerelease; - }); - } - }; - } - - template - class range_set { - public: - friend class detail::range_parser; - - constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { - return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { - return range.contains(v, option); - }); - } - - constexpr auto begin() const noexcept { - return ranges_.begin(); - } - - constexpr auto end() const noexcept { - return ranges_.end(); - } - - constexpr std::size_t size() const noexcept { - return ranges_.size(); - } - - constexpr bool empty() const noexcept { - return ranges_.empty(); - } - - constexpr string to_string() const { - return join(ranges_, " "); - } - - private: - vector> ranges_; - }; - - namespace detail { - class range_parser { - public: - constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} - - template - constexpr from_chars_result parse(range_set& out) noexcept { - vector> ranges; - - do { - - detail::range range; - if (const auto res = parse_range(range); !res) { - return res; - } - - ranges.push_back(range); - skip_whitespaces(); - - } while (stream_.advanceIfMatch(token_type::logical_or)); - - out.ranges_ = std::move(ranges); - - return success(stream_.peek().lexeme); - } - - private: - token_stream stream_; - - template - constexpr from_chars_result parse_range(detail::range& out) noexcept { - do { - skip_whitespaces(); - - if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { - return res; - } - - skip_whitespaces(); - - } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); - - return success(stream_.peek().lexeme); - } - - template - constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { - range_operator op = range_operator::equal; - token token; - if (stream_.advanceIfMatch(token, token_type::range_operator)) { - op = std::get(token.value); - } - - skip_whitespaces(); - - version ver; - version_parser parser{ stream_ }; - if (const auto res = parser.parse(ver); !res) { - return res; - } - - out.emplace_back(ver, op); - return success(stream_.peek().lexeme); - } - - constexpr void skip_whitespaces() noexcept { - while (stream_.advanceIfMatch(token_type::space)) { - ; - } - } - }; - } // namespace semver::detail - - - template - constexpr from_chars_result parse(std::string_view str, range_set& out) { - detail::token_stream token_stream; - const from_chars_result result = detail::lexer{ str }.scan_tokens(token_stream); - if (!result) { - return result; - } - - return detail::range_parser{ std::move(token_stream) }.parse(out); - } + template + constexpr from_chars_result parse(std::string_view str, version& output) { + return detail::parse(str, output); + } + + constexpr bool valid(std::string_view str) { + version v{}; + return detail::parse(str, v); + } + + namespace detail { + template + class range_comparator { + public: + constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} + + constexpr bool contains(const version& other) const noexcept { + switch (op_) { + case range_operator::less: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; + case range_operator::less_or_equal: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; + case range_operator::greater: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; + case range_operator::greater_or_equal: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; + case range_operator::equal: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; + } + return false; + } + + constexpr const version& get_version() const noexcept { return v_; } + + constexpr range_operator get_operator() const noexcept { return op_; } + + constexpr string to_string() const { + string result; + switch (op_) { + case range_operator::less: result += "<"; break; + case range_operator::less_or_equal: result += "<="; break; + case range_operator::greater: result += ">"; break; + case range_operator::greater_or_equal: result += ">="; break; + case range_operator::equal: result += "="; break; + } + result += v_.to_string(); + return result; + } + + private: + version v_; + range_operator op_; + }; + + class range_parser; + + template + class range { + public: + friend class detail::range_parser; + + constexpr bool contains(const version& v, version_compare_option option) const noexcept { + if (option == version_compare_option::exclude_prerelease) { + if (!match_at_least_one_comparator_with_prerelease(v)) { + return false; + } + } + + return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + return ranges_comparator.contains(v); + }); + } + + constexpr auto begin() const noexcept { + return ranges_comparators_.begin(); + } + + constexpr auto end() const noexcept { + return ranges_comparators_.end(); + } + + constexpr std::size_t size() const noexcept { + return ranges_comparators_.size(); + } + + constexpr bool empty() const noexcept { + return ranges_comparators_.empty(); + } + + constexpr string to_string() const { + return join(ranges_comparators_, " "); + } + + private: + vector> ranges_comparators_; + + constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { + if (v.prerelease_tag().empty()) { + return true; + } + + return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); + const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; + return has_prerelease && equal_without_prerelease; + }); + } + }; + } + + template + class range_set { + public: + friend class detail::range_parser; + + constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { + return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { + return range.contains(v, option); + }); + } + + constexpr auto begin() const noexcept { + return ranges_.begin(); + } + + constexpr auto end() const noexcept { + return ranges_.end(); + } + + constexpr std::size_t size() const noexcept { + return ranges_.size(); + } + + constexpr bool empty() const noexcept { + return ranges_.empty(); + } + + constexpr string to_string() const { + return join(ranges_, " "); + } + + private: + vector> ranges_; + }; + + namespace detail { + class range_parser { + public: + constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} + + template + constexpr from_chars_result parse(range_set& out) noexcept { + vector> ranges; + + do { + + detail::range range; + if (const auto res = parse_range(range); !res) { + return res; + } + + ranges.push_back(range); + skip_whitespaces(); + + } while (stream_.advanceIfMatch(token_type::logical_or)); + + out.ranges_ = std::move(ranges); + + return success(stream_.peek().lexeme); + } + + private: + token_stream stream_; + + template + constexpr from_chars_result parse_range(detail::range& out) noexcept { + do { + skip_whitespaces(); + + if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { + return res; + } + + skip_whitespaces(); + + } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); + + return success(stream_.peek().lexeme); + } + + template + constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { + range_operator op = range_operator::equal; + token token; + if (stream_.advanceIfMatch(token, token_type::range_operator)) { + op = std::get(token.value); + } + + skip_whitespaces(); + + version ver; + version_parser parser{ stream_ }; + if (const auto res = parser.parse(ver); !res) { + return res; + } + + out.emplace_back(ver, op); + return success(stream_.peek().lexeme); + } + + constexpr void skip_whitespaces() noexcept { + while (stream_.advanceIfMatch(token_type::space)) { + ; + } + } + }; + } // namespace semver::detail + + + template + constexpr from_chars_result parse(std::string_view str, range_set& out) { + detail::token_stream token_stream; + const from_chars_result result = detail::lexer{ str }.scan_tokens(token_stream); + if (!result) { + return result; + } + + return detail::range_parser{ std::move(token_stream) }.parse(out); + } } // namespace semver #ifndef PLUGIFY_VECTOR_NO_STD_HASH @@ -1078,7 +1078,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); @@ -1089,7 +1089,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); @@ -1100,7 +1100,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); diff --git a/test/cross_call_master/external/plugify/include/pps/cross_call_worker.hpp b/test/cross_call_master/external/plugify/include/pps/cross_call_worker.hpp index a18bc66..0af3cec 100644 --- a/test/cross_call_master/external/plugify/include/pps/cross_call_worker.hpp +++ b/test/cross_call_master/external/plugify/include/pps/cross_call_worker.hpp @@ -7,3018 +7,3155 @@ // Generated from cross_call_worker.pplugin by https://github.com/untrustedmodders/plugify-module-cpp/blob/main/generator/generator.py namespace cross_call_worker { - enum class Example : int32_t { - First = 1, - Second = 2, - Third = 3, - Forth = 4, - }; - - using NoParamReturnFunctionFunc = void (*)(); - using FuncVoid = void (*)(); - using FuncBool = bool (*)(); - using FuncChar8 = char (*)(); - using FuncChar16 = char16_t (*)(); - using FuncInt8 = int8_t (*)(); - using FuncInt16 = int16_t (*)(); - using FuncInt32 = int32_t (*)(); - using FuncInt64 = int64_t (*)(); - using FuncUInt8 = uint8_t (*)(); - using FuncUInt16 = uint16_t (*)(); - using FuncUInt32 = uint32_t (*)(); - using FuncUInt64 = uint64_t (*)(); - using FuncPtr = void* (*)(); - using FuncFloat = float (*)(); - using FuncDouble = double (*)(); - using FuncString = plg::string (*)(); - using FuncAny = plg::any (*)(); - using FuncFunction = void* (*)(); - using FuncBoolVector = plg::vector (*)(); - using FuncChar8Vector = plg::vector (*)(); - using FuncChar16Vector = plg::vector (*)(); - using FuncInt8Vector = plg::vector (*)(); - using FuncInt16Vector = plg::vector (*)(); - using FuncInt32Vector = plg::vector (*)(); - using FuncInt64Vector = plg::vector (*)(); - using FuncUInt8Vector = plg::vector (*)(); - using FuncUInt16Vector = plg::vector (*)(); - using FuncUInt32Vector = plg::vector (*)(); - using FuncUInt64Vector = plg::vector (*)(); - using FuncPtrVector = plg::vector (*)(); - using FuncFloatVector = plg::vector (*)(); - using FuncDoubleVector = plg::vector (*)(); - using FuncStringVector = plg::vector (*)(); - using FuncAnyVector = plg::vector (*)(); - using FuncVec2Vector = plg::vector (*)(); - using FuncVec3Vector = plg::vector (*)(); - using FuncVec4Vector = plg::vector (*)(); - using FuncMat4x4Vector = plg::vector (*)(); - using FuncVec2 = plg::vec2 (*)(); - using FuncVec3 = plg::vec3 (*)(); - using FuncVec4 = plg::vec4 (*)(); - using FuncMat4x4 = plg::mat4x4 (*)(); - using Func1 = int32_t (*)(const plg::vec3&); - using Func2 = char (*)(float, int64_t); - using Func3 = void (*)(void*, const plg::vec4&, const plg::string&); - using Func4 = plg::vec4 (*)(bool, int32_t, char16_t, const plg::mat4x4&); - using Func5 = bool (*)(int8_t, const plg::vec2&, void*, double, const plg::vector&); - using Func6 = int64_t (*)(const plg::string&, float, const plg::vector&, int16_t, const plg::vector&, void*); - using Func7 = double (*)(const plg::vector&, uint16_t, char16_t, const plg::vector&, const plg::vec4&, bool, uint64_t); - using Func8 = plg::mat4x4 (*)(const plg::vec3&, const plg::vector&, int16_t, bool, const plg::vec4&, const plg::vector&, char16_t, int32_t); - using Func9 = void (*)(float, const plg::vec2&, const plg::vector&, uint64_t, bool, const plg::string&, const plg::vec4&, int16_t, void*); - using Func10 = uint32_t (*)(const plg::vec4&, const plg::mat4x4&, const plg::vector&, uint64_t, const plg::vector&, int32_t, bool, const plg::vec2&, int64_t, double); - using Func11 = void* (*)(const plg::vector&, char16_t, uint8_t, double, const plg::vec3&, const plg::vector&, int64_t, uint16_t, float, const plg::vec2&, uint32_t); - using Func12 = bool (*)(void*, const plg::vector&, uint32_t, double, bool, int32_t, int8_t, uint64_t, float, const plg::vector&, int64_t, char); - using Func13 = plg::string (*)(int64_t, const plg::vector&, uint16_t, float, const plg::vector&, const plg::vec4&, const plg::string&, int32_t, const plg::vec3&, void*, const plg::vec2&, const plg::vector&, int16_t); - using Func14 = plg::vector (*)(const plg::vector&, const plg::vector&, const plg::mat4x4&, bool, char16_t, int32_t, const plg::vector&, uint16_t, const plg::vector&, int8_t, const plg::vec3&, const plg::vec4&, double, void*); - using Func15 = int16_t (*)(const plg::vector&, const plg::mat4x4&, const plg::vec4&, void*, uint64_t, const plg::vector&, bool, float, const plg::vector&, uint8_t, int32_t, const plg::vec2&, uint16_t, double, const plg::vector&); - using Func16 = void* (*)(const plg::vector&, int16_t, const plg::vector&, const plg::vec4&, const plg::mat4x4&, const plg::vec2&, const plg::vector&, const plg::vector&, const plg::string&, int64_t, const plg::vector&, const plg::vec3&, float, double, int8_t, uint16_t); - using Func17 = void (*)(int32_t&); - using Func18 = plg::vec2 (*)(int8_t&, int16_t&); - using Func19 = void (*)(uint32_t&, plg::vec3&, plg::vector&); - using Func20 = int32_t (*)(char16_t&, plg::vec4&, plg::vector&, char&); - using Func21 = float (*)(plg::mat4x4&, plg::vector&, plg::vec2&, bool&, double&); - using Func22 = uint64_t (*)(void*&, uint32_t&, plg::vector&, int16_t&, plg::string&, plg::vec4&); - using Func23 = void (*)(uint64_t&, plg::vec2&, plg::vector&, char16_t&, float&, int8_t&, plg::vector&); - using Func24 = plg::mat4x4 (*)(plg::vector&, int64_t&, plg::vector&, plg::vec4&, uint64_t&, plg::vector&, double&, plg::vector&); - using Func25 = double (*)(int32_t&, plg::vector&, bool&, uint8_t&, plg::string&, plg::vec3&, int64_t&, plg::vec4&, uint16_t&); - using Func26 = char (*)(char16_t&, plg::vec2&, plg::mat4x4&, plg::vector&, int16_t&, uint64_t&, uint32_t&, plg::vector&, void*&, bool&); - using Func27 = uint8_t (*)(float&, plg::vec3&, void*&, plg::vec2&, plg::vector&, plg::mat4x4&, bool&, plg::vec4&, int8_t&, int32_t&, plg::vector&); - using Func28 = plg::string (*)(void*&, uint16_t&, plg::vector&, plg::mat4x4&, float&, plg::vec4&, plg::string&, plg::vector&, int64_t&, bool&, plg::vec3&, plg::vector&); - using Func29 = plg::vector (*)(plg::vec4&, int32_t&, plg::vector&, double&, bool&, int8_t&, plg::vector&, float&, plg::string&, plg::mat4x4&, uint64_t&, plg::vec3&, plg::vector&); - using Func30 = int32_t (*)(void*&, plg::vec4&, int64_t&, plg::vector&, bool&, plg::string&, plg::vec3&, plg::vector&, float&, plg::vec2&, plg::mat4x4&, int8_t&, plg::vector&, double&); - using Func31 = plg::vec3 (*)(char&, uint32_t&, plg::vector&, plg::vec4&, plg::string&, bool&, int64_t&, plg::vec2&, int8_t&, uint16_t&, plg::vector&, plg::mat4x4&, plg::vec3&, float&, plg::vector&); - using Func32 = double (*)(int32_t&, uint16_t&, plg::vector&, plg::vec4&, void*&, plg::vector&, plg::mat4x4&, uint64_t&, plg::string&, int64_t&, plg::vec2&, plg::vector&, bool&, plg::vec3&, uint8_t&, plg::vector&); - using Func33 = void (*)(plg::any&); - using FuncEnum = plg::vector (*)(Example, plg::vector&); - - /** - * @brief No description provided. - * - * @function NoParamReturnVoid - */ - inline void NoParamReturnVoid() { - using NoParamReturnVoidFn = void (*)(); - static NoParamReturnVoidFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnVoid", reinterpret_cast(&__func)); - __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnBool - * - * @return bool: No description available. - */ - inline bool NoParamReturnBool() { - using NoParamReturnBoolFn = bool (*)(); - static NoParamReturnBoolFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnBool", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnChar8 - * - * @return char8: No description available. - */ - inline char NoParamReturnChar8() { - using NoParamReturnChar8Fn = char (*)(); - static NoParamReturnChar8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnChar8", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnChar16 - * - * @return char16: No description available. - */ - inline char16_t NoParamReturnChar16() { - using NoParamReturnChar16Fn = char16_t (*)(); - static NoParamReturnChar16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnChar16", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnInt8 - * - * @return int8: No description available. - */ - inline int8_t NoParamReturnInt8() { - using NoParamReturnInt8Fn = int8_t (*)(); - static NoParamReturnInt8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnInt8", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnInt16 - * - * @return int16: No description available. - */ - inline int16_t NoParamReturnInt16() { - using NoParamReturnInt16Fn = int16_t (*)(); - static NoParamReturnInt16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnInt16", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnInt32 - * - * @return int32: No description available. - */ - inline int32_t NoParamReturnInt32() { - using NoParamReturnInt32Fn = int32_t (*)(); - static NoParamReturnInt32Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnInt32", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnInt64 - * - * @return int64: No description available. - */ - inline int64_t NoParamReturnInt64() { - using NoParamReturnInt64Fn = int64_t (*)(); - static NoParamReturnInt64Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnInt64", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnUInt8 - * - * @return uint8: No description available. - */ - inline uint8_t NoParamReturnUInt8() { - using NoParamReturnUInt8Fn = uint8_t (*)(); - static NoParamReturnUInt8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnUInt8", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnUInt16 - * - * @return uint16: No description available. - */ - inline uint16_t NoParamReturnUInt16() { - using NoParamReturnUInt16Fn = uint16_t (*)(); - static NoParamReturnUInt16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnUInt16", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnUInt32 - * - * @return uint32: No description available. - */ - inline uint32_t NoParamReturnUInt32() { - using NoParamReturnUInt32Fn = uint32_t (*)(); - static NoParamReturnUInt32Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnUInt32", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnUInt64 - * - * @return uint64: No description available. - */ - inline uint64_t NoParamReturnUInt64() { - using NoParamReturnUInt64Fn = uint64_t (*)(); - static NoParamReturnUInt64Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnUInt64", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnPointer - * - * @return ptr64: No description available. - */ - inline void* NoParamReturnPointer() { - using NoParamReturnPointerFn = void* (*)(); - static NoParamReturnPointerFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnPointer", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnFloat - * - * @return float: No description available. - */ - inline float NoParamReturnFloat() { - using NoParamReturnFloatFn = float (*)(); - static NoParamReturnFloatFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnFloat", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnDouble - * - * @return double: No description available. - */ - inline double NoParamReturnDouble() { - using NoParamReturnDoubleFn = double (*)(); - static NoParamReturnDoubleFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnDouble", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnFunction - * - * @return function: No description available. - */ - inline NoParamReturnFunctionFunc NoParamReturnFunction() { - using NoParamReturnFunctionFn = NoParamReturnFunctionFunc (*)(); - static NoParamReturnFunctionFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnFunction", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnString - * - * @return string: No description available. - */ - inline plg::string NoParamReturnString() { - using NoParamReturnStringFn = plg::string (*)(); - static NoParamReturnStringFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnString", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnAny - * - * @return any: No description available. - */ - inline plg::any NoParamReturnAny() { - using NoParamReturnAnyFn = plg::any (*)(); - static NoParamReturnAnyFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnAny", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayBool - * - * @return bool[]: No description available. - */ - inline plg::vector NoParamReturnArrayBool() { - using NoParamReturnArrayBoolFn = plg::vector (*)(); - static NoParamReturnArrayBoolFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayBool", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayChar8 - * - * @return char8[]: No description available. - */ - inline plg::vector NoParamReturnArrayChar8() { - using NoParamReturnArrayChar8Fn = plg::vector (*)(); - static NoParamReturnArrayChar8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayChar8", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayChar16 - * - * @return char16[]: No description available. - */ - inline plg::vector NoParamReturnArrayChar16() { - using NoParamReturnArrayChar16Fn = plg::vector (*)(); - static NoParamReturnArrayChar16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayChar16", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayInt8 - * - * @return int8[]: No description available. - */ - inline plg::vector NoParamReturnArrayInt8() { - using NoParamReturnArrayInt8Fn = plg::vector (*)(); - static NoParamReturnArrayInt8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayInt8", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayInt16 - * - * @return int16[]: No description available. - */ - inline plg::vector NoParamReturnArrayInt16() { - using NoParamReturnArrayInt16Fn = plg::vector (*)(); - static NoParamReturnArrayInt16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayInt16", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayInt32 - * - * @return int32[]: No description available. - */ - inline plg::vector NoParamReturnArrayInt32() { - using NoParamReturnArrayInt32Fn = plg::vector (*)(); - static NoParamReturnArrayInt32Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayInt32", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayInt64 - * - * @return int64[]: No description available. - */ - inline plg::vector NoParamReturnArrayInt64() { - using NoParamReturnArrayInt64Fn = plg::vector (*)(); - static NoParamReturnArrayInt64Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayInt64", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayUInt8 - * - * @return uint8[]: No description available. - */ - inline plg::vector NoParamReturnArrayUInt8() { - using NoParamReturnArrayUInt8Fn = plg::vector (*)(); - static NoParamReturnArrayUInt8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayUInt8", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayUInt16 - * - * @return uint16[]: No description available. - */ - inline plg::vector NoParamReturnArrayUInt16() { - using NoParamReturnArrayUInt16Fn = plg::vector (*)(); - static NoParamReturnArrayUInt16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayUInt16", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayUInt32 - * - * @return uint32[]: No description available. - */ - inline plg::vector NoParamReturnArrayUInt32() { - using NoParamReturnArrayUInt32Fn = plg::vector (*)(); - static NoParamReturnArrayUInt32Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayUInt32", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayUInt64 - * - * @return uint64[]: No description available. - */ - inline plg::vector NoParamReturnArrayUInt64() { - using NoParamReturnArrayUInt64Fn = plg::vector (*)(); - static NoParamReturnArrayUInt64Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayUInt64", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayPointer - * - * @return ptr64[]: No description available. - */ - inline plg::vector NoParamReturnArrayPointer() { - using NoParamReturnArrayPointerFn = plg::vector (*)(); - static NoParamReturnArrayPointerFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayPointer", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayFloat - * - * @return float[]: No description available. - */ - inline plg::vector NoParamReturnArrayFloat() { - using NoParamReturnArrayFloatFn = plg::vector (*)(); - static NoParamReturnArrayFloatFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayFloat", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayDouble - * - * @return double[]: No description available. - */ - inline plg::vector NoParamReturnArrayDouble() { - using NoParamReturnArrayDoubleFn = plg::vector (*)(); - static NoParamReturnArrayDoubleFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayDouble", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayString - * - * @return string[]: No description available. - */ - inline plg::vector NoParamReturnArrayString() { - using NoParamReturnArrayStringFn = plg::vector (*)(); - static NoParamReturnArrayStringFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayString", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayAny - * - * @return any[]: No description available. - */ - inline plg::vector NoParamReturnArrayAny() { - using NoParamReturnArrayAnyFn = plg::vector (*)(); - static NoParamReturnArrayAnyFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayAny", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayVector2 - * - * @return vec2[]: No description available. - */ - inline plg::vector NoParamReturnArrayVector2() { - using NoParamReturnArrayVector2Fn = plg::vector (*)(); - static NoParamReturnArrayVector2Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayVector2", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayVector3 - * - * @return vec3[]: No description available. - */ - inline plg::vector NoParamReturnArrayVector3() { - using NoParamReturnArrayVector3Fn = plg::vector (*)(); - static NoParamReturnArrayVector3Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayVector3", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayVector4 - * - * @return vec4[]: No description available. - */ - inline plg::vector NoParamReturnArrayVector4() { - using NoParamReturnArrayVector4Fn = plg::vector (*)(); - static NoParamReturnArrayVector4Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayVector4", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayMatrix4x4 - * - * @return mat4x4[]: No description available. - */ - inline plg::vector NoParamReturnArrayMatrix4x4() { - using NoParamReturnArrayMatrix4x4Fn = plg::vector (*)(); - static NoParamReturnArrayMatrix4x4Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayMatrix4x4", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnVector2 - * - * @return vec2: No description available. - */ - inline plg::vec2 NoParamReturnVector2() { - using NoParamReturnVector2Fn = plg::vec2 (*)(); - static NoParamReturnVector2Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnVector2", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnVector3 - * - * @return vec3: No description available. - */ - inline plg::vec3 NoParamReturnVector3() { - using NoParamReturnVector3Fn = plg::vec3 (*)(); - static NoParamReturnVector3Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnVector3", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnVector4 - * - * @return vec4: No description available. - */ - inline plg::vec4 NoParamReturnVector4() { - using NoParamReturnVector4Fn = plg::vec4 (*)(); - static NoParamReturnVector4Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnVector4", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnMatrix4x4 - * - * @return mat4x4: No description available. - */ - inline plg::mat4x4 NoParamReturnMatrix4x4() { - using NoParamReturnMatrix4x4Fn = plg::mat4x4 (*)(); - static NoParamReturnMatrix4x4Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnMatrix4x4", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function Param1 - * @param a (int32): No description available. - */ - inline void Param1(int32_t a) { - using Param1Fn = void (*)(int32_t); - static Param1Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param1", reinterpret_cast(&__func)); - __func(a); - } - - /** - * @brief No description provided. - * - * @function Param2 - * @param a (int32): No description available. - * @param b (float): No description available. - */ - inline void Param2(int32_t a, float b) { - using Param2Fn = void (*)(int32_t, float); - static Param2Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param2", reinterpret_cast(&__func)); - __func(a, b); - } - - /** - * @brief No description provided. - * - * @function Param3 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - */ - inline void Param3(int32_t a, float b, double c) { - using Param3Fn = void (*)(int32_t, float, double); - static Param3Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param3", reinterpret_cast(&__func)); - __func(a, b, c); - } - - /** - * @brief No description provided. - * - * @function Param4 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - */ - inline void Param4(int32_t a, float b, double c, const plg::vec4& d) { - using Param4Fn = void (*)(int32_t, float, double, const plg::vec4&); - static Param4Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param4", reinterpret_cast(&__func)); - __func(a, b, c, d); - } - - /** - * @brief No description provided. - * - * @function Param5 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - */ - inline void Param5(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e) { - using Param5Fn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&); - static Param5Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param5", reinterpret_cast(&__func)); - __func(a, b, c, d, e); - } - - /** - * @brief No description provided. - * - * @function Param6 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - */ - inline void Param6(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f) { - using Param6Fn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char); - static Param6Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param6", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f); - } - - /** - * @brief No description provided. - * - * @function Param7 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - */ - inline void Param7(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g) { - using Param7Fn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char, const plg::string&); - static Param7Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param7", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g); - } - - /** - * @brief No description provided. - * - * @function Param8 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - */ - inline void Param8(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h) { - using Param8Fn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char, const plg::string&, char16_t); - static Param8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param8", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h); - } - - /** - * @brief No description provided. - * - * @function Param9 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - * @param k (int16): No description available. - */ - inline void Param9(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h, int16_t k) { - using Param9Fn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char, const plg::string&, char16_t, int16_t); - static Param9Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param9", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h, k); - } - - /** - * @brief No description provided. - * - * @function Param10 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - * @param k (int16): No description available. - * @param l (ptr64): No description available. - */ - inline void Param10(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h, int16_t k, void* l) { - using Param10Fn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char, const plg::string&, char16_t, int16_t, void*); - static Param10Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param10", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h, k, l); - } - - /** - * @brief No description provided. - * - * @function ParamRef1 - * @param a (int32): No description available. - */ - inline void ParamRef1(int32_t& a) { - using ParamRef1Fn = void (*)(int32_t&); - static ParamRef1Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef1", reinterpret_cast(&__func)); - __func(a); - } - - /** - * @brief No description provided. - * - * @function ParamRef2 - * @param a (int32): No description available. - * @param b (float): No description available. - */ - inline void ParamRef2(int32_t& a, float& b) { - using ParamRef2Fn = void (*)(int32_t&, float&); - static ParamRef2Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef2", reinterpret_cast(&__func)); - __func(a, b); - } - - /** - * @brief No description provided. - * - * @function ParamRef3 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - */ - inline void ParamRef3(int32_t& a, float& b, double& c) { - using ParamRef3Fn = void (*)(int32_t&, float&, double&); - static ParamRef3Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef3", reinterpret_cast(&__func)); - __func(a, b, c); - } - - /** - * @brief No description provided. - * - * @function ParamRef4 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - */ - inline void ParamRef4(int32_t& a, float& b, double& c, plg::vec4& d) { - using ParamRef4Fn = void (*)(int32_t&, float&, double&, plg::vec4&); - static ParamRef4Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef4", reinterpret_cast(&__func)); - __func(a, b, c, d); - } - - /** - * @brief No description provided. - * - * @function ParamRef5 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - */ - inline void ParamRef5(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e) { - using ParamRef5Fn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&); - static ParamRef5Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef5", reinterpret_cast(&__func)); - __func(a, b, c, d, e); - } - - /** - * @brief No description provided. - * - * @function ParamRef6 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - */ - inline void ParamRef6(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f) { - using ParamRef6Fn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&); - static ParamRef6Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef6", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f); - } - - /** - * @brief No description provided. - * - * @function ParamRef7 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - */ - inline void ParamRef7(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g) { - using ParamRef7Fn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&, plg::string&); - static ParamRef7Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef7", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g); - } - - /** - * @brief No description provided. - * - * @function ParamRef8 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - */ - inline void ParamRef8(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h) { - using ParamRef8Fn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&, plg::string&, char16_t&); - static ParamRef8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef8", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h); - } - - /** - * @brief No description provided. - * - * @function ParamRef9 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - * @param k (int16): No description available. - */ - inline void ParamRef9(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h, int16_t& k) { - using ParamRef9Fn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&, plg::string&, char16_t&, int16_t&); - static ParamRef9Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef9", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h, k); - } - - /** - * @brief No description provided. - * - * @function ParamRef10 - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - * @param k (int16): No description available. - * @param l (ptr64): No description available. - */ - inline void ParamRef10(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h, int16_t& k, void*& l) { - using ParamRef10Fn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&, plg::string&, char16_t&, int16_t&, void*&); - static ParamRef10Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef10", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h, k, l); - } - - /** - * @brief No description provided. - * - * @function ParamRefVectors - * @param p1 (bool[]): No description available. - * @param p2 (char8[]): No description available. - * @param p3 (char16[]): No description available. - * @param p4 (int8[]): No description available. - * @param p5 (int16[]): No description available. - * @param p6 (int32[]): No description available. - * @param p7 (int64[]): No description available. - * @param p8 (uint8[]): No description available. - * @param p9 (uint16[]): No description available. - * @param p10 (uint32[]): No description available. - * @param p11 (uint64[]): No description available. - * @param p12 (ptr64[]): No description available. - * @param p13 (float[]): No description available. - * @param p14 (double[]): No description available. - * @param p15 (string[]): No description available. - */ - inline void ParamRefVectors(plg::vector& p1, plg::vector& p2, plg::vector& p3, plg::vector& p4, plg::vector& p5, plg::vector& p6, plg::vector& p7, plg::vector& p8, plg::vector& p9, plg::vector& p10, plg::vector& p11, plg::vector& p12, plg::vector& p13, plg::vector& p14, plg::vector& p15) { - using ParamRefVectorsFn = void (*)(plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&); - static ParamRefVectorsFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRefVectors", reinterpret_cast(&__func)); - __func(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); - } - - /** - * @brief No description provided. - * - * @function ParamAllPrimitives - * @param p1 (bool): No description available. - * @param p2 (char8): No description available. - * @param p3 (char16): No description available. - * @param p4 (int8): No description available. - * @param p5 (int16): No description available. - * @param p6 (int32): No description available. - * @param p7 (int64): No description available. - * @param p8 (uint8): No description available. - * @param p9 (uint16): No description available. - * @param p10 (uint32): No description available. - * @param p11 (uint64): No description available. - * @param p12 (ptr64): No description available. - * @param p13 (float): No description available. - * @param p14 (double): No description available. - * - * @return int64: No description available. - */ - inline int64_t ParamAllPrimitives(bool p1, char p2, char16_t p3, int8_t p4, int16_t p5, int32_t p6, int64_t p7, uint8_t p8, uint16_t p9, uint32_t p10, uint64_t p11, void* p12, float p13, double p14) { - using ParamAllPrimitivesFn = int64_t (*)(bool, char, char16_t, int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, void*, float, double); - static ParamAllPrimitivesFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamAllPrimitives", reinterpret_cast(&__func)); - return __func(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); - } - - /** - * @brief No description provided. - * - * @function ParamVariant - * @param p1 (any): No description available. - * @param p2 (any[]): No description available. - */ - inline void ParamVariant(const plg::any& p1, const plg::vector& p2) { - using ParamVariantFn = void (*)(const plg::any&, const plg::vector&); - static ParamVariantFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamVariant", reinterpret_cast(&__func)); - __func(p1, p2); - } - - /** - * @brief No description provided. - * - * @function ParamEnum - * @param p1 (int32): No description available. - * @param p2 (int32[]): No description available. - * - * @return int32: No description available. - */ - inline int32_t ParamEnum(Example p1, const plg::vector& p2) { - using ParamEnumFn = int32_t (*)(Example, const plg::vector&); - static ParamEnumFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamEnum", reinterpret_cast(&__func)); - return __func(p1, p2); - } - - /** - * @brief No description provided. - * - * @function ParamEnumRef - * @param p1 (int32): No description available. - * @param p2 (int32[]): No description available. - * - * @return int32: No description available. - */ - inline int32_t ParamEnumRef(Example& p1, plg::vector& p2) { - using ParamEnumRefFn = int32_t (*)(Example&, plg::vector&); - static ParamEnumRefFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamEnumRef", reinterpret_cast(&__func)); - return __func(p1, p2); - } - - /** - * @brief No description provided. - * - * @function ParamVariantRef - * @param p1 (any): No description available. - * @param p2 (any[]): No description available. - */ - inline void ParamVariantRef(plg::any& p1, plg::vector& p2) { - using ParamVariantRefFn = void (*)(plg::any&, plg::vector&); - static ParamVariantRefFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamVariantRef", reinterpret_cast(&__func)); - __func(p1, p2); - } - - /** - * @brief No description provided. - * - * @function CallFuncVoid - * @param func (function): No description available. - * - * @callback FuncVoid - * @brief No description provided. - * - * - * @return (callback): void: No description available. - */ - inline void CallFuncVoid(FuncVoid func) { - using CallFuncVoidFn = void (*)(FuncVoid); - static CallFuncVoidFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVoid", reinterpret_cast(&__func)); - __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncBool - * @param func (function): No description available. - * - * @return bool: No description available. - * - * @callback FuncBool - * @brief No description provided. - * - * - * @return (callback): bool: No description available. - */ - inline bool CallFuncBool(FuncBool func) { - using CallFuncBoolFn = bool (*)(FuncBool); - static CallFuncBoolFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncBool", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncChar8 - * @param func (function): No description available. - * - * @return char8: No description available. - * - * @callback FuncChar8 - * @brief No description provided. - * - * - * @return (callback): char8: No description available. - */ - inline char CallFuncChar8(FuncChar8 func) { - using CallFuncChar8Fn = char (*)(FuncChar8); - static CallFuncChar8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncChar8", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncChar16 - * @param func (function): No description available. - * - * @return char16: No description available. - * - * @callback FuncChar16 - * @brief No description provided. - * - * - * @return (callback): char16: No description available. - */ - inline char16_t CallFuncChar16(FuncChar16 func) { - using CallFuncChar16Fn = char16_t (*)(FuncChar16); - static CallFuncChar16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncChar16", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt8 - * @param func (function): No description available. - * - * @return int8: No description available. - * - * @callback FuncInt8 - * @brief No description provided. - * - * - * @return (callback): int8: No description available. - */ - inline int8_t CallFuncInt8(FuncInt8 func) { - using CallFuncInt8Fn = int8_t (*)(FuncInt8); - static CallFuncInt8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt8", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt16 - * @param func (function): No description available. - * - * @return int16: No description available. - * - * @callback FuncInt16 - * @brief No description provided. - * - * - * @return (callback): int16: No description available. - */ - inline int16_t CallFuncInt16(FuncInt16 func) { - using CallFuncInt16Fn = int16_t (*)(FuncInt16); - static CallFuncInt16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt16", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt32 - * @param func (function): No description available. - * - * @return int32: No description available. - * - * @callback FuncInt32 - * @brief No description provided. - * - * - * @return (callback): int32: No description available. - */ - inline int32_t CallFuncInt32(FuncInt32 func) { - using CallFuncInt32Fn = int32_t (*)(FuncInt32); - static CallFuncInt32Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt32", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt64 - * @param func (function): No description available. - * - * @return int64: No description available. - * - * @callback FuncInt64 - * @brief No description provided. - * - * - * @return (callback): int64: No description available. - */ - inline int64_t CallFuncInt64(FuncInt64 func) { - using CallFuncInt64Fn = int64_t (*)(FuncInt64); - static CallFuncInt64Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt64", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt8 - * @param func (function): No description available. - * - * @return uint8: No description available. - * - * @callback FuncUInt8 - * @brief No description provided. - * - * - * @return (callback): uint8: No description available. - */ - inline uint8_t CallFuncUInt8(FuncUInt8 func) { - using CallFuncUInt8Fn = uint8_t (*)(FuncUInt8); - static CallFuncUInt8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt8", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt16 - * @param func (function): No description available. - * - * @return uint16: No description available. - * - * @callback FuncUInt16 - * @brief No description provided. - * - * - * @return (callback): uint16: No description available. - */ - inline uint16_t CallFuncUInt16(FuncUInt16 func) { - using CallFuncUInt16Fn = uint16_t (*)(FuncUInt16); - static CallFuncUInt16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt16", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt32 - * @param func (function): No description available. - * - * @return uint32: No description available. - * - * @callback FuncUInt32 - * @brief No description provided. - * - * - * @return (callback): uint32: No description available. - */ - inline uint32_t CallFuncUInt32(FuncUInt32 func) { - using CallFuncUInt32Fn = uint32_t (*)(FuncUInt32); - static CallFuncUInt32Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt32", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt64 - * @param func (function): No description available. - * - * @return uint64: No description available. - * - * @callback FuncUInt64 - * @brief No description provided. - * - * - * @return (callback): uint64: No description available. - */ - inline uint64_t CallFuncUInt64(FuncUInt64 func) { - using CallFuncUInt64Fn = uint64_t (*)(FuncUInt64); - static CallFuncUInt64Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt64", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncPtr - * @param func (function): No description available. - * - * @return ptr64: No description available. - * - * @callback FuncPtr - * @brief No description provided. - * - * - * @return (callback): ptr64: No description available. - */ - inline void* CallFuncPtr(FuncPtr func) { - using CallFuncPtrFn = void* (*)(FuncPtr); - static CallFuncPtrFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncPtr", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncFloat - * @param func (function): No description available. - * - * @return float: No description available. - * - * @callback FuncFloat - * @brief No description provided. - * - * - * @return (callback): float: No description available. - */ - inline float CallFuncFloat(FuncFloat func) { - using CallFuncFloatFn = float (*)(FuncFloat); - static CallFuncFloatFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncFloat", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncDouble - * @param func (function): No description available. - * - * @return double: No description available. - * - * @callback FuncDouble - * @brief No description provided. - * - * - * @return (callback): double: No description available. - */ - inline double CallFuncDouble(FuncDouble func) { - using CallFuncDoubleFn = double (*)(FuncDouble); - static CallFuncDoubleFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncDouble", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncString - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback FuncString - * @brief No description provided. - * - * - * @return (callback): string: No description available. - */ - inline plg::string CallFuncString(FuncString func) { - using CallFuncStringFn = plg::string (*)(FuncString); - static CallFuncStringFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncString", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncAny - * @param func (function): No description available. - * - * @return any: No description available. - * - * @callback FuncAny - * @brief No description provided. - * - * - * @return (callback): any: No description available. - */ - inline plg::any CallFuncAny(FuncAny func) { - using CallFuncAnyFn = plg::any (*)(FuncAny); - static CallFuncAnyFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncAny", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncFunction - * @param func (function): No description available. - * - * @return ptr64: No description available. - * - * @callback FuncFunction - * @brief No description provided. - * - * - * @return (callback): function: No description available. - */ - inline void* CallFuncFunction(FuncFunction func) { - using CallFuncFunctionFn = void* (*)(FuncFunction); - static CallFuncFunctionFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncFunction", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncBoolVector - * @param func (function): No description available. - * - * @return bool[]: No description available. - * - * @callback FuncBoolVector - * @brief No description provided. - * - * - * @return (callback): bool[]: No description available. - */ - inline plg::vector CallFuncBoolVector(FuncBoolVector func) { - using CallFuncBoolVectorFn = plg::vector (*)(FuncBoolVector); - static CallFuncBoolVectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncBoolVector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncChar8Vector - * @param func (function): No description available. - * - * @return char8[]: No description available. - * - * @callback FuncChar8Vector - * @brief No description provided. - * - * - * @return (callback): char8[]: No description available. - */ - inline plg::vector CallFuncChar8Vector(FuncChar8Vector func) { - using CallFuncChar8VectorFn = plg::vector (*)(FuncChar8Vector); - static CallFuncChar8VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncChar8Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncChar16Vector - * @param func (function): No description available. - * - * @return char16[]: No description available. - * - * @callback FuncChar16Vector - * @brief No description provided. - * - * - * @return (callback): char16[]: No description available. - */ - inline plg::vector CallFuncChar16Vector(FuncChar16Vector func) { - using CallFuncChar16VectorFn = plg::vector (*)(FuncChar16Vector); - static CallFuncChar16VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncChar16Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt8Vector - * @param func (function): No description available. - * - * @return int8[]: No description available. - * - * @callback FuncInt8Vector - * @brief No description provided. - * - * - * @return (callback): int8[]: No description available. - */ - inline plg::vector CallFuncInt8Vector(FuncInt8Vector func) { - using CallFuncInt8VectorFn = plg::vector (*)(FuncInt8Vector); - static CallFuncInt8VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt8Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt16Vector - * @param func (function): No description available. - * - * @return int16[]: No description available. - * - * @callback FuncInt16Vector - * @brief No description provided. - * - * - * @return (callback): int16[]: No description available. - */ - inline plg::vector CallFuncInt16Vector(FuncInt16Vector func) { - using CallFuncInt16VectorFn = plg::vector (*)(FuncInt16Vector); - static CallFuncInt16VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt16Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt32Vector - * @param func (function): No description available. - * - * @return int32[]: No description available. - * - * @callback FuncInt32Vector - * @brief No description provided. - * - * - * @return (callback): int32[]: No description available. - */ - inline plg::vector CallFuncInt32Vector(FuncInt32Vector func) { - using CallFuncInt32VectorFn = plg::vector (*)(FuncInt32Vector); - static CallFuncInt32VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt32Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt64Vector - * @param func (function): No description available. - * - * @return int64[]: No description available. - * - * @callback FuncInt64Vector - * @brief No description provided. - * - * - * @return (callback): int64[]: No description available. - */ - inline plg::vector CallFuncInt64Vector(FuncInt64Vector func) { - using CallFuncInt64VectorFn = plg::vector (*)(FuncInt64Vector); - static CallFuncInt64VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt64Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt8Vector - * @param func (function): No description available. - * - * @return uint8[]: No description available. - * - * @callback FuncUInt8Vector - * @brief No description provided. - * - * - * @return (callback): uint8[]: No description available. - */ - inline plg::vector CallFuncUInt8Vector(FuncUInt8Vector func) { - using CallFuncUInt8VectorFn = plg::vector (*)(FuncUInt8Vector); - static CallFuncUInt8VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt8Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt16Vector - * @param func (function): No description available. - * - * @return uint16[]: No description available. - * - * @callback FuncUInt16Vector - * @brief No description provided. - * - * - * @return (callback): uint16[]: No description available. - */ - inline plg::vector CallFuncUInt16Vector(FuncUInt16Vector func) { - using CallFuncUInt16VectorFn = plg::vector (*)(FuncUInt16Vector); - static CallFuncUInt16VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt16Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt32Vector - * @param func (function): No description available. - * - * @return uint32[]: No description available. - * - * @callback FuncUInt32Vector - * @brief No description provided. - * - * - * @return (callback): uint32[]: No description available. - */ - inline plg::vector CallFuncUInt32Vector(FuncUInt32Vector func) { - using CallFuncUInt32VectorFn = plg::vector (*)(FuncUInt32Vector); - static CallFuncUInt32VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt32Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt64Vector - * @param func (function): No description available. - * - * @return uint64[]: No description available. - * - * @callback FuncUInt64Vector - * @brief No description provided. - * - * - * @return (callback): uint64[]: No description available. - */ - inline plg::vector CallFuncUInt64Vector(FuncUInt64Vector func) { - using CallFuncUInt64VectorFn = plg::vector (*)(FuncUInt64Vector); - static CallFuncUInt64VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt64Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncPtrVector - * @param func (function): No description available. - * - * @return ptr64[]: No description available. - * - * @callback FuncPtrVector - * @brief No description provided. - * - * - * @return (callback): ptr64[]: No description available. - */ - inline plg::vector CallFuncPtrVector(FuncPtrVector func) { - using CallFuncPtrVectorFn = plg::vector (*)(FuncPtrVector); - static CallFuncPtrVectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncPtrVector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncFloatVector - * @param func (function): No description available. - * - * @return float[]: No description available. - * - * @callback FuncFloatVector - * @brief No description provided. - * - * - * @return (callback): float[]: No description available. - */ - inline plg::vector CallFuncFloatVector(FuncFloatVector func) { - using CallFuncFloatVectorFn = plg::vector (*)(FuncFloatVector); - static CallFuncFloatVectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncFloatVector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncDoubleVector - * @param func (function): No description available. - * - * @return double[]: No description available. - * - * @callback FuncDoubleVector - * @brief No description provided. - * - * - * @return (callback): double[]: No description available. - */ - inline plg::vector CallFuncDoubleVector(FuncDoubleVector func) { - using CallFuncDoubleVectorFn = plg::vector (*)(FuncDoubleVector); - static CallFuncDoubleVectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncDoubleVector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncStringVector - * @param func (function): No description available. - * - * @return string[]: No description available. - * - * @callback FuncStringVector - * @brief No description provided. - * - * - * @return (callback): string[]: No description available. - */ - inline plg::vector CallFuncStringVector(FuncStringVector func) { - using CallFuncStringVectorFn = plg::vector (*)(FuncStringVector); - static CallFuncStringVectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncStringVector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncAnyVector - * @param func (function): No description available. - * - * @return any[]: No description available. - * - * @callback FuncAnyVector - * @brief No description provided. - * - * - * @return (callback): any[]: No description available. - */ - inline plg::vector CallFuncAnyVector(FuncAnyVector func) { - using CallFuncAnyVectorFn = plg::vector (*)(FuncAnyVector); - static CallFuncAnyVectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncAnyVector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec2Vector - * @param func (function): No description available. - * - * @return vec2[]: No description available. - * - * @callback FuncVec2Vector - * @brief No description provided. - * - * - * @return (callback): vec2[]: No description available. - */ - inline plg::vector CallFuncVec2Vector(FuncVec2Vector func) { - using CallFuncVec2VectorFn = plg::vector (*)(FuncVec2Vector); - static CallFuncVec2VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec2Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec3Vector - * @param func (function): No description available. - * - * @return vec3[]: No description available. - * - * @callback FuncVec3Vector - * @brief No description provided. - * - * - * @return (callback): vec3[]: No description available. - */ - inline plg::vector CallFuncVec3Vector(FuncVec3Vector func) { - using CallFuncVec3VectorFn = plg::vector (*)(FuncVec3Vector); - static CallFuncVec3VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec3Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec4Vector - * @param func (function): No description available. - * - * @return vec4[]: No description available. - * - * @callback FuncVec4Vector - * @brief No description provided. - * - * - * @return (callback): vec4[]: No description available. - */ - inline plg::vector CallFuncVec4Vector(FuncVec4Vector func) { - using CallFuncVec4VectorFn = plg::vector (*)(FuncVec4Vector); - static CallFuncVec4VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec4Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncMat4x4Vector - * @param func (function): No description available. - * - * @return mat4x4[]: No description available. - * - * @callback FuncMat4x4Vector - * @brief No description provided. - * - * - * @return (callback): mat4x4[]: No description available. - */ - inline plg::vector CallFuncMat4x4Vector(FuncMat4x4Vector func) { - using CallFuncMat4x4VectorFn = plg::vector (*)(FuncMat4x4Vector); - static CallFuncMat4x4VectorFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncMat4x4Vector", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec2 - * @param func (function): No description available. - * - * @return vec2: No description available. - * - * @callback FuncVec2 - * @brief No description provided. - * - * - * @return (callback): vec2: No description available. - */ - inline plg::vec2 CallFuncVec2(FuncVec2 func) { - using CallFuncVec2Fn = plg::vec2 (*)(FuncVec2); - static CallFuncVec2Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec2", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec3 - * @param func (function): No description available. - * - * @return vec3: No description available. - * - * @callback FuncVec3 - * @brief No description provided. - * - * - * @return (callback): vec3: No description available. - */ - inline plg::vec3 CallFuncVec3(FuncVec3 func) { - using CallFuncVec3Fn = plg::vec3 (*)(FuncVec3); - static CallFuncVec3Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec3", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec4 - * @param func (function): No description available. - * - * @return vec4: No description available. - * - * @callback FuncVec4 - * @brief No description provided. - * - * - * @return (callback): vec4: No description available. - */ - inline plg::vec4 CallFuncVec4(FuncVec4 func) { - using CallFuncVec4Fn = plg::vec4 (*)(FuncVec4); - static CallFuncVec4Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec4", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncMat4x4 - * @param func (function): No description available. - * - * @return mat4x4: No description available. - * - * @callback FuncMat4x4 - * @brief No description provided. - * - * - * @return (callback): mat4x4: No description available. - */ - inline plg::mat4x4 CallFuncMat4x4(FuncMat4x4 func) { - using CallFuncMat4x4Fn = plg::mat4x4 (*)(FuncMat4x4); - static CallFuncMat4x4Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncMat4x4", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc1 - * @param func (function): No description available. - * - * @return int32: No description available. - * - * @callback Func1 - * @brief No description provided. - * - * @param a (vec3): No description available. - * - * @return (callback): int32: No description available. - */ - inline int32_t CallFunc1(Func1 func) { - using CallFunc1Fn = int32_t (*)(Func1); - static CallFunc1Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc1", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc2 - * @param func (function): No description available. - * - * @return char8: No description available. - * - * @callback Func2 - * @brief No description provided. - * - * @param a (float): No description available. - * @param b (int64): No description available. - * - * @return (callback): char8: No description available. - */ - inline char CallFunc2(Func2 func) { - using CallFunc2Fn = char (*)(Func2); - static CallFunc2Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc2", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc3 - * @param func (function): No description available. - * - * @callback Func3 - * @brief No description provided. - * - * @param a (ptr64): No description available. - * @param b (vec4): No description available. - * @param c (string): No description available. - * - * @return (callback): void: No description available. - */ - inline void CallFunc3(Func3 func) { - using CallFunc3Fn = void (*)(Func3); - static CallFunc3Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc3", reinterpret_cast(&__func)); - __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc4 - * @param func (function): No description available. - * - * @return vec4: No description available. - * - * @callback Func4 - * @brief No description provided. - * - * @param a (bool): No description available. - * @param b (int32): No description available. - * @param c (char16): No description available. - * @param d (mat4x4): No description available. - * - * @return (callback): vec4: No description available. - */ - inline plg::vec4 CallFunc4(Func4 func) { - using CallFunc4Fn = plg::vec4 (*)(Func4); - static CallFunc4Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc4", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc5 - * @param func (function): No description available. - * - * @return bool: No description available. - * - * @callback Func5 - * @brief No description provided. - * - * @param a (int8): No description available. - * @param b (vec2): No description available. - * @param c (ptr64): No description available. - * @param d (double): No description available. - * @param e (uint64[]): No description available. - * - * @return (callback): bool: No description available. - */ - inline bool CallFunc5(Func5 func) { - using CallFunc5Fn = bool (*)(Func5); - static CallFunc5Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc5", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc6 - * @param func (function): No description available. - * - * @return int64: No description available. - * - * @callback Func6 - * @brief No description provided. - * - * @param a (string): No description available. - * @param b (float): No description available. - * @param c (float[]): No description available. - * @param d (int16): No description available. - * @param e (uint8[]): No description available. - * @param f (ptr64): No description available. - * - * @return (callback): int64: No description available. - */ - inline int64_t CallFunc6(Func6 func) { - using CallFunc6Fn = int64_t (*)(Func6); - static CallFunc6Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc6", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc7 - * @param func (function): No description available. - * - * @return double: No description available. - * - * @callback Func7 - * @brief No description provided. - * - * @param vecC (char8[]): No description available. - * @param u16 (uint16): No description available. - * @param ch16 (char16): No description available. - * @param vecU32 (uint32[]): No description available. - * @param vec4 (vec4): No description available. - * @param b (bool): No description available. - * @param u64 (uint64): No description available. - * - * @return (callback): double: No description available. - */ - inline double CallFunc7(Func7 func) { - using CallFunc7Fn = double (*)(Func7); - static CallFunc7Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc7", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc8 - * @param func (function): No description available. - * - * @return mat4x4: No description available. - * - * @callback Func8 - * @brief No description provided. - * - * @param vec3 (vec3): No description available. - * @param vecU32 (uint32[]): No description available. - * @param i16 (int16): No description available. - * @param b (bool): No description available. - * @param vec4 (vec4): No description available. - * @param vecC16 (char16[]): No description available. - * @param ch16 (char16): No description available. - * @param i32 (int32): No description available. - * - * @return (callback): mat4x4: No description available. - */ - inline plg::mat4x4 CallFunc8(Func8 func) { - using CallFunc8Fn = plg::mat4x4 (*)(Func8); - static CallFunc8Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc8", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc9 - * @param func (function): No description available. - * - * @callback Func9 - * @brief No description provided. - * - * @param f (float): No description available. - * @param vec2 (vec2): No description available. - * @param vecI8 (int8[]): No description available. - * @param u64 (uint64): No description available. - * @param b (bool): No description available. - * @param str (string): No description available. - * @param vec4 (vec4): No description available. - * @param i16 (int16): No description available. - * @param ptr (ptr64): No description available. - * - * @return (callback): void: No description available. - */ - inline void CallFunc9(Func9 func) { - using CallFunc9Fn = void (*)(Func9); - static CallFunc9Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc9", reinterpret_cast(&__func)); - __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc10 - * @param func (function): No description available. - * - * @return uint32: No description available. - * - * @callback Func10 - * @brief No description provided. - * - * @param vec4 (vec4): No description available. - * @param mat (mat4x4): No description available. - * @param vecU32 (uint32[]): No description available. - * @param u64 (uint64): No description available. - * @param vecC (char8[]): No description available. - * @param i32 (int32): No description available. - * @param b (bool): No description available. - * @param vec2 (vec2): No description available. - * @param i64 (int64): No description available. - * @param d (double): No description available. - * - * @return (callback): uint32: No description available. - */ - inline uint32_t CallFunc10(Func10 func) { - using CallFunc10Fn = uint32_t (*)(Func10); - static CallFunc10Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc10", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc11 - * @param func (function): No description available. - * - * @return ptr64: No description available. - * - * @callback Func11 - * @brief No description provided. - * - * @param vecB (bool[]): No description available. - * @param ch16 (char16): No description available. - * @param u8 (uint8): No description available. - * @param d (double): No description available. - * @param vec3 (vec3): No description available. - * @param vecI8 (int8[]): No description available. - * @param i64 (int64): No description available. - * @param u16 (uint16): No description available. - * @param f (float): No description available. - * @param vec2 (vec2): No description available. - * @param u32 (uint32): No description available. - * - * @return (callback): ptr64: No description available. - */ - inline void* CallFunc11(Func11 func) { - using CallFunc11Fn = void* (*)(Func11); - static CallFunc11Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc11", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc12 - * @param func (function): No description available. - * - * @return bool: No description available. - * - * @callback Func12 - * @brief No description provided. - * - * @param ptr (ptr64): No description available. - * @param vecD (double[]): No description available. - * @param u32 (uint32): No description available. - * @param d (double): No description available. - * @param b (bool): No description available. - * @param i32 (int32): No description available. - * @param i8 (int8): No description available. - * @param u64 (uint64): No description available. - * @param f (float): No description available. - * @param vecPtr (ptr64[]): No description available. - * @param i64 (int64): No description available. - * @param ch (char8): No description available. - * - * @return (callback): bool: No description available. - */ - inline bool CallFunc12(Func12 func) { - using CallFunc12Fn = bool (*)(Func12); - static CallFunc12Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc12", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc13 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func13 - * @brief No description provided. - * - * @param i64 (int64): No description available. - * @param vecC (char8[]): No description available. - * @param d (uint16): No description available. - * @param f (float): No description available. - * @param b (bool[]): No description available. - * @param vec4 (vec4): No description available. - * @param str (string): No description available. - * @param int32 (int32): No description available. - * @param vec3 (vec3): No description available. - * @param ptr (ptr64): No description available. - * @param vec2 (vec2): No description available. - * @param arr (uint8[]): No description available. - * @param i16 (int16): No description available. - * - * @return (callback): string: No description available. - */ - inline plg::string CallFunc13(Func13 func) { - using CallFunc13Fn = plg::string (*)(Func13); - static CallFunc13Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc13", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc14 - * @param func (function): No description available. - * - * @return string[]: No description available. - * - * @callback Func14 - * @brief No description provided. - * - * @param vecC (char8[]): No description available. - * @param vecU32 (uint32[]): No description available. - * @param mat (mat4x4): No description available. - * @param b (bool): No description available. - * @param ch16 (char16): No description available. - * @param i32 (int32): No description available. - * @param vecF (float[]): No description available. - * @param u16 (uint16): No description available. - * @param vecU8 (uint8[]): No description available. - * @param i8 (int8): No description available. - * @param vec3 (vec3): No description available. - * @param vec4 (vec4): No description available. - * @param d (double): No description available. - * @param ptr (ptr64): No description available. - * - * @return (callback): string[]: No description available. - */ - inline plg::vector CallFunc14(Func14 func) { - using CallFunc14Fn = plg::vector (*)(Func14); - static CallFunc14Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc14", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc15 - * @param func (function): No description available. - * - * @return int16: No description available. - * - * @callback Func15 - * @brief No description provided. - * - * @param vecI16 (int16[]): No description available. - * @param mat (mat4x4): No description available. - * @param vec4 (vec4): No description available. - * @param ptr (ptr64): No description available. - * @param u64 (uint64): No description available. - * @param vecU32 (uint32[]): No description available. - * @param b (bool): No description available. - * @param f (float): No description available. - * @param vecC16 (char16[]): No description available. - * @param u8 (uint8): No description available. - * @param i32 (int32): No description available. - * @param vec2 (vec2): No description available. - * @param u16 (uint16): No description available. - * @param d (double): No description available. - * @param vecU8 (uint8[]): No description available. - * - * @return (callback): int16: No description available. - */ - inline int16_t CallFunc15(Func15 func) { - using CallFunc15Fn = int16_t (*)(Func15); - static CallFunc15Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc15", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc16 - * @param func (function): No description available. - * - * @return ptr64: No description available. - * - * @callback Func16 - * @brief No description provided. - * - * @param vecB (bool[]): No description available. - * @param i16 (int16): No description available. - * @param vecI8 (int8[]): No description available. - * @param vec4 (vec4): No description available. - * @param mat (mat4x4): No description available. - * @param vec2 (vec2): No description available. - * @param vecU64 (uint64[]): No description available. - * @param vecC (char8[]): No description available. - * @param str (string): No description available. - * @param i64 (int64): No description available. - * @param vecU32 (uint32[]): No description available. - * @param vec3 (vec3): No description available. - * @param f (float): No description available. - * @param d (double): No description available. - * @param i8 (int8): No description available. - * @param u16 (uint16): No description available. - * - * @return (callback): ptr64: No description available. - */ - inline void* CallFunc16(Func16 func) { - using CallFunc16Fn = void* (*)(Func16); - static CallFunc16Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc16", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc17 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func17 - * @brief No description provided. - * - * @param i32 (int32): No description available. - * - * @return (callback): void: No description available. - */ - inline plg::string CallFunc17(Func17 func) { - using CallFunc17Fn = plg::string (*)(Func17); - static CallFunc17Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc17", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc18 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func18 - * @brief No description provided. - * - * @param i8 (int8): No description available. - * @param i16 (int16): No description available. - * - * @return (callback): vec2: No description available. - */ - inline plg::string CallFunc18(Func18 func) { - using CallFunc18Fn = plg::string (*)(Func18); - static CallFunc18Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc18", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc19 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func19 - * @brief No description provided. - * - * @param u32 (uint32): No description available. - * @param vec3 (vec3): No description available. - * @param vecU32 (uint32[]): No description available. - * - * @return (callback): void: No description available. - */ - inline plg::string CallFunc19(Func19 func) { - using CallFunc19Fn = plg::string (*)(Func19); - static CallFunc19Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc19", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc20 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func20 - * @brief No description provided. - * - * @param ch16 (char16): No description available. - * @param vec4 (vec4): No description available. - * @param vecU64 (uint64[]): No description available. - * @param ch (char8): No description available. - * - * @return (callback): int32: No description available. - */ - inline plg::string CallFunc20(Func20 func) { - using CallFunc20Fn = plg::string (*)(Func20); - static CallFunc20Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc20", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc21 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func21 - * @brief No description provided. - * - * @param mat (mat4x4): No description available. - * @param vecI32 (int32[]): No description available. - * @param vec2 (vec2): No description available. - * @param b (bool): No description available. - * @param extraParam (double): No description available. - * - * @return (callback): float: No description available. - */ - inline plg::string CallFunc21(Func21 func) { - using CallFunc21Fn = plg::string (*)(Func21); - static CallFunc21Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc21", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc22 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func22 - * @brief No description provided. - * - * @param ptr64Ref (ptr64): No description available. - * @param uint32Ref (uint32): No description available. - * @param vectorDoubleRef (double[]): No description available. - * @param int16Ref (int16): No description available. - * @param plgStringRef (string): No description available. - * @param plgVector4Ref (vec4): No description available. - * - * @return (callback): uint64: No description available. - */ - inline plg::string CallFunc22(Func22 func) { - using CallFunc22Fn = plg::string (*)(Func22); - static CallFunc22Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc22", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc23 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func23 - * @brief No description provided. - * - * @param uint64Ref (uint64): No description available. - * @param plgVector2Ref (vec2): No description available. - * @param vectorInt16Ref (int16[]): No description available. - * @param char16Ref (char16): No description available. - * @param floatRef (float): No description available. - * @param int8Ref (int8): No description available. - * @param vectorUInt8Ref (uint8[]): No description available. - * - * @return (callback): void: No description available. - */ - inline plg::string CallFunc23(Func23 func) { - using CallFunc23Fn = plg::string (*)(Func23); - static CallFunc23Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc23", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc24 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func24 - * @brief No description provided. - * - * @param vectorCharRef (char8[]): No description available. - * @param int64Ref (int64): No description available. - * @param vectorUInt8Ref (uint8[]): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param uint64Ref (uint64): No description available. - * @param vectorptr64Ref (ptr64[]): No description available. - * @param doubleRef (double): No description available. - * @param vectorptr64Ref (ptr64[]): No description available. - * - * @return (callback): mat4x4: No description available. - */ - inline plg::string CallFunc24(Func24 func) { - using CallFunc24Fn = plg::string (*)(Func24); - static CallFunc24Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc24", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc25 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func25 - * @brief No description provided. - * - * @param int32Ref (int32): No description available. - * @param vectorptr64Ref (ptr64[]): No description available. - * @param boolRef (bool): No description available. - * @param uint8Ref (uint8): No description available. - * @param plgStringRef (string): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param int64Ref (int64): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param uint16Ref (uint16): No description available. - * - * @return (callback): double: No description available. - */ - inline plg::string CallFunc25(Func25 func) { - using CallFunc25Fn = plg::string (*)(Func25); - static CallFunc25Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc25", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc26 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func26 - * @brief No description provided. - * - * @param char16Ref (char16): No description available. - * @param plgVector2Ref (vec2): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param vectorFloatRef (float[]): No description available. - * @param int16Ref (int16): No description available. - * @param uint64Ref (uint64): No description available. - * @param uint32Ref (uint32): No description available. - * @param vectorUInt16Ref (uint16[]): No description available. - * @param ptr64Ref (ptr64): No description available. - * @param boolRef (bool): No description available. - * - * @return (callback): char8: No description available. - */ - inline plg::string CallFunc26(Func26 func) { - using CallFunc26Fn = plg::string (*)(Func26); - static CallFunc26Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc26", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc27 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func27 - * @brief No description provided. - * - * @param floatRef (float): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param ptr64Ref (ptr64): No description available. - * @param plgVector2Ref (vec2): No description available. - * @param vectorInt16Ref (int16[]): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param boolRef (bool): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param int8Ref (int8): No description available. - * @param int32Ref (int32): No description available. - * @param vectorUInt8Ref (uint8[]): No description available. - * - * @return (callback): uint8: No description available. - */ - inline plg::string CallFunc27(Func27 func) { - using CallFunc27Fn = plg::string (*)(Func27); - static CallFunc27Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc27", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc28 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func28 - * @brief No description provided. - * - * @param ptr64Ref (ptr64): No description available. - * @param uint16Ref (uint16): No description available. - * @param vectorUInt32Ref (uint32[]): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param floatRef (float): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param plgStringRef (string): No description available. - * @param vectorUInt64Ref (uint64[]): No description available. - * @param int64Ref (int64): No description available. - * @param boolRef (bool): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param vectorFloatRef (float[]): No description available. - * - * @return (callback): string: No description available. - */ - inline plg::string CallFunc28(Func28 func) { - using CallFunc28Fn = plg::string (*)(Func28); - static CallFunc28Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc28", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc29 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func29 - * @brief No description provided. - * - * @param plgVector4Ref (vec4): No description available. - * @param int32Ref (int32): No description available. - * @param vectorInt8Ref (int8[]): No description available. - * @param doubleRef (double): No description available. - * @param boolRef (bool): No description available. - * @param int8Ref (int8): No description available. - * @param vectorUInt16Ref (uint16[]): No description available. - * @param floatRef (float): No description available. - * @param plgStringRef (string): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param uint64Ref (uint64): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param vectorInt64Ref (int64[]): No description available. - * - * @return (callback): string[]: No description available. - */ - inline plg::string CallFunc29(Func29 func) { - using CallFunc29Fn = plg::string (*)(Func29); - static CallFunc29Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc29", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc30 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func30 - * @brief No description provided. - * - * @param ptr64Ref (ptr64): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param int64Ref (int64): No description available. - * @param vectorUInt32Ref (uint32[]): No description available. - * @param boolRef (bool): No description available. - * @param plgStringRef (string): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param vectorUInt8Ref (uint8[]): No description available. - * @param floatRef (float): No description available. - * @param plgVector2Ref (vec2): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param int8Ref (int8): No description available. - * @param vectorFloatRef (float[]): No description available. - * @param doubleRef (double): No description available. - * - * @return (callback): int32: No description available. - */ - inline plg::string CallFunc30(Func30 func) { - using CallFunc30Fn = plg::string (*)(Func30); - static CallFunc30Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc30", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc31 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func31 - * @brief No description provided. - * - * @param charRef (char8): No description available. - * @param uint32Ref (uint32): No description available. - * @param vectorUInt64Ref (uint64[]): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param plgStringRef (string): No description available. - * @param boolRef (bool): No description available. - * @param int64Ref (int64): No description available. - * @param vec2Ref (vec2): No description available. - * @param int8Ref (int8): No description available. - * @param uint16Ref (uint16): No description available. - * @param vectorInt16Ref (int16[]): No description available. - * @param mat4x4Ref (mat4x4): No description available. - * @param vec3Ref (vec3): No description available. - * @param floatRef (float): No description available. - * @param vectorDoubleRef (double[]): No description available. - * - * @return (callback): vec3: No description available. - */ - inline plg::string CallFunc31(Func31 func) { - using CallFunc31Fn = plg::string (*)(Func31); - static CallFunc31Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc31", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc32 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func32 - * @brief No description provided. - * - * @param p1 (int32): No description available. - * @param p2 (uint16): No description available. - * @param p3 (int8[]): No description available. - * @param p4 (vec4): No description available. - * @param p5 (ptr64): No description available. - * @param p6 (uint32[]): No description available. - * @param p7 (mat4x4): No description available. - * @param p8 (uint64): No description available. - * @param p9 (string): No description available. - * @param p10 (int64): No description available. - * @param p11 (vec2): No description available. - * @param p12 (int8[]): No description available. - * @param p13 (bool): No description available. - * @param p14 (vec3): No description available. - * @param p14 (uint8): No description available. - * @param p15 (char16[]): No description available. - * - * @return (callback): double: No description available. - */ - inline plg::string CallFunc32(Func32 func) { - using CallFunc32Fn = plg::string (*)(Func32); - static CallFunc32Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc32", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc33 - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func33 - * @brief No description provided. - * - * @param variant (any): No description available. - * - * @return (callback): void: No description available. - */ - inline plg::string CallFunc33(Func33 func) { - using CallFunc33Fn = plg::string (*)(Func33); - static CallFunc33Fn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc33", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncEnum - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback FuncEnum - * @brief No description provided. - * - * @param p1 (int32): No description available. - * @param p2 (int32[]): No description available. - * - * @return (callback): int32[]: No description available. - */ - inline plg::string CallFuncEnum(FuncEnum func) { - using CallFuncEnumFn = plg::string (*)(FuncEnum); - static CallFuncEnumFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncEnum", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function ReverseCall - * @param test (string): No description available. - */ - inline void ReverseCall(const plg::string& test) { - using ReverseCallFn = void (*)(const plg::string&); - static ReverseCallFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ReverseCall", reinterpret_cast(&__func)); - __func(test); - } - + enum class Example : int32_t { + First = 1, + Second = 2, + Third = 3, + Forth = 4, + }; + + using NoParamReturnFunctionFunc = void (*)(); + using FuncVoid = void (*)(); + using FuncBool = bool (*)(); + using FuncChar8 = char (*)(); + using FuncChar16 = char16_t (*)(); + using FuncInt8 = int8_t (*)(); + using FuncInt16 = int16_t (*)(); + using FuncInt32 = int32_t (*)(); + using FuncInt64 = int64_t (*)(); + using FuncUInt8 = uint8_t (*)(); + using FuncUInt16 = uint16_t (*)(); + using FuncUInt32 = uint32_t (*)(); + using FuncUInt64 = uint64_t (*)(); + using FuncPtr = void* (*)(); + using FuncFloat = float (*)(); + using FuncDouble = double (*)(); + using FuncString = plg::string (*)(); + using FuncAny = plg::any (*)(); + using FuncFunction = void* (*)(); + using FuncBoolVector = plg::vector (*)(); + using FuncChar8Vector = plg::vector (*)(); + using FuncChar16Vector = plg::vector (*)(); + using FuncInt8Vector = plg::vector (*)(); + using FuncInt16Vector = plg::vector (*)(); + using FuncInt32Vector = plg::vector (*)(); + using FuncInt64Vector = plg::vector (*)(); + using FuncUInt8Vector = plg::vector (*)(); + using FuncUInt16Vector = plg::vector (*)(); + using FuncUInt32Vector = plg::vector (*)(); + using FuncUInt64Vector = plg::vector (*)(); + using FuncPtrVector = plg::vector (*)(); + using FuncFloatVector = plg::vector (*)(); + using FuncDoubleVector = plg::vector (*)(); + using FuncStringVector = plg::vector (*)(); + using FuncAnyVector = plg::vector (*)(); + using FuncVec2Vector = plg::vector (*)(); + using FuncVec3Vector = plg::vector (*)(); + using FuncVec4Vector = plg::vector (*)(); + using FuncMat4x4Vector = plg::vector (*)(); + using FuncVec2 = plg::vec2 (*)(); + using FuncVec3 = plg::vec3 (*)(); + using FuncVec4 = plg::vec4 (*)(); + using FuncMat4x4 = plg::mat4x4 (*)(); + using Func1 = int32_t (*)(const plg::vec3 &); + using Func2 = char (*)(float, int64_t); + using Func3 = void (*)(void *, const plg::vec4 &, const plg::string &); + using Func4 = plg::vec4 (*)(bool, int32_t, char16_t, const plg::mat4x4 &); + using Func5 = bool (*)(int8_t, const plg::vec2 &, void *, double, const plg::vector &); + using Func6 = int64_t (*)(const plg::string &, float, const plg::vector &, int16_t, + const plg::vector &, void *); + using Func7 = double (*)(const plg::vector &, uint16_t, char16_t, const plg::vector &, + const plg::vec4 &, bool, uint64_t); + using Func8 = plg::mat4x4 (*)(const plg::vec3 &, const plg::vector &, int16_t, bool, const plg::vec4 &, + const plg::vector &, char16_t, int32_t); + using Func9 = void (*)(float, const plg::vec2 &, const plg::vector &, uint64_t, bool, const plg::string &, + const plg::vec4 &, int16_t, void *); + using Func10 = uint32_t (*)(const plg::vec4 &, const plg::mat4x4 &, const plg::vector &, uint64_t, + const plg::vector &, int32_t, bool, const plg::vec2 &, int64_t, double); + using Func11 = void* (*)(const plg::vector &, char16_t, uint8_t, double, const plg::vec3 &, + const plg::vector &, int64_t, uint16_t, float, const plg::vec2 &, uint32_t); + using Func12 = bool (*)(void *, const plg::vector &, uint32_t, double, bool, int32_t, int8_t, uint64_t, + float, const plg::vector &, int64_t, char); + using Func13 = plg::string (*)(int64_t, const plg::vector &, uint16_t, float, const plg::vector &, + const plg::vec4 &, const plg::string &, int32_t, const plg::vec3 &, void *, + const plg::vec2 &, const plg::vector &, int16_t); + using Func14 = plg::vector (*)(const plg::vector &, const plg::vector &, + const plg::mat4x4 &, bool, char16_t, int32_t, + const plg::vector &, uint16_t, const plg::vector &, + int8_t, const plg::vec3 &, const plg::vec4 &, double, void *); + using Func15 = int16_t (*)(const plg::vector &, const plg::mat4x4 &, const plg::vec4 &, void *, uint64_t, + const plg::vector &, bool, float, const plg::vector &, uint8_t, + int32_t, const plg::vec2 &, uint16_t, double, const plg::vector &); + using Func16 = void* (*)(const plg::vector &, int16_t, const plg::vector &, const plg::vec4 &, + const plg::mat4x4 &, const plg::vec2 &, const plg::vector &, + const plg::vector &, const plg::string &, int64_t, const plg::vector &, + const plg::vec3 &, float, double, int8_t, uint16_t); + using Func17 = void (*)(int32_t &); + using Func18 = plg::vec2 (*)(int8_t &, int16_t &); + using Func19 = void (*)(uint32_t &, plg::vec3 &, plg::vector &); + using Func20 = int32_t (*)(char16_t &, plg::vec4 &, plg::vector &, char &); + using Func21 = float (*)(plg::mat4x4 &, plg::vector &, plg::vec2 &, bool &, double &); + using Func22 = uint64_t (*)(void *&, uint32_t &, plg::vector &, int16_t &, plg::string &, plg::vec4 &); + using Func23 = void (*)(uint64_t &, plg::vec2 &, plg::vector &, char16_t &, float &, int8_t &, + plg::vector &); + using Func24 = plg::mat4x4 (*)(plg::vector &, int64_t &, plg::vector &, plg::vec4 &, uint64_t &, + plg::vector &, double &, plg::vector &); + using Func25 = double (*)(int32_t &, plg::vector &, bool &, uint8_t &, plg::string &, plg::vec3 &, + int64_t &, plg::vec4 &, uint16_t &); + using Func26 = char (*)(char16_t &, plg::vec2 &, plg::mat4x4 &, plg::vector &, int16_t &, uint64_t &, + uint32_t &, plg::vector &, void *&, bool &); + using Func27 = uint8_t (*)(float &, plg::vec3 &, void *&, plg::vec2 &, plg::vector &, plg::mat4x4 &, + bool &, plg::vec4 &, int8_t &, int32_t &, plg::vector &); + using Func28 = plg::string (*)(void *&, uint16_t &, plg::vector &, plg::mat4x4 &, float &, plg::vec4 &, + plg::string &, plg::vector &, int64_t &, bool &, plg::vec3 &, + plg::vector &); + using Func29 = plg::vector (*)(plg::vec4 &, int32_t &, plg::vector &, double &, bool &, + int8_t &, plg::vector &, float &, plg::string &, + plg::mat4x4 &, uint64_t &, plg::vec3 &, plg::vector &); + using Func30 = int32_t (*)(void *&, plg::vec4 &, int64_t &, plg::vector &, bool &, plg::string &, + plg::vec3 &, plg::vector &, float &, plg::vec2 &, plg::mat4x4 &, int8_t &, + plg::vector &, double &); + using Func31 = plg::vec3 (*)(char &, uint32_t &, plg::vector &, plg::vec4 &, plg::string &, bool &, + int64_t &, plg::vec2 &, int8_t &, uint16_t &, plg::vector &, plg::mat4x4 &, + plg::vec3 &, float &, plg::vector &); + using Func32 = double (*)(int32_t &, uint16_t &, plg::vector &, plg::vec4 &, void *&, + plg::vector &, plg::mat4x4 &, uint64_t &, plg::string &, int64_t &, plg::vec2 &, + plg::vector &, bool &, plg::vec3 &, uint8_t &, plg::vector &); + using Func33 = void (*)(plg::any &); + using FuncEnum = plg::vector (*)(Example, plg::vector &); + + /** + * @brief No description provided. + * + * @function NoParamReturnVoid + */ + inline void NoParamReturnVoid() { + using NoParamReturnVoidFn = void (*)(); + static NoParamReturnVoidFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnVoid", + reinterpret_cast(&__func)); + __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnBool + * + * @return bool: No description available. + */ + inline bool NoParamReturnBool() { + using NoParamReturnBoolFn = bool (*)(); + static NoParamReturnBoolFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnBool", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnChar8 + * + * @return char8: No description available. + */ + inline char NoParamReturnChar8() { + using NoParamReturnChar8Fn = char (*)(); + static NoParamReturnChar8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnChar8", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnChar16 + * + * @return char16: No description available. + */ + inline char16_t NoParamReturnChar16() { + using NoParamReturnChar16Fn = char16_t (*)(); + static NoParamReturnChar16Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnChar16", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnInt8 + * + * @return int8: No description available. + */ + inline int8_t NoParamReturnInt8() { + using NoParamReturnInt8Fn = int8_t (*)(); + static NoParamReturnInt8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnInt8", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnInt16 + * + * @return int16: No description available. + */ + inline int16_t NoParamReturnInt16() { + using NoParamReturnInt16Fn = int16_t (*)(); + static NoParamReturnInt16Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnInt16", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnInt32 + * + * @return int32: No description available. + */ + inline int32_t NoParamReturnInt32() { + using NoParamReturnInt32Fn = int32_t (*)(); + static NoParamReturnInt32Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnInt32", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnInt64 + * + * @return int64: No description available. + */ + inline int64_t NoParamReturnInt64() { + using NoParamReturnInt64Fn = int64_t (*)(); + static NoParamReturnInt64Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnInt64", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnUInt8 + * + * @return uint8: No description available. + */ + inline uint8_t NoParamReturnUInt8() { + using NoParamReturnUInt8Fn = uint8_t (*)(); + static NoParamReturnUInt8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnUInt8", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnUInt16 + * + * @return uint16: No description available. + */ + inline uint16_t NoParamReturnUInt16() { + using NoParamReturnUInt16Fn = uint16_t (*)(); + static NoParamReturnUInt16Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnUInt16", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnUInt32 + * + * @return uint32: No description available. + */ + inline uint32_t NoParamReturnUInt32() { + using NoParamReturnUInt32Fn = uint32_t (*)(); + static NoParamReturnUInt32Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnUInt32", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnUInt64 + * + * @return uint64: No description available. + */ + inline uint64_t NoParamReturnUInt64() { + using NoParamReturnUInt64Fn = uint64_t (*)(); + static NoParamReturnUInt64Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnUInt64", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnPointer + * + * @return ptr64: No description available. + */ + inline void *NoParamReturnPointer() { + using NoParamReturnPointerFn = void* (*)(); + static NoParamReturnPointerFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnPointer", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnFloat + * + * @return float: No description available. + */ + inline float NoParamReturnFloat() { + using NoParamReturnFloatFn = float (*)(); + static NoParamReturnFloatFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnFloat", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnDouble + * + * @return double: No description available. + */ + inline double NoParamReturnDouble() { + using NoParamReturnDoubleFn = double (*)(); + static NoParamReturnDoubleFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnDouble", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnFunction + * + * @return function: No description available. + */ + inline NoParamReturnFunctionFunc NoParamReturnFunction() { + using NoParamReturnFunctionFn = NoParamReturnFunctionFunc (*)(); + static NoParamReturnFunctionFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnFunction", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnString + * + * @return string: No description available. + */ + inline plg::string NoParamReturnString() { + using NoParamReturnStringFn = plg::string (*)(); + static NoParamReturnStringFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnString", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnAny + * + * @return any: No description available. + */ + inline plg::any NoParamReturnAny() { + using NoParamReturnAnyFn = plg::any (*)(); + static NoParamReturnAnyFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnAny", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayBool + * + * @return bool[]: No description available. + */ + inline plg::vector NoParamReturnArrayBool() { + using NoParamReturnArrayBoolFn = plg::vector (*)(); + static NoParamReturnArrayBoolFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayBool", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayChar8 + * + * @return char8[]: No description available. + */ + inline plg::vector NoParamReturnArrayChar8() { + using NoParamReturnArrayChar8Fn = plg::vector (*)(); + static NoParamReturnArrayChar8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayChar8", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayChar16 + * + * @return char16[]: No description available. + */ + inline plg::vector NoParamReturnArrayChar16() { + using NoParamReturnArrayChar16Fn = plg::vector (*)(); + static NoParamReturnArrayChar16Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayChar16", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayInt8 + * + * @return int8[]: No description available. + */ + inline plg::vector NoParamReturnArrayInt8() { + using NoParamReturnArrayInt8Fn = plg::vector (*)(); + static NoParamReturnArrayInt8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayInt8", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayInt16 + * + * @return int16[]: No description available. + */ + inline plg::vector NoParamReturnArrayInt16() { + using NoParamReturnArrayInt16Fn = plg::vector (*)(); + static NoParamReturnArrayInt16Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayInt16", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayInt32 + * + * @return int32[]: No description available. + */ + inline plg::vector NoParamReturnArrayInt32() { + using NoParamReturnArrayInt32Fn = plg::vector (*)(); + static NoParamReturnArrayInt32Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayInt32", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayInt64 + * + * @return int64[]: No description available. + */ + inline plg::vector NoParamReturnArrayInt64() { + using NoParamReturnArrayInt64Fn = plg::vector (*)(); + static NoParamReturnArrayInt64Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayInt64", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayUInt8 + * + * @return uint8[]: No description available. + */ + inline plg::vector NoParamReturnArrayUInt8() { + using NoParamReturnArrayUInt8Fn = plg::vector (*)(); + static NoParamReturnArrayUInt8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayUInt8", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayUInt16 + * + * @return uint16[]: No description available. + */ + inline plg::vector NoParamReturnArrayUInt16() { + using NoParamReturnArrayUInt16Fn = plg::vector (*)(); + static NoParamReturnArrayUInt16Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayUInt16", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayUInt32 + * + * @return uint32[]: No description available. + */ + inline plg::vector NoParamReturnArrayUInt32() { + using NoParamReturnArrayUInt32Fn = plg::vector (*)(); + static NoParamReturnArrayUInt32Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayUInt32", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayUInt64 + * + * @return uint64[]: No description available. + */ + inline plg::vector NoParamReturnArrayUInt64() { + using NoParamReturnArrayUInt64Fn = plg::vector (*)(); + static NoParamReturnArrayUInt64Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayUInt64", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayPointer + * + * @return ptr64[]: No description available. + */ + inline plg::vector NoParamReturnArrayPointer() { + using NoParamReturnArrayPointerFn = plg::vector (*)(); + static NoParamReturnArrayPointerFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayPointer", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayFloat + * + * @return float[]: No description available. + */ + inline plg::vector NoParamReturnArrayFloat() { + using NoParamReturnArrayFloatFn = plg::vector (*)(); + static NoParamReturnArrayFloatFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayFloat", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayDouble + * + * @return double[]: No description available. + */ + inline plg::vector NoParamReturnArrayDouble() { + using NoParamReturnArrayDoubleFn = plg::vector (*)(); + static NoParamReturnArrayDoubleFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayDouble", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayString + * + * @return string[]: No description available. + */ + inline plg::vector NoParamReturnArrayString() { + using NoParamReturnArrayStringFn = plg::vector (*)(); + static NoParamReturnArrayStringFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayString", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayAny + * + * @return any[]: No description available. + */ + inline plg::vector NoParamReturnArrayAny() { + using NoParamReturnArrayAnyFn = plg::vector (*)(); + static NoParamReturnArrayAnyFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayAny", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayVector2 + * + * @return vec2[]: No description available. + */ + inline plg::vector NoParamReturnArrayVector2() { + using NoParamReturnArrayVector2Fn = plg::vector (*)(); + static NoParamReturnArrayVector2Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayVector2", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayVector3 + * + * @return vec3[]: No description available. + */ + inline plg::vector NoParamReturnArrayVector3() { + using NoParamReturnArrayVector3Fn = plg::vector (*)(); + static NoParamReturnArrayVector3Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayVector3", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayVector4 + * + * @return vec4[]: No description available. + */ + inline plg::vector NoParamReturnArrayVector4() { + using NoParamReturnArrayVector4Fn = plg::vector (*)(); + static NoParamReturnArrayVector4Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayVector4", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayMatrix4x4 + * + * @return mat4x4[]: No description available. + */ + inline plg::vector NoParamReturnArrayMatrix4x4() { + using NoParamReturnArrayMatrix4x4Fn = plg::vector (*)(); + static NoParamReturnArrayMatrix4x4Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnArrayMatrix4x4", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnVector2 + * + * @return vec2: No description available. + */ + inline plg::vec2 NoParamReturnVector2() { + using NoParamReturnVector2Fn = plg::vec2 (*)(); + static NoParamReturnVector2Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnVector2", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnVector3 + * + * @return vec3: No description available. + */ + inline plg::vec3 NoParamReturnVector3() { + using NoParamReturnVector3Fn = plg::vec3 (*)(); + static NoParamReturnVector3Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnVector3", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnVector4 + * + * @return vec4: No description available. + */ + inline plg::vec4 NoParamReturnVector4() { + using NoParamReturnVector4Fn = plg::vec4 (*)(); + static NoParamReturnVector4Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnVector4", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnMatrix4x4 + * + * @return mat4x4: No description available. + */ + inline plg::mat4x4 NoParamReturnMatrix4x4() { + using NoParamReturnMatrix4x4Fn = plg::mat4x4 (*)(); + static NoParamReturnMatrix4x4Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.NoParamReturnMatrix4x4", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function Param1 + * @param a (int32): No description available. + */ + inline void Param1(int32_t a) { + using Param1Fn = void (*)(int32_t); + static Param1Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param1", reinterpret_cast(&__func)); + __func(a); + } + + /** + * @brief No description provided. + * + * @function Param2 + * @param a (int32): No description available. + * @param b (float): No description available. + */ + inline void Param2(int32_t a, float b) { + using Param2Fn = void (*)(int32_t, float); + static Param2Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param2", reinterpret_cast(&__func)); + __func(a, b); + } + + /** + * @brief No description provided. + * + * @function Param3 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + */ + inline void Param3(int32_t a, float b, double c) { + using Param3Fn = void (*)(int32_t, float, double); + static Param3Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param3", reinterpret_cast(&__func)); + __func(a, b, c); + } + + /** + * @brief No description provided. + * + * @function Param4 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + */ + inline void Param4(int32_t a, float b, double c, const plg::vec4 &d) { + using Param4Fn = void (*)(int32_t, float, double, const plg::vec4 &); + static Param4Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param4", reinterpret_cast(&__func)); + __func(a, b, c, d); + } + + /** + * @brief No description provided. + * + * @function Param5 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + */ + inline void Param5(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e) { + using Param5Fn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &); + static Param5Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param5", reinterpret_cast(&__func)); + __func(a, b, c, d, e); + } + + /** + * @brief No description provided. + * + * @function Param6 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + */ + inline void Param6(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f) { + using Param6Fn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, char); + static Param6Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param6", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f); + } + + /** + * @brief No description provided. + * + * @function Param7 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + */ + inline void Param7(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g) { + using Param7Fn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, char, + const plg::string &); + static Param7Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param7", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g); + } + + /** + * @brief No description provided. + * + * @function Param8 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + */ + inline void Param8(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h) { + using Param8Fn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, char, + const plg::string &, char16_t); + static Param8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param8", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h); + } + + /** + * @brief No description provided. + * + * @function Param9 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + * @param k (int16): No description available. + */ + inline void Param9(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h, int16_t k) { + using Param9Fn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, char, + const plg::string &, char16_t, int16_t); + static Param9Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param9", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h, k); + } + + /** + * @brief No description provided. + * + * @function Param10 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + * @param k (int16): No description available. + * @param l (ptr64): No description available. + */ + inline void Param10(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h, int16_t k, void *l) { + using Param10Fn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, char, + const plg::string &, char16_t, int16_t, void *); + static Param10Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.Param10", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h, k, l); + } + + /** + * @brief No description provided. + * + * @function ParamRef1 + * @param a (int32): No description available. + */ + inline void ParamRef1(int32_t &a) { + using ParamRef1Fn = void (*)(int32_t &); + static ParamRef1Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef1", reinterpret_cast(&__func)); + __func(a); + } + + /** + * @brief No description provided. + * + * @function ParamRef2 + * @param a (int32): No description available. + * @param b (float): No description available. + */ + inline void ParamRef2(int32_t &a, float &b) { + using ParamRef2Fn = void (*)(int32_t &, float &); + static ParamRef2Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef2", reinterpret_cast(&__func)); + __func(a, b); + } + + /** + * @brief No description provided. + * + * @function ParamRef3 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + */ + inline void ParamRef3(int32_t &a, float &b, double &c) { + using ParamRef3Fn = void (*)(int32_t &, float &, double &); + static ParamRef3Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef3", reinterpret_cast(&__func)); + __func(a, b, c); + } + + /** + * @brief No description provided. + * + * @function ParamRef4 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + */ + inline void ParamRef4(int32_t &a, float &b, double &c, plg::vec4 &d) { + using ParamRef4Fn = void (*)(int32_t &, float &, double &, plg::vec4 &); + static ParamRef4Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef4", reinterpret_cast(&__func)); + __func(a, b, c, d); + } + + /** + * @brief No description provided. + * + * @function ParamRef5 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + */ + inline void ParamRef5(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e) { + using ParamRef5Fn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &); + static ParamRef5Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef5", reinterpret_cast(&__func)); + __func(a, b, c, d, e); + } + + /** + * @brief No description provided. + * + * @function ParamRef6 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + */ + inline void ParamRef6(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f) { + using ParamRef6Fn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &); + static ParamRef6Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef6", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f); + } + + /** + * @brief No description provided. + * + * @function ParamRef7 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + */ + inline void ParamRef7(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g) { + using ParamRef7Fn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &, + plg::string &); + static ParamRef7Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef7", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g); + } + + /** + * @brief No description provided. + * + * @function ParamRef8 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + */ + inline void ParamRef8(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h) { + using ParamRef8Fn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &, + plg::string &, char16_t &); + static ParamRef8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef8", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h); + } + + /** + * @brief No description provided. + * + * @function ParamRef9 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + * @param k (int16): No description available. + */ + inline void ParamRef9(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h, int16_t &k) { + using ParamRef9Fn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &, + plg::string &, char16_t &, int16_t &); + static ParamRef9Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef9", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h, k); + } + + /** + * @brief No description provided. + * + * @function ParamRef10 + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + * @param k (int16): No description available. + * @param l (ptr64): No description available. + */ + inline void ParamRef10(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h, int16_t &k, void *&l) { + using ParamRef10Fn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &, + plg::string &, char16_t &, int16_t &, void *&); + static ParamRef10Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRef10", reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h, k, l); + } + + /** + * @brief No description provided. + * + * @function ParamRefVectors + * @param p1 (bool[]): No description available. + * @param p2 (char8[]): No description available. + * @param p3 (char16[]): No description available. + * @param p4 (int8[]): No description available. + * @param p5 (int16[]): No description available. + * @param p6 (int32[]): No description available. + * @param p7 (int64[]): No description available. + * @param p8 (uint8[]): No description available. + * @param p9 (uint16[]): No description available. + * @param p10 (uint32[]): No description available. + * @param p11 (uint64[]): No description available. + * @param p12 (ptr64[]): No description available. + * @param p13 (float[]): No description available. + * @param p14 (double[]): No description available. + * @param p15 (string[]): No description available. + */ + inline void ParamRefVectors(plg::vector &p1, plg::vector &p2, plg::vector &p3, + plg::vector &p4, plg::vector &p5, plg::vector &p6, + plg::vector &p7, plg::vector &p8, plg::vector &p9, + plg::vector &p10, plg::vector &p11, plg::vector &p12, + plg::vector &p13, plg::vector &p14, plg::vector &p15) { + using ParamRefVectorsFn = void (*)(plg::vector &, plg::vector &, plg::vector &, + plg::vector &, plg::vector &, plg::vector &, + plg::vector &, plg::vector &, plg::vector &, + plg::vector &, plg::vector &, plg::vector &, + plg::vector &, plg::vector &, plg::vector &); + static ParamRefVectorsFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamRefVectors", + reinterpret_cast(&__func)); + __func(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); + } + + /** + * @brief No description provided. + * + * @function ParamAllPrimitives + * @param p1 (bool): No description available. + * @param p2 (char8): No description available. + * @param p3 (char16): No description available. + * @param p4 (int8): No description available. + * @param p5 (int16): No description available. + * @param p6 (int32): No description available. + * @param p7 (int64): No description available. + * @param p8 (uint8): No description available. + * @param p9 (uint16): No description available. + * @param p10 (uint32): No description available. + * @param p11 (uint64): No description available. + * @param p12 (ptr64): No description available. + * @param p13 (float): No description available. + * @param p14 (double): No description available. + * + * @return int64: No description available. + */ + inline int64_t ParamAllPrimitives(bool p1, char p2, char16_t p3, int8_t p4, int16_t p5, int32_t p6, int64_t p7, + uint8_t p8, uint16_t p9, uint32_t p10, uint64_t p11, void *p12, float p13, + double p14) { + using ParamAllPrimitivesFn = int64_t (*)(bool, char, char16_t, int8_t, int16_t, int32_t, int64_t, uint8_t, + uint16_t, uint32_t, uint64_t, void *, float, double); + static ParamAllPrimitivesFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamAllPrimitives", + reinterpret_cast(&__func)); + return __func(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); + } + + /** + * @brief No description provided. + * + * @function ParamVariant + * @param p1 (any): No description available. + * @param p2 (any[]): No description available. + */ + inline void ParamVariant(const plg::any &p1, const plg::vector &p2) { + using ParamVariantFn = void (*)(const plg::any &, const plg::vector &); + static ParamVariantFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamVariant", reinterpret_cast(&__func)); + __func(p1, p2); + } + + /** + * @brief No description provided. + * + * @function ParamEnum + * @param p1 (int32): No description available. + * @param p2 (int32[]): No description available. + * + * @return int32: No description available. + */ + inline int32_t ParamEnum(Example p1, const plg::vector &p2) { + using ParamEnumFn = int32_t (*)(Example, const plg::vector &); + static ParamEnumFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamEnum", reinterpret_cast(&__func)); + return __func(p1, p2); + } + + /** + * @brief No description provided. + * + * @function ParamEnumRef + * @param p1 (int32): No description available. + * @param p2 (int32[]): No description available. + * + * @return int32: No description available. + */ + inline int32_t ParamEnumRef(Example &p1, plg::vector &p2) { + using ParamEnumRefFn = int32_t (*)(Example &, plg::vector &); + static ParamEnumRefFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamEnumRef", reinterpret_cast(&__func)); + return __func(p1, p2); + } + + /** + * @brief No description provided. + * + * @function ParamVariantRef + * @param p1 (any): No description available. + * @param p2 (any[]): No description available. + */ + inline void ParamVariantRef(plg::any &p1, plg::vector &p2) { + using ParamVariantRefFn = void (*)(plg::any &, plg::vector &); + static ParamVariantRefFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ParamVariantRef", + reinterpret_cast(&__func)); + __func(p1, p2); + } + + /** + * @brief No description provided. + * + * @function CallFuncVoid + * @param func (function): No description available. + * + * @callback FuncVoid + * @brief No description provided. + * + * + * @return (callback): void: No description available. + */ + inline void CallFuncVoid(FuncVoid func) { + using CallFuncVoidFn = void (*)(FuncVoid); + static CallFuncVoidFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVoid", reinterpret_cast(&__func)); + __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncBool + * @param func (function): No description available. + * + * @return bool: No description available. + * + * @callback FuncBool + * @brief No description provided. + * + * + * @return (callback): bool: No description available. + */ + inline bool CallFuncBool(FuncBool func) { + using CallFuncBoolFn = bool (*)(FuncBool); + static CallFuncBoolFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncBool", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncChar8 + * @param func (function): No description available. + * + * @return char8: No description available. + * + * @callback FuncChar8 + * @brief No description provided. + * + * + * @return (callback): char8: No description available. + */ + inline char CallFuncChar8(FuncChar8 func) { + using CallFuncChar8Fn = char (*)(FuncChar8); + static CallFuncChar8Fn __func = nullptr; + if (__func == nullptr) + plg::GetMethodPtr2("cross_call_worker.CallFuncChar8", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncChar16 + * @param func (function): No description available. + * + * @return char16: No description available. + * + * @callback FuncChar16 + * @brief No description provided. + * + * + * @return (callback): char16: No description available. + */ + inline char16_t CallFuncChar16(FuncChar16 func) { + using CallFuncChar16Fn = char16_t (*)(FuncChar16); + static CallFuncChar16Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncChar16", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt8 + * @param func (function): No description available. + * + * @return int8: No description available. + * + * @callback FuncInt8 + * @brief No description provided. + * + * + * @return (callback): int8: No description available. + */ + inline int8_t CallFuncInt8(FuncInt8 func) { + using CallFuncInt8Fn = int8_t (*)(FuncInt8); + static CallFuncInt8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt8", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt16 + * @param func (function): No description available. + * + * @return int16: No description available. + * + * @callback FuncInt16 + * @brief No description provided. + * + * + * @return (callback): int16: No description available. + */ + inline int16_t CallFuncInt16(FuncInt16 func) { + using CallFuncInt16Fn = int16_t (*)(FuncInt16); + static CallFuncInt16Fn __func = nullptr; + if (__func == nullptr) + plg::GetMethodPtr2("cross_call_worker.CallFuncInt16", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt32 + * @param func (function): No description available. + * + * @return int32: No description available. + * + * @callback FuncInt32 + * @brief No description provided. + * + * + * @return (callback): int32: No description available. + */ + inline int32_t CallFuncInt32(FuncInt32 func) { + using CallFuncInt32Fn = int32_t (*)(FuncInt32); + static CallFuncInt32Fn __func = nullptr; + if (__func == nullptr) + plg::GetMethodPtr2("cross_call_worker.CallFuncInt32", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt64 + * @param func (function): No description available. + * + * @return int64: No description available. + * + * @callback FuncInt64 + * @brief No description provided. + * + * + * @return (callback): int64: No description available. + */ + inline int64_t CallFuncInt64(FuncInt64 func) { + using CallFuncInt64Fn = int64_t (*)(FuncInt64); + static CallFuncInt64Fn __func = nullptr; + if (__func == nullptr) + plg::GetMethodPtr2("cross_call_worker.CallFuncInt64", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt8 + * @param func (function): No description available. + * + * @return uint8: No description available. + * + * @callback FuncUInt8 + * @brief No description provided. + * + * + * @return (callback): uint8: No description available. + */ + inline uint8_t CallFuncUInt8(FuncUInt8 func) { + using CallFuncUInt8Fn = uint8_t (*)(FuncUInt8); + static CallFuncUInt8Fn __func = nullptr; + if (__func == nullptr) + plg::GetMethodPtr2("cross_call_worker.CallFuncUInt8", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt16 + * @param func (function): No description available. + * + * @return uint16: No description available. + * + * @callback FuncUInt16 + * @brief No description provided. + * + * + * @return (callback): uint16: No description available. + */ + inline uint16_t CallFuncUInt16(FuncUInt16 func) { + using CallFuncUInt16Fn = uint16_t (*)(FuncUInt16); + static CallFuncUInt16Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt16", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt32 + * @param func (function): No description available. + * + * @return uint32: No description available. + * + * @callback FuncUInt32 + * @brief No description provided. + * + * + * @return (callback): uint32: No description available. + */ + inline uint32_t CallFuncUInt32(FuncUInt32 func) { + using CallFuncUInt32Fn = uint32_t (*)(FuncUInt32); + static CallFuncUInt32Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt32", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt64 + * @param func (function): No description available. + * + * @return uint64: No description available. + * + * @callback FuncUInt64 + * @brief No description provided. + * + * + * @return (callback): uint64: No description available. + */ + inline uint64_t CallFuncUInt64(FuncUInt64 func) { + using CallFuncUInt64Fn = uint64_t (*)(FuncUInt64); + static CallFuncUInt64Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt64", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncPtr + * @param func (function): No description available. + * + * @return ptr64: No description available. + * + * @callback FuncPtr + * @brief No description provided. + * + * + * @return (callback): ptr64: No description available. + */ + inline void *CallFuncPtr(FuncPtr func) { + using CallFuncPtrFn = void* (*)(FuncPtr); + static CallFuncPtrFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncPtr", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncFloat + * @param func (function): No description available. + * + * @return float: No description available. + * + * @callback FuncFloat + * @brief No description provided. + * + * + * @return (callback): float: No description available. + */ + inline float CallFuncFloat(FuncFloat func) { + using CallFuncFloatFn = float (*)(FuncFloat); + static CallFuncFloatFn __func = nullptr; + if (__func == nullptr) + plg::GetMethodPtr2("cross_call_worker.CallFuncFloat", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncDouble + * @param func (function): No description available. + * + * @return double: No description available. + * + * @callback FuncDouble + * @brief No description provided. + * + * + * @return (callback): double: No description available. + */ + inline double CallFuncDouble(FuncDouble func) { + using CallFuncDoubleFn = double (*)(FuncDouble); + static CallFuncDoubleFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncDouble", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncString + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback FuncString + * @brief No description provided. + * + * + * @return (callback): string: No description available. + */ + inline plg::string CallFuncString(FuncString func) { + using CallFuncStringFn = plg::string (*)(FuncString); + static CallFuncStringFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncString", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncAny + * @param func (function): No description available. + * + * @return any: No description available. + * + * @callback FuncAny + * @brief No description provided. + * + * + * @return (callback): any: No description available. + */ + inline plg::any CallFuncAny(FuncAny func) { + using CallFuncAnyFn = plg::any (*)(FuncAny); + static CallFuncAnyFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncAny", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncFunction + * @param func (function): No description available. + * + * @return ptr64: No description available. + * + * @callback FuncFunction + * @brief No description provided. + * + * + * @return (callback): function: No description available. + */ + inline void *CallFuncFunction(FuncFunction func) { + using CallFuncFunctionFn = void* (*)(FuncFunction); + static CallFuncFunctionFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncFunction", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncBoolVector + * @param func (function): No description available. + * + * @return bool[]: No description available. + * + * @callback FuncBoolVector + * @brief No description provided. + * + * + * @return (callback): bool[]: No description available. + */ + inline plg::vector CallFuncBoolVector(FuncBoolVector func) { + using CallFuncBoolVectorFn = plg::vector (*)(FuncBoolVector); + static CallFuncBoolVectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncBoolVector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncChar8Vector + * @param func (function): No description available. + * + * @return char8[]: No description available. + * + * @callback FuncChar8Vector + * @brief No description provided. + * + * + * @return (callback): char8[]: No description available. + */ + inline plg::vector CallFuncChar8Vector(FuncChar8Vector func) { + using CallFuncChar8VectorFn = plg::vector (*)(FuncChar8Vector); + static CallFuncChar8VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncChar8Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncChar16Vector + * @param func (function): No description available. + * + * @return char16[]: No description available. + * + * @callback FuncChar16Vector + * @brief No description provided. + * + * + * @return (callback): char16[]: No description available. + */ + inline plg::vector CallFuncChar16Vector(FuncChar16Vector func) { + using CallFuncChar16VectorFn = plg::vector (*)(FuncChar16Vector); + static CallFuncChar16VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncChar16Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt8Vector + * @param func (function): No description available. + * + * @return int8[]: No description available. + * + * @callback FuncInt8Vector + * @brief No description provided. + * + * + * @return (callback): int8[]: No description available. + */ + inline plg::vector CallFuncInt8Vector(FuncInt8Vector func) { + using CallFuncInt8VectorFn = plg::vector (*)(FuncInt8Vector); + static CallFuncInt8VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt8Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt16Vector + * @param func (function): No description available. + * + * @return int16[]: No description available. + * + * @callback FuncInt16Vector + * @brief No description provided. + * + * + * @return (callback): int16[]: No description available. + */ + inline plg::vector CallFuncInt16Vector(FuncInt16Vector func) { + using CallFuncInt16VectorFn = plg::vector (*)(FuncInt16Vector); + static CallFuncInt16VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt16Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt32Vector + * @param func (function): No description available. + * + * @return int32[]: No description available. + * + * @callback FuncInt32Vector + * @brief No description provided. + * + * + * @return (callback): int32[]: No description available. + */ + inline plg::vector CallFuncInt32Vector(FuncInt32Vector func) { + using CallFuncInt32VectorFn = plg::vector (*)(FuncInt32Vector); + static CallFuncInt32VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt32Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt64Vector + * @param func (function): No description available. + * + * @return int64[]: No description available. + * + * @callback FuncInt64Vector + * @brief No description provided. + * + * + * @return (callback): int64[]: No description available. + */ + inline plg::vector CallFuncInt64Vector(FuncInt64Vector func) { + using CallFuncInt64VectorFn = plg::vector (*)(FuncInt64Vector); + static CallFuncInt64VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncInt64Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt8Vector + * @param func (function): No description available. + * + * @return uint8[]: No description available. + * + * @callback FuncUInt8Vector + * @brief No description provided. + * + * + * @return (callback): uint8[]: No description available. + */ + inline plg::vector CallFuncUInt8Vector(FuncUInt8Vector func) { + using CallFuncUInt8VectorFn = plg::vector (*)(FuncUInt8Vector); + static CallFuncUInt8VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt8Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt16Vector + * @param func (function): No description available. + * + * @return uint16[]: No description available. + * + * @callback FuncUInt16Vector + * @brief No description provided. + * + * + * @return (callback): uint16[]: No description available. + */ + inline plg::vector CallFuncUInt16Vector(FuncUInt16Vector func) { + using CallFuncUInt16VectorFn = plg::vector (*)(FuncUInt16Vector); + static CallFuncUInt16VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt16Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt32Vector + * @param func (function): No description available. + * + * @return uint32[]: No description available. + * + * @callback FuncUInt32Vector + * @brief No description provided. + * + * + * @return (callback): uint32[]: No description available. + */ + inline plg::vector CallFuncUInt32Vector(FuncUInt32Vector func) { + using CallFuncUInt32VectorFn = plg::vector (*)(FuncUInt32Vector); + static CallFuncUInt32VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt32Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt64Vector + * @param func (function): No description available. + * + * @return uint64[]: No description available. + * + * @callback FuncUInt64Vector + * @brief No description provided. + * + * + * @return (callback): uint64[]: No description available. + */ + inline plg::vector CallFuncUInt64Vector(FuncUInt64Vector func) { + using CallFuncUInt64VectorFn = plg::vector (*)(FuncUInt64Vector); + static CallFuncUInt64VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncUInt64Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncPtrVector + * @param func (function): No description available. + * + * @return ptr64[]: No description available. + * + * @callback FuncPtrVector + * @brief No description provided. + * + * + * @return (callback): ptr64[]: No description available. + */ + inline plg::vector CallFuncPtrVector(FuncPtrVector func) { + using CallFuncPtrVectorFn = plg::vector (*)(FuncPtrVector); + static CallFuncPtrVectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncPtrVector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncFloatVector + * @param func (function): No description available. + * + * @return float[]: No description available. + * + * @callback FuncFloatVector + * @brief No description provided. + * + * + * @return (callback): float[]: No description available. + */ + inline plg::vector CallFuncFloatVector(FuncFloatVector func) { + using CallFuncFloatVectorFn = plg::vector (*)(FuncFloatVector); + static CallFuncFloatVectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncFloatVector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncDoubleVector + * @param func (function): No description available. + * + * @return double[]: No description available. + * + * @callback FuncDoubleVector + * @brief No description provided. + * + * + * @return (callback): double[]: No description available. + */ + inline plg::vector CallFuncDoubleVector(FuncDoubleVector func) { + using CallFuncDoubleVectorFn = plg::vector (*)(FuncDoubleVector); + static CallFuncDoubleVectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncDoubleVector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncStringVector + * @param func (function): No description available. + * + * @return string[]: No description available. + * + * @callback FuncStringVector + * @brief No description provided. + * + * + * @return (callback): string[]: No description available. + */ + inline plg::vector CallFuncStringVector(FuncStringVector func) { + using CallFuncStringVectorFn = plg::vector (*)(FuncStringVector); + static CallFuncStringVectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncStringVector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncAnyVector + * @param func (function): No description available. + * + * @return any[]: No description available. + * + * @callback FuncAnyVector + * @brief No description provided. + * + * + * @return (callback): any[]: No description available. + */ + inline plg::vector CallFuncAnyVector(FuncAnyVector func) { + using CallFuncAnyVectorFn = plg::vector (*)(FuncAnyVector); + static CallFuncAnyVectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncAnyVector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec2Vector + * @param func (function): No description available. + * + * @return vec2[]: No description available. + * + * @callback FuncVec2Vector + * @brief No description provided. + * + * + * @return (callback): vec2[]: No description available. + */ + inline plg::vector CallFuncVec2Vector(FuncVec2Vector func) { + using CallFuncVec2VectorFn = plg::vector (*)(FuncVec2Vector); + static CallFuncVec2VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec2Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec3Vector + * @param func (function): No description available. + * + * @return vec3[]: No description available. + * + * @callback FuncVec3Vector + * @brief No description provided. + * + * + * @return (callback): vec3[]: No description available. + */ + inline plg::vector CallFuncVec3Vector(FuncVec3Vector func) { + using CallFuncVec3VectorFn = plg::vector (*)(FuncVec3Vector); + static CallFuncVec3VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec3Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec4Vector + * @param func (function): No description available. + * + * @return vec4[]: No description available. + * + * @callback FuncVec4Vector + * @brief No description provided. + * + * + * @return (callback): vec4[]: No description available. + */ + inline plg::vector CallFuncVec4Vector(FuncVec4Vector func) { + using CallFuncVec4VectorFn = plg::vector (*)(FuncVec4Vector); + static CallFuncVec4VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec4Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncMat4x4Vector + * @param func (function): No description available. + * + * @return mat4x4[]: No description available. + * + * @callback FuncMat4x4Vector + * @brief No description provided. + * + * + * @return (callback): mat4x4[]: No description available. + */ + inline plg::vector CallFuncMat4x4Vector(FuncMat4x4Vector func) { + using CallFuncMat4x4VectorFn = plg::vector (*)(FuncMat4x4Vector); + static CallFuncMat4x4VectorFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncMat4x4Vector", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec2 + * @param func (function): No description available. + * + * @return vec2: No description available. + * + * @callback FuncVec2 + * @brief No description provided. + * + * + * @return (callback): vec2: No description available. + */ + inline plg::vec2 CallFuncVec2(FuncVec2 func) { + using CallFuncVec2Fn = plg::vec2 (*)(FuncVec2); + static CallFuncVec2Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec2", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec3 + * @param func (function): No description available. + * + * @return vec3: No description available. + * + * @callback FuncVec3 + * @brief No description provided. + * + * + * @return (callback): vec3: No description available. + */ + inline plg::vec3 CallFuncVec3(FuncVec3 func) { + using CallFuncVec3Fn = plg::vec3 (*)(FuncVec3); + static CallFuncVec3Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec3", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec4 + * @param func (function): No description available. + * + * @return vec4: No description available. + * + * @callback FuncVec4 + * @brief No description provided. + * + * + * @return (callback): vec4: No description available. + */ + inline plg::vec4 CallFuncVec4(FuncVec4 func) { + using CallFuncVec4Fn = plg::vec4 (*)(FuncVec4); + static CallFuncVec4Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncVec4", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncMat4x4 + * @param func (function): No description available. + * + * @return mat4x4: No description available. + * + * @callback FuncMat4x4 + * @brief No description provided. + * + * + * @return (callback): mat4x4: No description available. + */ + inline plg::mat4x4 CallFuncMat4x4(FuncMat4x4 func) { + using CallFuncMat4x4Fn = plg::mat4x4 (*)(FuncMat4x4); + static CallFuncMat4x4Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncMat4x4", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc1 + * @param func (function): No description available. + * + * @return int32: No description available. + * + * @callback Func1 + * @brief No description provided. + * + * @param a (vec3): No description available. + * + * @return (callback): int32: No description available. + */ + inline int32_t CallFunc1(Func1 func) { + using CallFunc1Fn = int32_t (*)(Func1); + static CallFunc1Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc1", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc2 + * @param func (function): No description available. + * + * @return char8: No description available. + * + * @callback Func2 + * @brief No description provided. + * + * @param a (float): No description available. + * @param b (int64): No description available. + * + * @return (callback): char8: No description available. + */ + inline char CallFunc2(Func2 func) { + using CallFunc2Fn = char (*)(Func2); + static CallFunc2Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc2", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc3 + * @param func (function): No description available. + * + * @callback Func3 + * @brief No description provided. + * + * @param a (ptr64): No description available. + * @param b (vec4): No description available. + * @param c (string): No description available. + * + * @return (callback): void: No description available. + */ + inline void CallFunc3(Func3 func) { + using CallFunc3Fn = void (*)(Func3); + static CallFunc3Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc3", reinterpret_cast(&__func)); + __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc4 + * @param func (function): No description available. + * + * @return vec4: No description available. + * + * @callback Func4 + * @brief No description provided. + * + * @param a (bool): No description available. + * @param b (int32): No description available. + * @param c (char16): No description available. + * @param d (mat4x4): No description available. + * + * @return (callback): vec4: No description available. + */ + inline plg::vec4 CallFunc4(Func4 func) { + using CallFunc4Fn = plg::vec4 (*)(Func4); + static CallFunc4Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc4", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc5 + * @param func (function): No description available. + * + * @return bool: No description available. + * + * @callback Func5 + * @brief No description provided. + * + * @param a (int8): No description available. + * @param b (vec2): No description available. + * @param c (ptr64): No description available. + * @param d (double): No description available. + * @param e (uint64[]): No description available. + * + * @return (callback): bool: No description available. + */ + inline bool CallFunc5(Func5 func) { + using CallFunc5Fn = bool (*)(Func5); + static CallFunc5Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc5", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc6 + * @param func (function): No description available. + * + * @return int64: No description available. + * + * @callback Func6 + * @brief No description provided. + * + * @param a (string): No description available. + * @param b (float): No description available. + * @param c (float[]): No description available. + * @param d (int16): No description available. + * @param e (uint8[]): No description available. + * @param f (ptr64): No description available. + * + * @return (callback): int64: No description available. + */ + inline int64_t CallFunc6(Func6 func) { + using CallFunc6Fn = int64_t (*)(Func6); + static CallFunc6Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc6", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc7 + * @param func (function): No description available. + * + * @return double: No description available. + * + * @callback Func7 + * @brief No description provided. + * + * @param vecC (char8[]): No description available. + * @param u16 (uint16): No description available. + * @param ch16 (char16): No description available. + * @param vecU32 (uint32[]): No description available. + * @param vec4 (vec4): No description available. + * @param b (bool): No description available. + * @param u64 (uint64): No description available. + * + * @return (callback): double: No description available. + */ + inline double CallFunc7(Func7 func) { + using CallFunc7Fn = double (*)(Func7); + static CallFunc7Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc7", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc8 + * @param func (function): No description available. + * + * @return mat4x4: No description available. + * + * @callback Func8 + * @brief No description provided. + * + * @param vec3 (vec3): No description available. + * @param vecU32 (uint32[]): No description available. + * @param i16 (int16): No description available. + * @param b (bool): No description available. + * @param vec4 (vec4): No description available. + * @param vecC16 (char16[]): No description available. + * @param ch16 (char16): No description available. + * @param i32 (int32): No description available. + * + * @return (callback): mat4x4: No description available. + */ + inline plg::mat4x4 CallFunc8(Func8 func) { + using CallFunc8Fn = plg::mat4x4 (*)(Func8); + static CallFunc8Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc8", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc9 + * @param func (function): No description available. + * + * @callback Func9 + * @brief No description provided. + * + * @param f (float): No description available. + * @param vec2 (vec2): No description available. + * @param vecI8 (int8[]): No description available. + * @param u64 (uint64): No description available. + * @param b (bool): No description available. + * @param str (string): No description available. + * @param vec4 (vec4): No description available. + * @param i16 (int16): No description available. + * @param ptr (ptr64): No description available. + * + * @return (callback): void: No description available. + */ + inline void CallFunc9(Func9 func) { + using CallFunc9Fn = void (*)(Func9); + static CallFunc9Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc9", reinterpret_cast(&__func)); + __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc10 + * @param func (function): No description available. + * + * @return uint32: No description available. + * + * @callback Func10 + * @brief No description provided. + * + * @param vec4 (vec4): No description available. + * @param mat (mat4x4): No description available. + * @param vecU32 (uint32[]): No description available. + * @param u64 (uint64): No description available. + * @param vecC (char8[]): No description available. + * @param i32 (int32): No description available. + * @param b (bool): No description available. + * @param vec2 (vec2): No description available. + * @param i64 (int64): No description available. + * @param d (double): No description available. + * + * @return (callback): uint32: No description available. + */ + inline uint32_t CallFunc10(Func10 func) { + using CallFunc10Fn = uint32_t (*)(Func10); + static CallFunc10Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc10", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc11 + * @param func (function): No description available. + * + * @return ptr64: No description available. + * + * @callback Func11 + * @brief No description provided. + * + * @param vecB (bool[]): No description available. + * @param ch16 (char16): No description available. + * @param u8 (uint8): No description available. + * @param d (double): No description available. + * @param vec3 (vec3): No description available. + * @param vecI8 (int8[]): No description available. + * @param i64 (int64): No description available. + * @param u16 (uint16): No description available. + * @param f (float): No description available. + * @param vec2 (vec2): No description available. + * @param u32 (uint32): No description available. + * + * @return (callback): ptr64: No description available. + */ + inline void *CallFunc11(Func11 func) { + using CallFunc11Fn = void* (*)(Func11); + static CallFunc11Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc11", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc12 + * @param func (function): No description available. + * + * @return bool: No description available. + * + * @callback Func12 + * @brief No description provided. + * + * @param ptr (ptr64): No description available. + * @param vecD (double[]): No description available. + * @param u32 (uint32): No description available. + * @param d (double): No description available. + * @param b (bool): No description available. + * @param i32 (int32): No description available. + * @param i8 (int8): No description available. + * @param u64 (uint64): No description available. + * @param f (float): No description available. + * @param vecPtr (ptr64[]): No description available. + * @param i64 (int64): No description available. + * @param ch (char8): No description available. + * + * @return (callback): bool: No description available. + */ + inline bool CallFunc12(Func12 func) { + using CallFunc12Fn = bool (*)(Func12); + static CallFunc12Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc12", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc13 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func13 + * @brief No description provided. + * + * @param i64 (int64): No description available. + * @param vecC (char8[]): No description available. + * @param d (uint16): No description available. + * @param f (float): No description available. + * @param b (bool[]): No description available. + * @param vec4 (vec4): No description available. + * @param str (string): No description available. + * @param int32 (int32): No description available. + * @param vec3 (vec3): No description available. + * @param ptr (ptr64): No description available. + * @param vec2 (vec2): No description available. + * @param arr (uint8[]): No description available. + * @param i16 (int16): No description available. + * + * @return (callback): string: No description available. + */ + inline plg::string CallFunc13(Func13 func) { + using CallFunc13Fn = plg::string (*)(Func13); + static CallFunc13Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc13", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc14 + * @param func (function): No description available. + * + * @return string[]: No description available. + * + * @callback Func14 + * @brief No description provided. + * + * @param vecC (char8[]): No description available. + * @param vecU32 (uint32[]): No description available. + * @param mat (mat4x4): No description available. + * @param b (bool): No description available. + * @param ch16 (char16): No description available. + * @param i32 (int32): No description available. + * @param vecF (float[]): No description available. + * @param u16 (uint16): No description available. + * @param vecU8 (uint8[]): No description available. + * @param i8 (int8): No description available. + * @param vec3 (vec3): No description available. + * @param vec4 (vec4): No description available. + * @param d (double): No description available. + * @param ptr (ptr64): No description available. + * + * @return (callback): string[]: No description available. + */ + inline plg::vector CallFunc14(Func14 func) { + using CallFunc14Fn = plg::vector (*)(Func14); + static CallFunc14Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc14", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc15 + * @param func (function): No description available. + * + * @return int16: No description available. + * + * @callback Func15 + * @brief No description provided. + * + * @param vecI16 (int16[]): No description available. + * @param mat (mat4x4): No description available. + * @param vec4 (vec4): No description available. + * @param ptr (ptr64): No description available. + * @param u64 (uint64): No description available. + * @param vecU32 (uint32[]): No description available. + * @param b (bool): No description available. + * @param f (float): No description available. + * @param vecC16 (char16[]): No description available. + * @param u8 (uint8): No description available. + * @param i32 (int32): No description available. + * @param vec2 (vec2): No description available. + * @param u16 (uint16): No description available. + * @param d (double): No description available. + * @param vecU8 (uint8[]): No description available. + * + * @return (callback): int16: No description available. + */ + inline int16_t CallFunc15(Func15 func) { + using CallFunc15Fn = int16_t (*)(Func15); + static CallFunc15Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc15", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc16 + * @param func (function): No description available. + * + * @return ptr64: No description available. + * + * @callback Func16 + * @brief No description provided. + * + * @param vecB (bool[]): No description available. + * @param i16 (int16): No description available. + * @param vecI8 (int8[]): No description available. + * @param vec4 (vec4): No description available. + * @param mat (mat4x4): No description available. + * @param vec2 (vec2): No description available. + * @param vecU64 (uint64[]): No description available. + * @param vecC (char8[]): No description available. + * @param str (string): No description available. + * @param i64 (int64): No description available. + * @param vecU32 (uint32[]): No description available. + * @param vec3 (vec3): No description available. + * @param f (float): No description available. + * @param d (double): No description available. + * @param i8 (int8): No description available. + * @param u16 (uint16): No description available. + * + * @return (callback): ptr64: No description available. + */ + inline void *CallFunc16(Func16 func) { + using CallFunc16Fn = void* (*)(Func16); + static CallFunc16Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc16", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc17 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func17 + * @brief No description provided. + * + * @param i32 (int32): No description available. + * + * @return (callback): void: No description available. + */ + inline plg::string CallFunc17(Func17 func) { + using CallFunc17Fn = plg::string (*)(Func17); + static CallFunc17Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc17", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc18 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func18 + * @brief No description provided. + * + * @param i8 (int8): No description available. + * @param i16 (int16): No description available. + * + * @return (callback): vec2: No description available. + */ + inline plg::string CallFunc18(Func18 func) { + using CallFunc18Fn = plg::string (*)(Func18); + static CallFunc18Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc18", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc19 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func19 + * @brief No description provided. + * + * @param u32 (uint32): No description available. + * @param vec3 (vec3): No description available. + * @param vecU32 (uint32[]): No description available. + * + * @return (callback): void: No description available. + */ + inline plg::string CallFunc19(Func19 func) { + using CallFunc19Fn = plg::string (*)(Func19); + static CallFunc19Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc19", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc20 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func20 + * @brief No description provided. + * + * @param ch16 (char16): No description available. + * @param vec4 (vec4): No description available. + * @param vecU64 (uint64[]): No description available. + * @param ch (char8): No description available. + * + * @return (callback): int32: No description available. + */ + inline plg::string CallFunc20(Func20 func) { + using CallFunc20Fn = plg::string (*)(Func20); + static CallFunc20Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc20", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc21 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func21 + * @brief No description provided. + * + * @param mat (mat4x4): No description available. + * @param vecI32 (int32[]): No description available. + * @param vec2 (vec2): No description available. + * @param b (bool): No description available. + * @param extraParam (double): No description available. + * + * @return (callback): float: No description available. + */ + inline plg::string CallFunc21(Func21 func) { + using CallFunc21Fn = plg::string (*)(Func21); + static CallFunc21Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc21", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc22 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func22 + * @brief No description provided. + * + * @param ptr64Ref (ptr64): No description available. + * @param uint32Ref (uint32): No description available. + * @param vectorDoubleRef (double[]): No description available. + * @param int16Ref (int16): No description available. + * @param plgStringRef (string): No description available. + * @param plgVector4Ref (vec4): No description available. + * + * @return (callback): uint64: No description available. + */ + inline plg::string CallFunc22(Func22 func) { + using CallFunc22Fn = plg::string (*)(Func22); + static CallFunc22Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc22", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc23 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func23 + * @brief No description provided. + * + * @param uint64Ref (uint64): No description available. + * @param plgVector2Ref (vec2): No description available. + * @param vectorInt16Ref (int16[]): No description available. + * @param char16Ref (char16): No description available. + * @param floatRef (float): No description available. + * @param int8Ref (int8): No description available. + * @param vectorUInt8Ref (uint8[]): No description available. + * + * @return (callback): void: No description available. + */ + inline plg::string CallFunc23(Func23 func) { + using CallFunc23Fn = plg::string (*)(Func23); + static CallFunc23Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc23", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc24 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func24 + * @brief No description provided. + * + * @param vectorCharRef (char8[]): No description available. + * @param int64Ref (int64): No description available. + * @param vectorUInt8Ref (uint8[]): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param uint64Ref (uint64): No description available. + * @param vectorptr64Ref (ptr64[]): No description available. + * @param doubleRef (double): No description available. + * @param vectorptr64Ref (ptr64[]): No description available. + * + * @return (callback): mat4x4: No description available. + */ + inline plg::string CallFunc24(Func24 func) { + using CallFunc24Fn = plg::string (*)(Func24); + static CallFunc24Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc24", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc25 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func25 + * @brief No description provided. + * + * @param int32Ref (int32): No description available. + * @param vectorptr64Ref (ptr64[]): No description available. + * @param boolRef (bool): No description available. + * @param uint8Ref (uint8): No description available. + * @param plgStringRef (string): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param int64Ref (int64): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param uint16Ref (uint16): No description available. + * + * @return (callback): double: No description available. + */ + inline plg::string CallFunc25(Func25 func) { + using CallFunc25Fn = plg::string (*)(Func25); + static CallFunc25Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc25", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc26 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func26 + * @brief No description provided. + * + * @param char16Ref (char16): No description available. + * @param plgVector2Ref (vec2): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param vectorFloatRef (float[]): No description available. + * @param int16Ref (int16): No description available. + * @param uint64Ref (uint64): No description available. + * @param uint32Ref (uint32): No description available. + * @param vectorUInt16Ref (uint16[]): No description available. + * @param ptr64Ref (ptr64): No description available. + * @param boolRef (bool): No description available. + * + * @return (callback): char8: No description available. + */ + inline plg::string CallFunc26(Func26 func) { + using CallFunc26Fn = plg::string (*)(Func26); + static CallFunc26Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc26", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc27 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func27 + * @brief No description provided. + * + * @param floatRef (float): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param ptr64Ref (ptr64): No description available. + * @param plgVector2Ref (vec2): No description available. + * @param vectorInt16Ref (int16[]): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param boolRef (bool): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param int8Ref (int8): No description available. + * @param int32Ref (int32): No description available. + * @param vectorUInt8Ref (uint8[]): No description available. + * + * @return (callback): uint8: No description available. + */ + inline plg::string CallFunc27(Func27 func) { + using CallFunc27Fn = plg::string (*)(Func27); + static CallFunc27Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc27", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc28 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func28 + * @brief No description provided. + * + * @param ptr64Ref (ptr64): No description available. + * @param uint16Ref (uint16): No description available. + * @param vectorUInt32Ref (uint32[]): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param floatRef (float): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param plgStringRef (string): No description available. + * @param vectorUInt64Ref (uint64[]): No description available. + * @param int64Ref (int64): No description available. + * @param boolRef (bool): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param vectorFloatRef (float[]): No description available. + * + * @return (callback): string: No description available. + */ + inline plg::string CallFunc28(Func28 func) { + using CallFunc28Fn = plg::string (*)(Func28); + static CallFunc28Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc28", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc29 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func29 + * @brief No description provided. + * + * @param plgVector4Ref (vec4): No description available. + * @param int32Ref (int32): No description available. + * @param vectorInt8Ref (int8[]): No description available. + * @param doubleRef (double): No description available. + * @param boolRef (bool): No description available. + * @param int8Ref (int8): No description available. + * @param vectorUInt16Ref (uint16[]): No description available. + * @param floatRef (float): No description available. + * @param plgStringRef (string): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param uint64Ref (uint64): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param vectorInt64Ref (int64[]): No description available. + * + * @return (callback): string[]: No description available. + */ + inline plg::string CallFunc29(Func29 func) { + using CallFunc29Fn = plg::string (*)(Func29); + static CallFunc29Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc29", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc30 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func30 + * @brief No description provided. + * + * @param ptr64Ref (ptr64): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param int64Ref (int64): No description available. + * @param vectorUInt32Ref (uint32[]): No description available. + * @param boolRef (bool): No description available. + * @param plgStringRef (string): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param vectorUInt8Ref (uint8[]): No description available. + * @param floatRef (float): No description available. + * @param plgVector2Ref (vec2): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param int8Ref (int8): No description available. + * @param vectorFloatRef (float[]): No description available. + * @param doubleRef (double): No description available. + * + * @return (callback): int32: No description available. + */ + inline plg::string CallFunc30(Func30 func) { + using CallFunc30Fn = plg::string (*)(Func30); + static CallFunc30Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc30", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc31 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func31 + * @brief No description provided. + * + * @param charRef (char8): No description available. + * @param uint32Ref (uint32): No description available. + * @param vectorUInt64Ref (uint64[]): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param plgStringRef (string): No description available. + * @param boolRef (bool): No description available. + * @param int64Ref (int64): No description available. + * @param vec2Ref (vec2): No description available. + * @param int8Ref (int8): No description available. + * @param uint16Ref (uint16): No description available. + * @param vectorInt16Ref (int16[]): No description available. + * @param mat4x4Ref (mat4x4): No description available. + * @param vec3Ref (vec3): No description available. + * @param floatRef (float): No description available. + * @param vectorDoubleRef (double[]): No description available. + * + * @return (callback): vec3: No description available. + */ + inline plg::string CallFunc31(Func31 func) { + using CallFunc31Fn = plg::string (*)(Func31); + static CallFunc31Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc31", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc32 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func32 + * @brief No description provided. + * + * @param p1 (int32): No description available. + * @param p2 (uint16): No description available. + * @param p3 (int8[]): No description available. + * @param p4 (vec4): No description available. + * @param p5 (ptr64): No description available. + * @param p6 (uint32[]): No description available. + * @param p7 (mat4x4): No description available. + * @param p8 (uint64): No description available. + * @param p9 (string): No description available. + * @param p10 (int64): No description available. + * @param p11 (vec2): No description available. + * @param p12 (int8[]): No description available. + * @param p13 (bool): No description available. + * @param p14 (vec3): No description available. + * @param p14 (uint8): No description available. + * @param p15 (char16[]): No description available. + * + * @return (callback): double: No description available. + */ + inline plg::string CallFunc32(Func32 func) { + using CallFunc32Fn = plg::string (*)(Func32); + static CallFunc32Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc32", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc33 + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func33 + * @brief No description provided. + * + * @param variant (any): No description available. + * + * @return (callback): void: No description available. + */ + inline plg::string CallFunc33(Func33 func) { + using CallFunc33Fn = plg::string (*)(Func33); + static CallFunc33Fn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFunc33", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncEnum + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback FuncEnum + * @brief No description provided. + * + * @param p1 (int32): No description available. + * @param p2 (int32[]): No description available. + * + * @return (callback): int32[]: No description available. + */ + inline plg::string CallFuncEnum(FuncEnum func) { + using CallFuncEnumFn = plg::string (*)(FuncEnum); + static CallFuncEnumFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.CallFuncEnum", reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function ReverseCall + * @param test (string): No description available. + */ + inline void ReverseCall(const plg::string &test) { + using ReverseCallFn = void (*)(const plg::string &); + static ReverseCallFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_worker.ReverseCall", reinterpret_cast(&__func)); + __func(test); + } } // namespace cross_call_worker diff --git a/test/cross_call_master/plugin.cpp b/test/cross_call_master/plugin.cpp index ad699e8..3f14eee 100644 --- a/test/cross_call_master/plugin.cpp +++ b/test/cross_call_master/plugin.cpp @@ -36,6 +36,7 @@ using Example = cross_call_worker::Example; // format support #ifdef FMT_HEADER_ONLY namespace fmt { + #else namespace std { #endif @@ -46,7 +47,7 @@ namespace std { } template - auto format(const Example& e, FormatContext &ctx) const { + auto format(const Example &e, FormatContext &ctx) const { return std::format_to(ctx.out(), "{}", static_cast(e)); } }; @@ -54,7 +55,10 @@ namespace std { // Mock Functions for the typedefs -void MockVoid() { /*std::cout << "Void function called\n";*/ } +void MockVoid() { + /*std::cout << "Void function called\n";*/ +} + bool MockBool() { return false; } char MockChar8() { return 'B'; } char16_t MockChar16() { return u'A'; } @@ -66,10 +70,10 @@ uint8_t MockUInt8() { return 25; } uint16_t MockUInt16() { return 250; } uint32_t MockUInt32() { return 2500; } uint64_t MockUInt64() { return 25000; } -void* MockPtr() { return reinterpret_cast(1); } +void *MockPtr() { return reinterpret_cast(1); } float MockFloat() { return 2.71f; } double MockDouble() { return 5.55; } -void* MockFunction() { return reinterpret_cast(2); } +void *MockFunction() { return reinterpret_cast(2); } plg::string MockString() { return "Example string"; } plg::any MockAny() { return 0xDEADBEAF; } @@ -84,72 +88,77 @@ plg::vector MockUInt8Vector() { return {25, 35}; } plg::vector MockUInt16Vector() { return {250, 350}; } plg::vector MockUInt32Vector() { return {2500, 3500}; } plg::vector MockUInt64Vector() { return {25000, 35000}; } -plg::vector MockPtrVector() { return {reinterpret_cast(1), reinterpret_cast(2)}; } +plg::vector MockPtrVector() { return {reinterpret_cast(1), reinterpret_cast(2)}; } plg::vector MockFloatVector() { return {3.3f, 4.4f}; } plg::vector MockDoubleVector() { return {5.5, 6.6}; } plg::vector MockStringVector() { return {"Foo", "Bar"}; } + plg::vector MockVec2Vector() { return { - {1.1f, 2.2f}, - {3.3f, 4.4f}, - {-5.5f, -6.6f}, - {0.0f, 0.0f}, - {7.7f, 8.8f} + {1.1f, 2.2f}, + {3.3f, 4.4f}, + {-5.5f, -6.6f}, + {0.0f, 0.0f}, + {7.7f, 8.8f} }; } plg::vector MockVec3Vector() { return { - {1.1f, 2.2f, 3.3f}, - {4.4f, 5.5f, 6.6f}, - {-7.7f, -8.8f, -9.9f}, - {0.0f, 0.0f, 0.0f}, - {10.1f, 11.2f, 12.3f} + {1.1f, 2.2f, 3.3f}, + {4.4f, 5.5f, 6.6f}, + {-7.7f, -8.8f, -9.9f}, + {0.0f, 0.0f, 0.0f}, + {10.1f, 11.2f, 12.3f} }; } plg::vector MockVec4Vector() { return { - {1.1f, 2.2f, 3.3f, 4.4f}, - {5.5f, 6.6f, 7.7f, 8.8f}, - {-9.9f, -10.1f, -11.2f, -12.3f}, - {0.0f, 0.0f, 0.0f, 0.0f}, - {13.1f, 14.2f, 15.3f, 16.4f} + {1.1f, 2.2f, 3.3f, 4.4f}, + {5.5f, 6.6f, 7.7f, 8.8f}, + {-9.9f, -10.1f, -11.2f, -12.3f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {13.1f, 14.2f, 15.3f, 16.4f} }; } plg::vector MockMat4x4Vector() { return { - // Identity matrix - { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }, - // Example random matrix - { - 2.0f, 3.0f, 4.0f, 5.0f, - 6.0f, 7.0f, 8.0f, 9.0f, - 10.0f, 11.0f, 12.0f, 13.0f, - 14.0f, 15.0f, 16.0f, 17.0f - }, - // Another random matrix - { - -1.0f, -2.0f, -3.0f, -4.0f, - -5.0f, -6.0f, -7.0f, -8.0f, - -9.0f, -10.0f, -11.0f, -12.0f, - -13.0f, -14.0f, -15.0f, -16.0f - } + // Identity matrix + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }, + // Example random matrix + { + 2.0f, 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f, 9.0f, + 10.0f, 11.0f, 12.0f, 13.0f, + 14.0f, 15.0f, 16.0f, 17.0f + }, + // Another random matrix + { + -1.0f, -2.0f, -3.0f, -4.0f, + -5.0f, -6.0f, -7.0f, -8.0f, + -9.0f, -10.0f, -11.0f, -12.0f, + -13.0f, -14.0f, -15.0f, -16.0f + } }; } + plg::vec2 MockVec2() { return {2.0f, 3.0f}; } plg::vec3 MockVec3() { return {2.0f, 3.0f, 4.0f}; } plg::vec4 MockVec4() { return {2.0f, 3.0f, 4.0f, 5.0f}; } -plg::mat4x4 MockMat4x4() { return {2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; } + +plg::mat4x4 MockMat4x4() { + return {2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; +} // Mock implementations for 1 parameter functions -int32_t MockFunc1(const plg::vec3& v) { +int32_t MockFunc1(const plg::vec3 &v) { const auto buffer = std::format("{}{}{}", v.x, v.y, v.z); return static_cast(v.x * 2 + v.y * 2 + v.z * 2); } @@ -161,108 +170,135 @@ char MockFunc2(float a, int64_t b) { } // Mock implementations for 3 parameter functions -void MockFunc3(void* p, const plg::vec4& v, const plg::string& s) { +void MockFunc3(void *p, const plg::vec4 &v, const plg::string &s) { const auto buffer = std::format("{}{}{}{}{}{}", p, v.x, v.y, v.z, v.w, s); } // Mock implementations for 4 parameter functions -plg::vec4 MockFunc4(bool flag, int32_t u, char16_t c, const plg::mat4x4& m) { +plg::vec4 MockFunc4(bool flag, int32_t u, char16_t c, const plg::mat4x4 &m) { const auto buffer = std::format("{}{}{}{}", flag, u, static_cast(c), m.m[0][0]); - return {5.0f, 6.0f, 7.0f, 8.0f}; // Returning a different dummy const plg::vec4 + return {5.0f, 6.0f, 7.0f, 8.0f}; // Returning a different dummy const plg::vec4 } // Mock implementations for 5 parameter functions -bool MockFunc5(int8_t i, const plg::vec2& v, void* p, double d, const plg::vector& vec) { +bool MockFunc5(int8_t i, const plg::vec2 &v, void *p, double d, const plg::vector &vec) { const auto buffer = std::format("{}{}{}{}{}{}", i, v.x, v.y, p, d, vec.size()); return false; // Changed return value to dummy false } // Mock implementations for 6 parameter functions -int64_t MockFunc6(const plg::string& s, float f, const plg::vector& vec, int16_t i, const plg::vector& uVec, void* p) { +int64_t MockFunc6(const plg::string &s, float f, const plg::vector &vec, int16_t i, + const plg::vector &uVec, void *p) { const auto buffer = std::format("{}{}{}{}{}{}", s, f, vec.size(), i, uVec.size(), p); - return static_cast(f * 2 + i); // Changed return value + return static_cast(f * 2 + i); // Changed return value } // Mock implementations for 7 parameter functions -double MockFunc7(const plg::vector& vec, uint16_t u, char16_t c, const plg::vector& uVec, const plg::vec4& v, bool flag, uint64_t l) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}", vec.size(), u, static_cast(c), uVec.size(), v.x, v.y, v.z, v.w, flag, l); - return 6.28; // Changed return value to a different dummy double +double MockFunc7(const plg::vector &vec, uint16_t u, char16_t c, const plg::vector &uVec, + const plg::vec4 &v, bool flag, uint64_t l) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}", vec.size(), u, static_cast(c), uVec.size(), v.x, v.y, + v.z, v.w, flag, l); + return 6.28; // Changed return value to a different dummy double } // Mock implementations for 8 parameter functions -plg::mat4x4 MockFunc8(const plg::vec3& v, const plg::vector& uVec, int16_t i, bool flag, const plg::vec4& v4, const plg::vector& cVec, char16_t c, int32_t a) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}", v.x, v.y, v.z, uVec.size(), i, flag, v4.w, cVec.size(), static_cast(c), a); +plg::mat4x4 MockFunc8(const plg::vec3 &v, const plg::vector &uVec, int16_t i, bool flag, const plg::vec4 &v4, + const plg::vector &cVec, char16_t c, int32_t a) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}", v.x, v.y, v.z, uVec.size(), i, flag, v4.w, cVec.size(), + static_cast(c), a); return {}; // Returning a different dummy const plg::mat4x4 } // Mock implementations for 9 parameter functions -void MockFunc9(float f, const plg::vec2& v, const plg::vector& iVec, uint64_t l, bool flag, const plg::string& s, const plg::vec4& v4, int16_t i, void* p) { +void MockFunc9(float f, const plg::vec2 &v, const plg::vector &iVec, uint64_t l, bool flag, + const plg::string &s, const plg::vec4 &v4, int16_t i, void *p) { const auto buffer = std::format("{}{}{}{}{}{}{}{}{}", f, v.x, v.y, iVec.size(), l, flag, s, v4.w, i, p); } // Mock implementations for 10 parameter functions -uint32_t MockFunc10(const plg::vec4& v4, const plg::mat4x4& m, const plg::vector& uVec, uint64_t l, const plg::vector& cVec, int32_t a, bool flag, const plg::vec2& v, int64_t i, double d) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", v4.x, v4.y, v4.z, v4.w, m.m[1][1], uVec.size(), l, cVec.size(), a, flag, v.x, v.y, i, d); +uint32_t MockFunc10(const plg::vec4 &v4, const plg::mat4x4 &m, const plg::vector &uVec, uint64_t l, + const plg::vector &cVec, int32_t a, bool flag, const plg::vec2 &v, int64_t i, double d) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", v4.x, v4.y, v4.z, v4.w, m.m[1][1], uVec.size(), l, + cVec.size(), a, flag, v.x, v.y, i, d); return 84; // Changed to a different dummy uint32_t } // Mock implementations for 11 parameter functions -void* MockFunc11(const plg::vector& bVec, char16_t c, uint8_t u, double d, const plg::vec3& v3, const plg::vector& iVec, int64_t i, uint16_t u16, float f, const plg::vec2& v, uint32_t u32) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}", bVec.size(), static_cast(c), u, d, v3.x, iVec.size(), i, u16, f, v.x, u32); - return reinterpret_cast(1); // Changed to return a non-null pointer +void *MockFunc11(const plg::vector &bVec, char16_t c, uint8_t u, double d, const plg::vec3 &v3, + const plg::vector &iVec, int64_t i, uint16_t u16, float f, const plg::vec2 &v, uint32_t u32) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}", bVec.size(), static_cast(c), u, d, v3.x, + iVec.size(), i, u16, f, v.x, u32); + return reinterpret_cast(1); // Changed to return a non-null pointer } // Mock implementations for 12 parameter functions -bool MockFunc12(void* p, const plg::vector& dVec, uint32_t u, double d, bool flag, int32_t a, int8_t i, uint64_t l, float f, const plg::vector& pVec, int64_t i64, char c) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}", p, dVec.size(), u, d, flag, a, i, l, f, pVec.size(), i64, c); +bool MockFunc12(void *p, const plg::vector &dVec, uint32_t u, double d, bool flag, int32_t a, int8_t i, + uint64_t l, float f, const plg::vector &pVec, int64_t i64, char c) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}", p, dVec.size(), u, d, flag, a, i, l, f, pVec.size(), + i64, c); return true; // Changed to return dummy true } // Mock implementations for 13 parameter functions -plg::string MockFunc13(int64_t i64, const plg::vector& cVec, uint16_t u16, float f, const plg::vector& bVec, const plg::vec4& v4, const plg::string& s, int32_t a, const plg::vec3& v3, void* p, const plg::vec2& v2, const plg::vector& u8Vec, int16_t i16) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", i64, cVec.size(), u16, f, bVec.size(), v4.z, s, a, v3.x, p, v2.x, u8Vec.size(), i16); +plg::string MockFunc13(int64_t i64, const plg::vector &cVec, uint16_t u16, float f, const plg::vector &bVec, + const plg::vec4 &v4, const plg::string &s, int32_t a, const plg::vec3 &v3, void *p, + const plg::vec2 &v2, const plg::vector &u8Vec, int16_t i16) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", i64, cVec.size(), u16, f, bVec.size(), v4.z, s, a, v3.x, p, + v2.x, u8Vec.size(), i16); return "Updated Dummy String"; // Changed return string } // Mock implementations for 14 parameter functions -plg::vector MockFunc14(const plg::vector& cVec, const plg::vector& uVec, const plg::mat4x4& m, bool flag, char16_t c, int32_t a, const plg::vector& fVec, uint16_t u16, const plg::vector& u8Vec, int8_t i8, const plg::vec3& v3, const plg::vec4& v4, double d, void* p) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}", cVec.size(), uVec.size(), m.m[2][2], flag, static_cast(c), a, fVec.size(), u16, u8Vec.size(), i8, v3.x, v4.x, d, p); +plg::vector MockFunc14(const plg::vector &cVec, const plg::vector &uVec, + const plg::mat4x4 &m, bool flag, char16_t c, int32_t a, + const plg::vector &fVec, uint16_t u16, const plg::vector &u8Vec, + int8_t i8, const plg::vec3 &v3, const plg::vec4 &v4, double d, void *p) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}", cVec.size(), uVec.size(), m.m[2][2], flag, + static_cast(c), a, fVec.size(), u16, u8Vec.size(), i8, v3.x, v4.x, d, p); return {"New String1", "New String2"}; // Changed return values } // Mock implementations for 15 parameter functions -int16_t MockFunc15(const plg::vector& iVec, const plg::mat4x4& m, const plg::vec4& v4, void* p, uint64_t l, const plg::vector& uVec, bool flag, float f, const plg::vector& cVec, uint8_t u, int32_t a, const plg::vec2& v2, uint16_t u16, double d, const plg::vector& u8Vec) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", iVec.size(), m.m[1][0], v4.x, p, l, uVec.size(), flag, f, cVec.size(), u, a, v2.x, u16, d, u8Vec.size()); +int16_t MockFunc15(const plg::vector &iVec, const plg::mat4x4 &m, const plg::vec4 &v4, void *p, uint64_t l, + const plg::vector &uVec, bool flag, float f, const plg::vector &cVec, uint8_t u, + int32_t a, const plg::vec2 &v2, uint16_t u16, double d, const plg::vector &u8Vec) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", iVec.size(), m.m[1][0], v4.x, p, l, uVec.size(), flag, f, + cVec.size(), u, a, v2.x, u16, d, u8Vec.size()); return 512; // Changed to a different dummy int16_t } // Mock implementations for 16 parameter functions -void* MockFunc16(const plg::vector& bVec, int16_t i16, const plg::vector& iVec, const plg::vec4& v4, const plg::mat4x4& m, const plg::vec2& v2, const plg::vector& uVec, const plg::vector& cVec, const plg::string& s, int64_t i64, const plg::vector& u32Vec, const plg::vec3& v3, float f, double d, int8_t i8, uint16_t u16) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", i16, bVec.size(), iVec.size(), v4.x, v4.y, v4.z, v4.w, m.m[2][3], v2.x, uVec.size(), cVec.size(), s, i64, u32Vec.size(), v3.x, f, d, i8, u16); - return reinterpret_cast(2); // Changed to return a different non-null pointer +void *MockFunc16(const plg::vector &bVec, int16_t i16, const plg::vector &iVec, const plg::vec4 &v4, + const plg::mat4x4 &m, const plg::vec2 &v2, const plg::vector &uVec, + const plg::vector &cVec, const plg::string &s, int64_t i64, const plg::vector &u32Vec, + const plg::vec3 &v3, float f, double d, int8_t i8, uint16_t u16) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", i16, bVec.size(), iVec.size(), v4.x, v4.y, v4.z, + v4.w, m.m[2][3], v2.x, uVec.size(), cVec.size(), s, i64, u32Vec.size(), v3.x, f, d, + i8, u16); + return reinterpret_cast(2); // Changed to return a different non-null pointer } // Mock implementations for 17 parameter functions -void MockFunc17(int32_t& ref) { - ref += 20; // Modified value change +void MockFunc17(int32_t &ref) { + ref += 20; // Modified value change } // Mock implementations for 18 parameter functions -plg::vec2 MockFunc18(int8_t& i8, int16_t& i16) { - i8 = 10; // Changed int8_t value - i16 = 20; // Changed int16_t value - return {static_cast(i8), static_cast(i16)}; // Updated return values +plg::vec2 MockFunc18(int8_t &i8, int16_t &i16) { + i8 = 10; // Changed int8_t value + i16 = 20; // Changed int16_t value + return {static_cast(i8), static_cast(i16)}; // Updated return values } // Mock implementations for 19 parameter functions -void MockFunc19(uint32_t& u32, plg::vec3& v3, plg::vector& uVec) { - u32 = 84; // Changed uint32_t value +void MockFunc19(uint32_t &u32, plg::vec3 &v3, plg::vector &uVec) { + u32 = 84; // Changed uint32_t value v3 = {4.0f, 5.0f, 6.0f}; // Updated plg::vec3 reference uVec = {4, 5, 6}; // Changed plg::vector values } // Mock implementations for 20 parameter functions -int32_t MockFunc20(char16_t& c, plg::vec4& v4, plg::vector& uVec, char& ch) { +int32_t MockFunc20(char16_t &c, plg::vec4 &v4, plg::vector &uVec, char &ch) { c = u'g'; // Changed char16_t value v4 = {5.0f, 6.0f, 7.0f, 8.0f}; // Updated plg::vec4 reference uVec = {300, 400}; // Changed plg::vector values @@ -271,12 +307,12 @@ int32_t MockFunc20(char16_t& c, plg::vec4& v4, plg::vector& uVec, char } // Mock implementations for 21 parameter functions -float MockFunc21(plg::mat4x4& m, plg::vector& iVec, plg::vec2& v2, bool& flag, double& d) { +float MockFunc21(plg::mat4x4 &m, plg::vector &iVec, plg::vec2 &v2, bool &flag, double &d) { flag = false; // Changed boolean reference - d = 6.28; // Updated double reference + d = 6.28; // Updated double reference v2 = {3.0f, 4.0f}; // Changed plg::vec2 reference m = { - 1.5f, 0.7f, 0.9f, 0.6f, // Updated values + 1.5f, 0.7f, 0.9f, 0.6f, // Updated values 0.8f, 1.2f, 0.3f, 0.5f, 1.1f, 0.4f, 1.3f, 0.8f, 0.6f, 1.0f, 0.4f, 0.9f @@ -286,10 +322,10 @@ float MockFunc21(plg::mat4x4& m, plg::vector& iVec, plg::vec2& v2, bool } // Mock implementations for 22 parameter functions -uint64_t MockFunc22(void*& p, uint32_t& u32, plg::vector& dVec, int16_t& i16, plg::string& s, plg::vec4& v4) { - p = reinterpret_cast(0x1); // Updated void* reference - u32 = 150; // Changed uint32_t value - i16 = 456; // Changed int16_t value +uint64_t MockFunc22(void *&p, uint32_t &u32, plg::vector &dVec, int16_t &i16, plg::string &s, plg::vec4 &v4) { + p = reinterpret_cast(0x1); // Updated void* reference + u32 = 150; // Changed uint32_t value + i16 = 456; // Changed int16_t value s = "World"; // Changed string reference v4 = {5.0f, 6.0f, 7.0f, 8.0f}; // Updated plg::vec4 reference dVec = {4.4, 5.5, 6.6}; // Updated plg::vector values @@ -297,10 +333,11 @@ uint64_t MockFunc22(void*& p, uint32_t& u32, plg::vector& dVec, int16_t& } // Mock implementations for 23 parameter functions -void MockFunc23(uint64_t& u64, plg::vec2& v2, plg::vector& iVec, char16_t& c, float& f, int8_t& i8, plg::vector& u8Vec) { +void MockFunc23(uint64_t &u64, plg::vec2 &v2, plg::vector &iVec, char16_t &c, float &f, int8_t &i8, + plg::vector &u8Vec) { u64 = 100; // Changed uint64_t reference f = 2.0f; // Updated float reference - i8 = 2; // Changed int8_t reference + i8 = 2; // Changed int8_t reference v2 = {6.0f, 7.0f}; // Updated plg::vec2 reference u8Vec = {4, 5, 6}; // Changed plg::vector values c = L'Ⅷ'; // Updated char16_t value @@ -308,39 +345,42 @@ void MockFunc23(uint64_t& u64, plg::vec2& v2, plg::vector& iVec, char16 } // Mock implementations for 24 parameter functions -plg::mat4x4 MockFunc24(plg::vector& cVec, int64_t& i64, plg::vector& u8Vec, plg::vec4& v4, uint64_t& u64, plg::vector& pVec, double& d, plg::vector& vVec) { - i64 = 128; // Changed int64_t reference - d = 3.14; // Updated double reference +plg::mat4x4 MockFunc24(plg::vector &cVec, int64_t &i64, plg::vector &u8Vec, plg::vec4 &v4, uint64_t &u64, + plg::vector &pVec, double &d, plg::vector &vVec) { + i64 = 128; // Changed int64_t reference + d = 3.14; // Updated double reference v4 = {5.0f, 6.0f, 7.0f, 8.0f}; // Updated plg::vec4 reference cVec = {'d', 'e', 'f'}; // Changed plg::vector values u8Vec = {7, 8, 9}; // Changed plg::vector values - pVec = { reinterpret_cast(0xFFFFDDDDFFFFDDDD) }; // Updated plg::vector values + pVec = {reinterpret_cast(0xFFFFDDDDFFFFDDDD)}; // Updated plg::vector values vVec = {reinterpret_cast(3), reinterpret_cast(4)}; // Updated plg::vector values u64 = 0xFFFFFFFFFF; // Changed uint64_t reference return {}; // Returning dummy plg::mat4x4 } // Mock implementations for 25 parameter functions -double MockFunc25(int32_t& i32, plg::vector& pVec, bool& flag, uint8_t& u8, plg::string& s, plg::vec3& v3, int64_t& i64, plg::vec4& v4, uint16_t& u16) { +double MockFunc25(int32_t &i32, plg::vector &pVec, bool &flag, uint8_t &u8, plg::string &s, plg::vec3 &v3, + int64_t &i64, plg::vec4 &v4, uint16_t &u16) { flag = true; // Changed boolean reference - i32 = 200; // Updated int32_t reference - u8 = 128; // Changed uint8_t reference + i32 = 200; // Updated int32_t reference + u8 = 128; // Changed uint8_t reference v3 = {4.0f, 5.0f, 6.0f}; // Updated plg::vec3 reference v4 = {8.0f, 9.0f, 10.0f, 11.0f}; // Changed plg::vec4 reference s = "UpdatedMockFunc25"; // Changed string reference - pVec = { reinterpret_cast(0xDEADBEEFDEADBEEF) }; // Updated plg::vector values + pVec = {reinterpret_cast(0xDEADBEEFDEADBEEF)}; // Updated plg::vector values i64 = 2023; // Changed int64_t reference u16 = 64222; // Changed uint16_t reference - return 1.0; // Updated return value + return 1.0; // Updated return value } // Mock implementations for 26 parameter functions -char MockFunc26(char16_t& c, plg::vec2& v2, plg::mat4x4& m, plg::vector& fVec, int16_t& i16, uint64_t& u64, uint32_t& u32, plg::vector& u16Vec, void*& p, bool& flag) { +char MockFunc26(char16_t &c, plg::vec2 &v2, plg::mat4x4 &m, plg::vector &fVec, int16_t &i16, uint64_t &u64, + uint32_t &u32, plg::vector &u16Vec, void *&p, bool &flag) { c = u'A'; // Updated char16_t reference flag = false; // Changed boolean reference v2 = {4.0f, 5.0f}; // Updated plg::vec2 reference m = { - 0.5f, 0.3f, 0.1f, 0.4f, // Updated values + 0.5f, 0.3f, 0.1f, 0.4f, // Updated values 1.5f, 0.7f, 0.6f, 0.8f, 1.1f, 0.4f, 0.2f, 1.0f, 0.9f, 0.8f, 0.6f, 1.0f @@ -355,7 +395,8 @@ char MockFunc26(char16_t& c, plg::vec2& v2, plg::mat4x4& m, plg::vector& } // Mock implementations for 27 parameter functions -uint8_t MockFunc27(float& f, plg::vec3& v3, void*& p, plg::vec2& v2, plg::vector& i16Vec, plg::mat4x4& m, bool& flag, plg::vec4& v4, int8_t& i8, int32_t& i32, plg::vector& u8Vec) { +uint8_t MockFunc27(float &f, plg::vec3 &v3, void *&p, plg::vec2 &v2, plg::vector &i16Vec, plg::mat4x4 &m, + bool &flag, plg::vec4 &v4, int8_t &i8, int32_t &i32, plg::vector &u8Vec) { f = 9.0f; // Changed float reference v3 = {7.0f, 8.0f, 9.0f}; // Updated plg::vec3 reference p = reinterpret_cast(0xDEADBEEFDEADBEEF); // Updated void* reference @@ -371,20 +412,22 @@ uint8_t MockFunc27(float& f, plg::vec3& v3, void*& p, plg::vec2& v2, plg::vector v4 = {2.0f, 3.0f, 4.0f, 5.0f}; // Changed plg::vec4 reference i8 = 10; // Updated int8_t reference i32 = 20; // Updated int32_t reference - u8Vec = { 1, 55, 66, 87, 99, 23, 123 }; + u8Vec = {1, 55, 66, 87, 99, 23, 123}; return 27; // Updated return value } // Mock implementations for 28 parameter functions -plg::string MockFunc28(void*& ptr, uint16_t& u16, plg::vector& u32Vec, plg::mat4x4& m, float& f, plg::vec4& v4, plg::string& str, plg::vector& u64Vec, int64_t& i64, bool& b, plg::vec3& vec3, plg::vector& fVec) { - ptr = reinterpret_cast(0x7FFFFFFFFFFF); +plg::string MockFunc28(void *&ptr, uint16_t &u16, plg::vector &u32Vec, plg::mat4x4 &m, float &f, + plg::vec4 &v4, plg::string &str, plg::vector &u64Vec, int64_t &i64, bool &b, + plg::vec3 &vec3, plg::vector &fVec) { + ptr = reinterpret_cast(0x7FFFFFFFFFFF); u16 = 60000; // Updated value - u32Vec = { 10, 20, 30, 40, 50, 60 }; // Updated values + u32Vec = {10, 20, 30, 40, 50, 60}; // Updated values m = { - 2.1f, 0.9f, 0.4f, 0.8f, // Row 0 - 0.5f, 1.2f, 0.7f, 0.4f, // Row 1 - 1.0f, 0.6f, 1.5f, 0.2f, // Row 2 - 0.8f, 0.3f, 0.9f, 1.1f // Row 3 + 2.1f, 0.9f, 0.4f, 0.8f, // Row 0 + 0.5f, 1.2f, 0.7f, 0.4f, // Row 1 + 1.0f, 0.6f, 1.5f, 0.2f, // Row 2 + 0.8f, 0.3f, 0.9f, 1.1f // Row 3 }; f = 7.5f; // Updated value for float reference v4 = {2.0f, 3.0f, 4.0f, 5.0f}; // Updated value for plg::vec4 reference @@ -398,7 +441,9 @@ plg::string MockFunc28(void*& ptr, uint16_t& u16, plg::vector& u32Vec, } // Mock implementations for 29 parameter functions -plg::vector MockFunc29(plg::vec4& v4, int32_t& i32, plg::vector& iVec, double& d, bool& flag, int8_t& i8, plg::vector& u16Vec, float& f, plg::string& s, plg::mat4x4& m, uint64_t& u64, plg::vec3& v3, plg::vector& i64Vec) { +plg::vector MockFunc29(plg::vec4 &v4, int32_t &i32, plg::vector &iVec, double &d, bool &flag, + int8_t &i8, plg::vector &u16Vec, float &f, plg::string &s, plg::mat4x4 &m, + uint64_t &u64, plg::vec3 &v3, plg::vector &i64Vec) { i32 = 50; // Updated value for int32_t reference flag = false; // Updated boolean value v4 = {2.5f, 3.5f, 4.5f, 5.5f}; // Updated value for plg::vec4 reference @@ -408,10 +453,10 @@ plg::vector MockFunc29(plg::vec4& v4, int32_t& i32, plg::vector MockFunc29(plg::vec4& v4, int32_t& i32, plg::vector& uVec, bool& flag, plg::string& s, plg::vec3& v3, plg::vector& u8Vec, float& f, plg::vec2& v2, plg::mat4x4& m, int8_t& i8, plg::vector& vVec, double& d) { +int32_t MockFunc30(void *&p, plg::vec4 &v4, int64_t &i64, plg::vector &uVec, bool &flag, plg::string &s, + plg::vec3 &v3, plg::vector &u8Vec, float &f, plg::vec2 &v2, plg::mat4x4 &m, int8_t &i8, + plg::vector &vVec, double &d) { flag = true; // Updated boolean value f = 3.3f; // Updated value for float reference i64 = 2000; // Updated value for int64_t reference v2 = {4.0f, 5.0f}; // Updated value for plg::vec2 reference v4 = {2.0f, 4.0f, 6.0f, 8.0f}; // Updated value for plg::vec4 reference s = "Updated MockFunc30"; // Updated string reference - p = reinterpret_cast(0x7FFFFFFFFFFF); // Keeping void* reference as nullptr + p = reinterpret_cast(0x7FFFFFFFFFFF); // Keeping void* reference as nullptr uVec = {300, 400}; // Updated values for plg::vector m = { - 0.6f, 0.2f, 1.5f, 0.9f, // Row 0 - 1.2f, 0.4f, 0.7f, 0.8f, // Row 1 - 0.5f, 0.1f, 1.7f, 0.4f, // Row 2 - 0.8f, 0.6f, 1.2f, 1.3f // Row 3 + 0.6f, 0.2f, 1.5f, 0.9f, // Row 0 + 1.2f, 0.4f, 0.7f, 0.8f, // Row 1 + 0.5f, 0.1f, 1.7f, 0.4f, // Row 2 + 0.8f, 0.6f, 1.2f, 1.3f // Row 3 }; // Updated value for plg::mat4x4 reference i8 = 10; // Updated value for int8_t reference vVec = {3.0f, 3.0f, 4.0f, 4.0f}; // Updated values for plg::vector d = 3.14159; // Updated double value - v3 = { 4.0f, 5.0f, 6.0f }; // Updated values for plg::vec3 - u8Vec = { 128, 64, 255, 0, 100, 50 }; // Updated values for plg::vector + v3 = {4.0f, 5.0f, 6.0f}; // Updated values for plg::vec3 + u8Vec = {128, 64, 255, 0, 100, 50}; // Updated values for plg::vector return 77; // Updated return value } // Mock implementations for 31 parameter functions -plg::vec3 MockFunc31(char& c, uint32_t& u32, plg::vector& uVec, plg::vec4& v4, plg::string& s, bool& flag, int64_t& i64, plg::vec2& v2, int8_t& i8, uint16_t& u16, plg::vector& iVec, plg::mat4x4& m, plg::vec3& v3, float& f, plg::vector& v4Vec) { +plg::vec3 MockFunc31(char &c, uint32_t &u32, plg::vector &uVec, plg::vec4 &v4, plg::string &s, bool &flag, + int64_t &i64, plg::vec2 &v2, int8_t &i8, uint16_t &u16, plg::vector &iVec, plg::mat4x4 &m, + plg::vec3 &v3, float &f, plg::vector &v4Vec) { u32 = 54321; // Updated value for uint32_t reference flag = false; // Updated boolean value v3 = {10.0f, 20.0f, 30.0f}; // Updated value for plg::vec3 reference c = 'D'; // Updated char value - uVec = { UINT64_MAX, UINT64_MAX - 1 , UINT64_MAX - 2 }; + uVec = {UINT64_MAX, UINT64_MAX - 1, UINT64_MAX - 2}; v4 = {5.0f, 6.0f, 7.0f, 8.0f}; // Updated value for plg::vec4 reference s = "Updated MockFunc31"; // Updated string reference i64 = 987654321; // Updated value for int64_t reference @@ -459,10 +508,10 @@ plg::vec3 MockFunc31(char& c, uint32_t& u32, plg::vector& uVec, plg::v u16 = 500; // Updated value for uint16_t reference iVec = {5, 10}; // Updated values for plg::vector m = { - 1.0f, 0.2f, 1.1f, 0.4f, // Row 0 - 1.1f, 0.8f, 0.3f, 0.9f, // Row 1 - 0.5f, 0.7f, 1.8f, 0.6f, // Row 2 - 0.3f, 0.6f, 1.4f, 0.8f // Row 3 + 1.0f, 0.2f, 1.1f, 0.4f, // Row 0 + 1.1f, 0.8f, 0.3f, 0.9f, // Row 1 + 0.5f, 0.7f, 1.8f, 0.6f, // Row 2 + 0.3f, 0.6f, 1.4f, 0.8f // Row 3 }; // Updated value for plg::mat4x4 reference f = 8.8f; // Updated value for float reference v4Vec = {0.2, 0.4, 0.6}; // Updated values for plg::vector @@ -470,7 +519,10 @@ plg::vec3 MockFunc31(char& c, uint32_t& u32, plg::vector& uVec, plg::v } // Mock implementations for 32 parameter functions -double MockFunc32(int32_t& i32, uint16_t& u16, plg::vector& iVec, plg::vec4& v4, void*& p, plg::vector& uVec, plg::mat4x4& m, uint64_t& u64, plg::string& s, int64_t& i64, plg::vec2& v2, plg::vector& u8Vec, bool& flag, plg::vec3& v3, uint8_t& u8, plg::vector& cVec) { +double MockFunc32(int32_t &i32, uint16_t &u16, plg::vector &iVec, plg::vec4 &v4, void *&p, + plg::vector &uVec, plg::mat4x4 &m, uint64_t &u64, plg::string &s, int64_t &i64, + plg::vec2 &v2, plg::vector &u8Vec, bool &flag, plg::vec3 &v3, uint8_t &u8, + plg::vector &cVec) { i32 = 100; // Updated value for int32_t reference u16 = 512; // Updated value for uint16_t reference flag = true; // Updated boolean value @@ -478,12 +530,12 @@ double MockFunc32(int32_t& i32, uint16_t& u16, plg::vector& iVec, plg::v u8Vec = {6, 7, 8, 9}; // Updated values for plg::vector v4 = {8.0f, 9.0f, 10.0f, 11.0f}; // Updated value for plg::vec4 reference s = "Updated MockFunc32"; // Updated string reference - p = reinterpret_cast(0xDEADBEAFDEADBEAF); // Keeping void* reference as nullptr + p = reinterpret_cast(0xDEADBEAFDEADBEAF); // Keeping void* reference as nullptr m = { - 0.5f, 0.3f, 0.2f, 0.1f, // Row 0 - 0.8f, 0.9f, 0.4f, 0.6f, // Row 1 - 0.1f, 0.7f, 1.0f, 0.5f, // Row 2 - 0.4f, 0.2f, 0.3f, 1.2f // Row 3 + 0.5f, 0.3f, 0.2f, 0.1f, // Row 0 + 0.8f, 0.9f, 0.4f, 0.6f, // Row 1 + 0.1f, 0.7f, 1.0f, 0.5f, // Row 2 + 0.4f, 0.2f, 0.3f, 1.2f // Row 3 }; // Updated value for plg::mat4x4 reference u64 = 987654321; // Updated value for uint64_t reference uVec = {400, 500}; // Updated values for plg::vector @@ -491,332 +543,354 @@ double MockFunc32(int32_t& i32, uint16_t& u16, plg::vector& iVec, plg::v v3 = {1.0f, 2.0f, 3.0f}; // Updated value for plg::vec3 reference u8 = 15; // Updated value for uint8_t reference cVec = {u'x', u'y', u'z'}; // Updated values for plg::vector - iVec = { 5, 10 }; // Updated values for plg::vector + iVec = {5, 10}; // Updated values for plg::vector return 2.5; // Updated return value for double } // Mock implementations for 1 parameter functions -void MockFunc33(plg::any& variant) { +void MockFunc33(plg::any &variant) { variant = "Updated MockFunc33"; // Updated value for variant reference } // Mock implementations for enu parameters functions -plg::vector MockFuncEnum(Example p1, plg::vector& p2) { - p2 = { Example::Forth, Example::Third, Example::Second }; - return { p1, Example::First }; +plg::vector MockFuncEnum(Example p1, plg::vector &p2) { + p2 = {Example::Forth, Example::Third, Example::Second}; + return {p1, Example::First}; } class CrossCallMaster final : public plg::IPluginEntry { public: - void OnPluginStart() final { - NoParamOnlyReturn(); - ParamsNoRefs(); - ParamsWithRefs(); - ParamsRefVectors(); - ParamsAllPrimitives(); - ParamsFunctions(); - ReverseNoParamOnlyReturn(); - ReverseParamsNoRefs(); - ReverseParamsWithRefs(); - ReverseParamsRefVectors(); - ReverseParamsAllPrimitives(); - ReverseParamsVariants(); - ReverseParamsFunctions(); - _tests.Run(); - } + void OnPluginStart() final { + NoParamOnlyReturn(); + ParamsNoRefs(); + ParamsWithRefs(); + ParamsRefVectors(); + ParamsAllPrimitives(); + ParamsFunctions(); + ReverseNoParamOnlyReturn(); + ReverseParamsNoRefs(); + ReverseParamsWithRefs(); + ReverseParamsRefVectors(); + ReverseParamsAllPrimitives(); + ReverseParamsVariants(); + ReverseParamsFunctions(); + _tests.Run(); + } void OnPluginEnd() final { _tests.Reset(); }; - void NoParamOnlyReturn() { + void NoParamOnlyReturn() { #if TEST_CASES & TEST_NO_PARAM_ONLY_RETURN_PRIMITIVES - _tests.Add("NoParamReturnVoid", [](SimpleTests::Test& /*test*/) { - cross_call_worker::NoParamReturnVoid(); - }); - _tests.Add("NoParamReturnBool", [](SimpleTests::Test& test) { - auto expected = true; - auto result = cross_call_worker::NoParamReturnBool(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnChar8", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnChar8(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", static_cast(result), static_cast(expected))); - } - }); - _tests.Add("NoParamReturnChar16", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnChar16(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", static_cast(result), static_cast(expected))); - } - }); - _tests.Add("NoParamReturnInt8", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnInt8(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnInt16", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnInt16(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnInt32", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnInt32(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnInt64", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnInt64(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnUInt8", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnUInt8(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnUInt16", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnUInt16(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnUInt32", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnUInt32(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnUInt64", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnUInt64(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnPointer", [](SimpleTests::Test& test) { - auto expected = reinterpret_cast(0x1); - auto result = cross_call_worker::NoParamReturnPointer(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnFloat", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnFloat(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnDouble", [](SimpleTests::Test& test) { - auto expected = std::numeric_limits::max(); - auto result = cross_call_worker::NoParamReturnDouble(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); + _tests.Add("NoParamReturnVoid", [](SimpleTests::Test & /*test*/) { + cross_call_worker::NoParamReturnVoid(); + }); + _tests.Add("NoParamReturnBool", [](SimpleTests::Test &test) { + auto expected = true; + auto result = cross_call_worker::NoParamReturnBool(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnChar8", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnChar8(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", static_cast(result), + static_cast(expected))); + } + }); + _tests.Add("NoParamReturnChar16", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnChar16(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", static_cast(result), + static_cast(expected))); + } + }); + _tests.Add("NoParamReturnInt8", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnInt8(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnInt16", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnInt16(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnInt32", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnInt32(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnInt64", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnInt64(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnUInt8", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnUInt8(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnUInt16", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnUInt16(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnUInt32", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnUInt32(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnUInt64", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnUInt64(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnPointer", [](SimpleTests::Test &test) { + auto expected = reinterpret_cast(0x1); + auto result = cross_call_worker::NoParamReturnPointer(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnFloat", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnFloat(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnDouble", [](SimpleTests::Test &test) { + auto expected = std::numeric_limits::max(); + auto result = cross_call_worker::NoParamReturnDouble(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); #endif // TEST_CASES & TEST_NO_PARAM_ONLY_RETURN_PRIMITIVES #if TEST_CASES & TEST_NO_PARAM_ONLY_RETURN_OBJECTS - _tests.Add("NoParamReturnFunction", [](SimpleTests::Test& test) { - cross_call_worker::NoParamReturnFunctionFunc expected = nullptr; - auto result = cross_call_worker::NoParamReturnFunction(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", reinterpret_cast(result), reinterpret_cast(expected))); - } - }); - _tests.Add("NoParamReturnString", [](SimpleTests::Test& test) { - auto expected = "Hello World"; - auto result = cross_call_worker::NoParamReturnString(); - if (result != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", result, expected)); - } - }); - _tests.Add("NoParamReturnAny", [](SimpleTests::Test& test) { - plg::any expected = plg::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - auto result = cross_call_worker::NoParamReturnAny(); - if (result.index() != expected.index() && std::format("{}", result) != std::format("{}", expected)) { - test.Fail(std::format("Wrong return '{}', expected '{}'", result, expected)); - } - }); + _tests.Add("NoParamReturnFunction", [](SimpleTests::Test &test) { + cross_call_worker::NoParamReturnFunctionFunc expected = nullptr; + auto result = cross_call_worker::NoParamReturnFunction(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", reinterpret_cast(result), + reinterpret_cast(expected))); + } + }); + _tests.Add("NoParamReturnString", [](SimpleTests::Test &test) { + auto expected = "Hello World"; + auto result = cross_call_worker::NoParamReturnString(); + if (result != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", result, expected)); + } + }); + _tests.Add("NoParamReturnAny", [](SimpleTests::Test &test) { + plg::any expected = plg::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + auto result = cross_call_worker::NoParamReturnAny(); + if (result.index() != expected.index() && std::format("{}", result) != std::format("{}", expected)) { + test.Fail(std::format("Wrong return '{}', expected '{}'", result, expected)); + } + }); #endif // TEST_CASES & TEST_NO_PARAM_ONLY_RETURN_OBJECTS #if TEST_CASES & TEST_NO_PARAM_ONLY_RETURN_ARRAYS - _tests.Add("NoParamReturnArrayBool", [](SimpleTests::Test& test) { - auto expected = plg::vector{true, false}; - auto result = cross_call_worker::NoParamReturnArrayBool(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayChar8", [](SimpleTests::Test& test) { - auto expected = plg::vector{'a', 'b', 'c', 'd'}; - auto result = cross_call_worker::NoParamReturnArrayChar8(); - if (result != expected) { + _tests.Add("NoParamReturnArrayBool", [](SimpleTests::Test &test) { + auto expected = plg::vector{true, false}; + auto result = cross_call_worker::NoParamReturnArrayBool(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnArrayChar8", [](SimpleTests::Test &test) { + auto expected = plg::vector{'a', 'b', 'c', 'd'}; + auto result = cross_call_worker::NoParamReturnArrayChar8(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayChar16", [](SimpleTests::Test& test) { - auto expected = plg::vector{u'a', u'b', u'c', u'd'}; - auto result = cross_call_worker::NoParamReturnArrayChar16(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayChar16", [](SimpleTests::Test &test) { + auto expected = plg::vector{u'a', u'b', u'c', u'd'}; + auto result = cross_call_worker::NoParamReturnArrayChar16(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayInt8", [](SimpleTests::Test& test) { - auto expected = plg::vector{-3, -2, -1, 0, 1}; - auto result = cross_call_worker::NoParamReturnArrayInt8(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayInt8", [](SimpleTests::Test &test) { + auto expected = plg::vector{-3, -2, -1, 0, 1}; + auto result = cross_call_worker::NoParamReturnArrayInt8(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayInt16", [](SimpleTests::Test& test) { - auto expected = plg::vector{-4, -3, -2, -1, 0, 1}; - auto result = cross_call_worker::NoParamReturnArrayInt16(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayInt16", [](SimpleTests::Test &test) { + auto expected = plg::vector{-4, -3, -2, -1, 0, 1}; + auto result = cross_call_worker::NoParamReturnArrayInt16(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayInt32", [](SimpleTests::Test& test) { - auto expected = plg::vector{-5, -4, -3, -2, -1, 0, 1}; - auto result = cross_call_worker::NoParamReturnArrayInt32(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayInt32", [](SimpleTests::Test &test) { + auto expected = plg::vector{-5, -4, -3, -2, -1, 0, 1}; + auto result = cross_call_worker::NoParamReturnArrayInt32(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayInt64", [](SimpleTests::Test& test) { - auto expected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1}; - auto result = cross_call_worker::NoParamReturnArrayInt64(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayInt64", [](SimpleTests::Test &test) { + auto expected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1}; + auto result = cross_call_worker::NoParamReturnArrayInt64(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayUInt8", [](SimpleTests::Test& test) { - auto expected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8}; - auto result = cross_call_worker::NoParamReturnArrayUInt8(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayUInt8", [](SimpleTests::Test &test) { + auto expected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8}; + auto result = cross_call_worker::NoParamReturnArrayUInt8(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayUInt16", [](SimpleTests::Test& test) { - auto expected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - auto result = cross_call_worker::NoParamReturnArrayUInt16(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayUInt16", [](SimpleTests::Test &test) { + auto expected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + auto result = cross_call_worker::NoParamReturnArrayUInt16(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayUInt32", [](SimpleTests::Test& test) { - auto expected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - auto result = cross_call_worker::NoParamReturnArrayUInt32(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayUInt32", [](SimpleTests::Test &test) { + auto expected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + auto result = cross_call_worker::NoParamReturnArrayUInt32(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayUInt64", [](SimpleTests::Test& test) { - auto expected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; - auto result = cross_call_worker::NoParamReturnArrayUInt64(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayUInt64", [](SimpleTests::Test &test) { + auto expected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + auto result = cross_call_worker::NoParamReturnArrayUInt64(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayPointer", [](SimpleTests::Test& test) { - auto expected = plg::vector{reinterpret_cast(0), reinterpret_cast(1), reinterpret_cast(2), reinterpret_cast(3)}; - auto result = cross_call_worker::NoParamReturnArrayPointer(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayPointer", [](SimpleTests::Test &test) { + auto expected = plg::vector{ + reinterpret_cast(0), reinterpret_cast(1), reinterpret_cast(2), + reinterpret_cast(3) + }; + auto result = cross_call_worker::NoParamReturnArrayPointer(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayFloat", [](SimpleTests::Test& test) { - auto expected = plg::vector{-12.34f, 0.0f, 12.34f}; - auto result = cross_call_worker::NoParamReturnArrayFloat(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayFloat", [](SimpleTests::Test &test) { + auto expected = plg::vector{-12.34f, 0.0f, 12.34f}; + auto result = cross_call_worker::NoParamReturnArrayFloat(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayDouble", [](SimpleTests::Test& test) { - auto expected = plg::vector{-12.345, 0.0, 12.345}; - auto result = cross_call_worker::NoParamReturnArrayDouble(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayDouble", [](SimpleTests::Test &test) { + auto expected = plg::vector{-12.345, 0.0, 12.345}; + auto result = cross_call_worker::NoParamReturnArrayDouble(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayString", [](SimpleTests::Test& test) { - auto expected = plg::vector{"1st string", "2nd string", "3rd element string (Should be big enough to avoid small string optimization)"}; - auto result = cross_call_worker::NoParamReturnArrayString(); - if (result != expected) { + } + }); + _tests.Add("NoParamReturnArrayString", [](SimpleTests::Test &test) { + auto expected = plg::vector{ + "1st string", "2nd string", + "3rd element string (Should be big enough to avoid small string optimization)" + }; + auto result = cross_call_worker::NoParamReturnArrayString(); + if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayAny", [](SimpleTests::Test& test) { - auto expected = plg::vector{1.0, 2.0f, "3rd element string (Should be big enough to avoid small string optimization)", plg::vector{"lolek", "and", "bolek"}, 1}; - auto result = cross_call_worker::NoParamReturnArrayAny(); - bool wrong = result.size() != expected.size(); + } + }); + _tests.Add("NoParamReturnArrayAny", [](SimpleTests::Test &test) { + auto expected = plg::vector{ + 1.0, 2.0f, "3rd element string (Should be big enough to avoid small string optimization)", + plg::vector{"lolek", "and", "bolek"}, 1 + }; + auto result = cross_call_worker::NoParamReturnArrayAny(); + bool wrong = result.size() != expected.size(); if (!wrong) { for (size_t i = 0; i < result.size(); ++i) { - wrong |= result[i].index() != expected[i].index() && std::format("{}", result) != std::format("{}", expected); + wrong |= result[i].index() != expected[i].index() && std::format("{}", result) != std::format( + "{}", expected); } } if (wrong) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnArrayVector2", [](SimpleTests::Test& test) { - auto expected = plg::vector{{1.1f, 2.2f}, {-3.3f, 4.4f}, {5.5f, -6.6f}, {7.7f, 8.8f}, {0.0f, 0.0f}}; + } + }); + _tests.Add("NoParamReturnArrayVector2", [](SimpleTests::Test &test) { + auto expected = plg::vector{ + {1.1f, 2.2f}, {-3.3f, 4.4f}, {5.5f, -6.6f}, {7.7f, 8.8f}, {0.0f, 0.0f} + }; auto result = cross_call_worker::NoParamReturnArrayVector2(); if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); } }); - _tests.Add("NoParamReturnArrayVector3", [](SimpleTests::Test& test) { - auto expected = plg::vector{{1.1f, 2.2f, 3.3f}, {-4.4f, 5.5f, -6.6f}, {7.7f, 8.8f, 9.9f}, {0.0f, 0.0f, 0.0f}, {10.1f, -11.2f, 12.3f}}; + _tests.Add("NoParamReturnArrayVector3", [](SimpleTests::Test &test) { + auto expected = plg::vector{ + {1.1f, 2.2f, 3.3f}, {-4.4f, 5.5f, -6.6f}, {7.7f, 8.8f, 9.9f}, {0.0f, 0.0f, 0.0f}, {10.1f, -11.2f, 12.3f} + }; auto result = cross_call_worker::NoParamReturnArrayVector3(); if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); } }); - _tests.Add("NoParamReturnArrayVector4", [](SimpleTests::Test& test) { - auto expected = plg::vector{{1.1f, 2.2f, 3.3f, 4.4f}, {-5.5f, 6.6f, -7.7f, 8.8f}, {9.9f, 0.0f, -1.1f, 2.2f}, {3.3f, 4.4f, 5.5f, 6.6f}, {-7.7f, -8.8f, 9.9f, -10.1f}}; + _tests.Add("NoParamReturnArrayVector4", [](SimpleTests::Test &test) { + auto expected = plg::vector{ + {1.1f, 2.2f, 3.3f, 4.4f}, {-5.5f, 6.6f, -7.7f, 8.8f}, {9.9f, 0.0f, -1.1f, 2.2f}, + {3.3f, 4.4f, 5.5f, 6.6f}, {-7.7f, -8.8f, 9.9f, -10.1f} + }; auto result = cross_call_worker::NoParamReturnArrayVector4(); if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); } }); - _tests.Add("NoParamReturnArrayMatrix4x4", [](SimpleTests::Test& test) { - auto expected = plg::vector{{ - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f // Identity matrix - }, - { - 2.0f, 3.0f, 4.0f, 5.0f, - 6.0f, 7.0f, 8.0f, 9.0f, - 10.0f, 11.0f, 12.0f, 13.0f, - 14.0f, 15.0f, 16.0f, 17.0f // Example random matrix - }, - { - -1.0f, -2.0f, -3.0f, -4.0f, - -5.0f, -6.0f, -7.0f, -8.0f, - -9.0f, -10.0f, -11.0f, -12.0f, - -13.0f, -14.0f, -15.0f, -16.0f // Negative matrix - }}; + _tests.Add("NoParamReturnArrayMatrix4x4", [](SimpleTests::Test &test) { + auto expected = plg::vector{ + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f // Identity matrix + }, + { + 2.0f, 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f, 9.0f, + 10.0f, 11.0f, 12.0f, 13.0f, + 14.0f, 15.0f, 16.0f, 17.0f // Example random matrix + }, + { + -1.0f, -2.0f, -3.0f, -4.0f, + -5.0f, -6.0f, -7.0f, -8.0f, + -9.0f, -10.0f, -11.0f, -12.0f, + -13.0f, -14.0f, -15.0f, -16.0f // Negative matrix + } + }; auto result = cross_call_worker::NoParamReturnArrayMatrix4x4(); if (result != expected) { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); @@ -825,518 +899,539 @@ class CrossCallMaster final : public plg::IPluginEntry { #endif// TEST_CASES & TEST_NO_PARAM_ONLY_RETURN_ARRAYS #if TEST_CASES & TEST_NO_PARAM_ONLY_RETURN_VECTORS - _tests.Add("NoParamReturnVector2", [](SimpleTests::Test& test) { - auto expected = plg::vec2{1, 2}; - auto result = cross_call_worker::NoParamReturnVector2(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnVector3", [](SimpleTests::Test& test) { - auto expected = plg::vec3{1, 2, 3}; - auto result = cross_call_worker::NoParamReturnVector3(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnVector4", [](SimpleTests::Test& test) { - auto expected = plg::vec4{1, 2, 3, 4}; - auto result = cross_call_worker::NoParamReturnVector4(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("NoParamReturnMatrix4x4", [](SimpleTests::Test& test) { - auto expected = plg::mat4x4{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - auto result = cross_call_worker::NoParamReturnMatrix4x4(); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); + _tests.Add("NoParamReturnVector2", [](SimpleTests::Test &test) { + auto expected = plg::vec2{1, 2}; + auto result = cross_call_worker::NoParamReturnVector2(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnVector3", [](SimpleTests::Test &test) { + auto expected = plg::vec3{1, 2, 3}; + auto result = cross_call_worker::NoParamReturnVector3(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnVector4", [](SimpleTests::Test &test) { + auto expected = plg::vec4{1, 2, 3, 4}; + auto result = cross_call_worker::NoParamReturnVector4(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("NoParamReturnMatrix4x4", [](SimpleTests::Test &test) { + auto expected = plg::mat4x4{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + auto result = cross_call_worker::NoParamReturnMatrix4x4(); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); #endif// TEST_CASES & TEST_NO_PARAM_ONLY_RETURN_VECTORS - } + } - void ParamsNoRefs() { + void ParamsNoRefs() { #if TEST_CASES & TEST_PARAMS_NO_REFS - constexpr const int32_t intValue = 42; - constexpr float floatValue = 3.14f; - constexpr const double doubleValue = 6.28; - constexpr const char charValue = 'A'; - constexpr const char16_t char16Value = 'B'; - constexpr const int16_t shortValue = 10; - constexpr void* const ptrValue = nullptr; - - _tests.Add("Param1", [](SimpleTests::Test& /*test*/) { - cross_call_worker::Param1(intValue); - }); - - _tests.Add("Param2", [](SimpleTests::Test& /*test*/) { - cross_call_worker::Param2(intValue, floatValue); - }); - - _tests.Add("Param3", [](SimpleTests::Test& /*test*/) { - cross_call_worker::Param3(intValue, floatValue, doubleValue); - }); - - _tests.Add("Param4", [&](SimpleTests::Test& /*test*/) { - const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; - cross_call_worker::Param4(intValue, floatValue, doubleValue, vector4Value); - }); - - _tests.Add("Param5", [&](SimpleTests::Test& /*test*/) { - const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; - const plg::vector longListValue = {100, 200, 300}; - cross_call_worker::Param5(intValue, floatValue, doubleValue, vector4Value, longListValue); - }); - - _tests.Add("Param6", [&](SimpleTests::Test& /*test*/) { - const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; - const plg::vector longListValue = {100, 200, 300}; - cross_call_worker::Param6(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue); - }); - - _tests.Add("Param7", [=](SimpleTests::Test& /*test*/) { - const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; - const plg::vector longListValue = {100, 200, 300}; - const plg::string stringValue = "Hello"; - cross_call_worker::Param7(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, stringValue); - }); - - _tests.Add("Param9", [=](SimpleTests::Test& /*test*/) { - const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; - const plg::vector longListValue = {100, 200, 300}; - const plg::string stringValue = "Hello"; - cross_call_worker::Param9(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, stringValue, char16Value, shortValue); - }); - - _tests.Add("Param10", [=](SimpleTests::Test& /*test*/) { - const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; - const plg::vector longListValue = {100, 200, 300}; - const plg::string stringValue = "Hello"; - cross_call_worker::Param10(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, stringValue, char16Value, shortValue, ptrValue); - }); + constexpr const int32_t intValue = 42; + constexpr float floatValue = 3.14f; + constexpr const double doubleValue = 6.28; + constexpr const char charValue = 'A'; + constexpr const char16_t char16Value = 'B'; + constexpr const int16_t shortValue = 10; + constexpr void *const ptrValue = nullptr; + + _tests.Add("Param1", [](SimpleTests::Test & /*test*/) { + cross_call_worker::Param1(intValue); + }); + + _tests.Add("Param2", [](SimpleTests::Test & /*test*/) { + cross_call_worker::Param2(intValue, floatValue); + }); + + _tests.Add("Param3", [](SimpleTests::Test & /*test*/) { + cross_call_worker::Param3(intValue, floatValue, doubleValue); + }); + + _tests.Add("Param4", [&](SimpleTests::Test & /*test*/) { + const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; + cross_call_worker::Param4(intValue, floatValue, doubleValue, vector4Value); + }); + + _tests.Add("Param5", [&](SimpleTests::Test & /*test*/) { + const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; + const plg::vector longListValue = {100, 200, 300}; + cross_call_worker::Param5(intValue, floatValue, doubleValue, vector4Value, longListValue); + }); + + _tests.Add("Param6", [&](SimpleTests::Test & /*test*/) { + const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; + const plg::vector longListValue = {100, 200, 300}; + cross_call_worker::Param6(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue); + }); + + _tests.Add("Param7", [=](SimpleTests::Test & /*test*/) { + const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; + const plg::vector longListValue = {100, 200, 300}; + const plg::string stringValue = "Hello"; + cross_call_worker::Param7(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, + stringValue); + }); + + _tests.Add("Param9", [=](SimpleTests::Test & /*test*/) { + const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; + const plg::vector longListValue = {100, 200, 300}; + const plg::string stringValue = "Hello"; + cross_call_worker::Param9(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, + stringValue, char16Value, shortValue); + }); + + _tests.Add("Param10", [=](SimpleTests::Test & /*test*/) { + const plg::vec4 vector4Value{1.0f, 2.0f, 3.0f, 4.0f}; + const plg::vector longListValue = {100, 200, 300}; + const plg::string stringValue = "Hello"; + cross_call_worker::Param10(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, + stringValue, char16Value, shortValue, ptrValue); + }); #endif // TEST_CASES & TEST_PARAMS_NO_REFS - } + } - void ParamsWithRefs() { + void ParamsWithRefs() { #if TEST_CASES & TEST_PARAMS_WITH_REFS - _tests.Add("ParamRef1", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{42}; - int32_t intValue{}; - cross_call_worker::ParamRef1(intValue); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - }); - _tests.Add("ParamRef2", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{10}; - const auto floatExpected = 3.14f; - int32_t intValue{}; - float floatValue{}; - cross_call_worker::ParamRef2(intValue, floatValue); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - if (floatValue != floatExpected) { - test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); - } - }); - _tests.Add("ParamRef3", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{-20}; - const auto floatExpected = 2.718f; - const auto doubleExpected = 3.14159; - int32_t intValue{}; - float floatValue{}; - double doubleValue{}; - cross_call_worker::ParamRef3(intValue, floatValue, doubleValue); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - if (floatValue != floatExpected) { - test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); - } - if (doubleValue != doubleExpected) { - test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); - } - }); - _tests.Add("ParamRef4", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{100}; - const auto floatExpected = -5.55f; - const auto doubleExpected = 1.618; - const auto vector4Expected = plg::vec4{1.0f, 2.0f, 3.0f, 4.0f}; - int32_t intValue{}; - float floatValue{}; - double doubleValue{}; - plg::vec4 vector4Value{}; - cross_call_worker::ParamRef4(intValue, floatValue, doubleValue, vector4Value); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - if (floatValue != floatExpected) { - test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); - } - if (doubleValue != doubleExpected) { - test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); - } - if (vector4Value != vector4Expected) { + _tests.Add("ParamRef1", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{42}; + int32_t intValue{}; + cross_call_worker::ParamRef1(intValue); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + }); + _tests.Add("ParamRef2", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{10}; + const auto floatExpected = 3.14f; + int32_t intValue{}; + float floatValue{}; + cross_call_worker::ParamRef2(intValue, floatValue); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + if (floatValue != floatExpected) { + test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); + } + }); + _tests.Add("ParamRef3", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{-20}; + const auto floatExpected = 2.718f; + const auto doubleExpected = 3.14159; + int32_t intValue{}; + float floatValue{}; + double doubleValue{}; + cross_call_worker::ParamRef3(intValue, floatValue, doubleValue); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + if (floatValue != floatExpected) { + test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); + } + if (doubleValue != doubleExpected) { + test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); + } + }); + _tests.Add("ParamRef4", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{100}; + const auto floatExpected = -5.55f; + const auto doubleExpected = 1.618; + const auto vector4Expected = plg::vec4{1.0f, 2.0f, 3.0f, 4.0f}; + int32_t intValue{}; + float floatValue{}; + double doubleValue{}; + plg::vec4 vector4Value{}; + cross_call_worker::ParamRef4(intValue, floatValue, doubleValue, vector4Value); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + if (floatValue != floatExpected) { + test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); + } + if (doubleValue != doubleExpected) { + test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); + } + if (vector4Value != vector4Expected) { test.Fail(std::format("Wrong vector4Value param {}, expected {}", vector4Value, vector4Expected)); - } - }); - _tests.Add("ParamRef5", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{500}; - const auto floatExpected = -10.5f; - const auto doubleExpected = 2.71828; - const auto vector4Expected = plg::vec4{-1.0f, -2.0f, -3.0f, -4.0f}; - const auto longListExpected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1}; - int32_t intValue{}; - float floatValue{}; - double doubleValue{}; - plg::vec4 vector4Value{}; - plg::vector longListValue{}; - cross_call_worker::ParamRef5(intValue, floatValue, doubleValue, vector4Value, longListValue); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - if (floatValue != floatExpected) { - test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); - } - if (doubleValue != doubleExpected) { - test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); - } - if (vector4Value != vector4Expected) { + } + }); + _tests.Add("ParamRef5", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{500}; + const auto floatExpected = -10.5f; + const auto doubleExpected = 2.71828; + const auto vector4Expected = plg::vec4{-1.0f, -2.0f, -3.0f, -4.0f}; + const auto longListExpected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1}; + int32_t intValue{}; + float floatValue{}; + double doubleValue{}; + plg::vec4 vector4Value{}; + plg::vector longListValue{}; + cross_call_worker::ParamRef5(intValue, floatValue, doubleValue, vector4Value, longListValue); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + if (floatValue != floatExpected) { + test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); + } + if (doubleValue != doubleExpected) { + test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); + } + if (vector4Value != vector4Expected) { test.Fail(std::format("Wrong vector4Value param {}, expected {}", vector4Value, vector4Expected)); - } - if (longListValue != longListExpected) { - test.Fail(std::format("Wrong longListValue param {}, expected {}", longListValue, longListExpected)); - } - }); - _tests.Add("ParamRef6", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{750}; - const auto floatExpected = 20.0f; - const auto doubleExpected = 1.23456; - const auto vector4Expected = plg::vec4{10.0f, 20.0f, 30.0f, 40.0f}; - const auto longListExpected = plg::vector{-6, -5, -4}; - const auto charExpected = 'Z'; - int32_t intValue{}; - float floatValue{}; - double doubleValue{}; - plg::vec4 vector4Value{}; - plg::vector longListValue{}; - char charValue{}; - cross_call_worker::ParamRef6(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - if (floatValue != floatExpected) { - test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); - } - if (doubleValue != doubleExpected) { - test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); - } - if (vector4Value != vector4Expected) { + } + if (longListValue != longListExpected) { + test.Fail(std::format("Wrong longListValue param {}, expected {}", longListValue, longListExpected)); + } + }); + _tests.Add("ParamRef6", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{750}; + const auto floatExpected = 20.0f; + const auto doubleExpected = 1.23456; + const auto vector4Expected = plg::vec4{10.0f, 20.0f, 30.0f, 40.0f}; + const auto longListExpected = plg::vector{-6, -5, -4}; + const auto charExpected = 'Z'; + int32_t intValue{}; + float floatValue{}; + double doubleValue{}; + plg::vec4 vector4Value{}; + plg::vector longListValue{}; + char charValue{}; + cross_call_worker::ParamRef6(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + if (floatValue != floatExpected) { + test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); + } + if (doubleValue != doubleExpected) { + test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); + } + if (vector4Value != vector4Expected) { test.Fail(std::format("Wrong vector4Value param {}, expected {}", vector4Value, vector4Expected)); - } - if (longListValue != longListExpected) { + } + if (longListValue != longListExpected) { test.Fail(std::format("Wrong longListValue param {}, expected {}", longListValue, longListExpected)); - } - if (charValue != charExpected) { - test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), static_cast(charExpected))); - } - }); - _tests.Add("ParamRef7", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{-1000}; - const auto floatExpected = 3.0f; - const auto doubleExpected = -1; - const auto vector4Expected = plg::vec4{100.0f, 200.0f, 300.0f, 400.0f}; - const auto longListExpected = plg::vector{-6, -5, -4, -3}; - const auto charExpected = 'Y'; - const auto stringExpected = plg::string{"Hello, World!"}; - int32_t intValue{}; - float floatValue{}; - double doubleValue{}; - plg::vec4 vector4Value{}; - plg::vector longListValue{}; - char charValue{}; - plg::string stringValue{}; - cross_call_worker::ParamRef7(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, stringValue); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - if (floatValue != floatExpected) { - test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); - } - if (doubleValue != doubleExpected) { - test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); - } - if (vector4Value != vector4Expected) { - test.Fail(std::format("Wrong vector4Value param {}, expected {}", vector4Value, vector4Expected)); - } - if (longListValue != longListExpected) { + } + if (charValue != charExpected) { + test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), + static_cast(charExpected))); + } + }); + _tests.Add("ParamRef7", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{-1000}; + const auto floatExpected = 3.0f; + const auto doubleExpected = -1; + const auto vector4Expected = plg::vec4{100.0f, 200.0f, 300.0f, 400.0f}; + const auto longListExpected = plg::vector{-6, -5, -4, -3}; + const auto charExpected = 'Y'; + const auto stringExpected = plg::string{"Hello, World!"}; + int32_t intValue{}; + float floatValue{}; + double doubleValue{}; + plg::vec4 vector4Value{}; + plg::vector longListValue{}; + char charValue{}; + plg::string stringValue{}; + cross_call_worker::ParamRef7(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, + stringValue); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + if (floatValue != floatExpected) { + test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); + } + if (doubleValue != doubleExpected) { + test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); + } + if (vector4Value != vector4Expected) { + test.Fail(std::format("Wrong vector4Value param {}, expected {}", vector4Value, vector4Expected)); + } + if (longListValue != longListExpected) { test.Fail(std::format("Wrong longListValue param {}, expected {}", longListValue, longListExpected)); - } - if (charValue != charExpected) { - test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), static_cast(charExpected))); - } - if (stringValue != stringExpected) { - test.Fail(std::format("Wrong stringValue param '{}', expected '{}'", stringValue, stringExpected)); - } - }); - _tests.Add("ParamRef8", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{999}; - const auto floatExpected = -7.5f; - const auto doubleExpected = 0.123456; - const auto vector4Expected = plg::vec4{-100.0f, -200.0f, -300.0f, -400.0f}; - const auto longListExpected = plg::vector{-6, -5, -4, -3, -2, -1}; - const auto charExpected = 'X'; - const auto stringExpected = plg::string{"Goodbye, World!"}; - const auto char16Expected = 'A'; - int32_t intValue{}; - float floatValue{}; - double doubleValue{}; - plg::vec4 vector4Value{}; - plg::vector longListValue{}; - char charValue{}; - plg::string stringValue{}; - char16_t char16Value{}; - cross_call_worker::ParamRef8(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, stringValue, char16Value); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - if (floatValue != floatExpected) { - test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); - } - if (doubleValue != doubleExpected) { - test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); - } - if (vector4Value != vector4Expected) { + } + if (charValue != charExpected) { + test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), + static_cast(charExpected))); + } + if (stringValue != stringExpected) { + test.Fail(std::format("Wrong stringValue param '{}', expected '{}'", stringValue, stringExpected)); + } + }); + _tests.Add("ParamRef8", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{999}; + const auto floatExpected = -7.5f; + const auto doubleExpected = 0.123456; + const auto vector4Expected = plg::vec4{-100.0f, -200.0f, -300.0f, -400.0f}; + const auto longListExpected = plg::vector{-6, -5, -4, -3, -2, -1}; + const auto charExpected = 'X'; + const auto stringExpected = plg::string{"Goodbye, World!"}; + const auto char16Expected = 'A'; + int32_t intValue{}; + float floatValue{}; + double doubleValue{}; + plg::vec4 vector4Value{}; + plg::vector longListValue{}; + char charValue{}; + plg::string stringValue{}; + char16_t char16Value{}; + cross_call_worker::ParamRef8(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, + stringValue, char16Value); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + if (floatValue != floatExpected) { + test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); + } + if (doubleValue != doubleExpected) { + test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); + } + if (vector4Value != vector4Expected) { test.Fail(std::format("Wrong vector4Value param {}, expected {}", vector4Value, vector4Expected)); - } - if (longListValue != longListExpected) { + } + if (longListValue != longListExpected) { test.Fail(std::format("Wrong longListValue param {}, expected {}", longListValue, longListExpected)); - } - if (charValue != charExpected) { - test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), static_cast(charExpected))); - } - if (stringValue != stringExpected) { - test.Fail(std::format("Wrong stringValue param '{}', expected '{}'", stringValue, stringExpected)); - } - if (char16Value != char16Expected) { - test.Fail(std::format("Wrong char16Value param {}, expected {}", static_cast(char16Value), static_cast(char16Expected))); - } - }); - _tests.Add("ParamRef9", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{-1234}; - const auto floatExpected = 123.45f; - const auto doubleExpected = -678.9; - const auto vector4Expected = plg::vec4{987.65f, 432.1f, 123.456f, 789.123f}; - const auto longListExpected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1, 5, 9}; - const auto charExpected = 'W'; - const auto stringExpected = plg::string{"Testing, 1 2 3"}; - const auto char16Expected = 'B'; - const auto shortExpected = int16_t{42}; - int32_t intValue{}; - float floatValue{}; - double doubleValue{}; - plg::vec4 vector4Value{}; - plg::vector longListValue{}; - char charValue{}; - plg::string stringValue{}; - char16_t char16Value{}; - int16_t shortValue{}; - cross_call_worker::ParamRef9(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, stringValue, char16Value, shortValue); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - if (floatValue != floatExpected) { - test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); - } - if (doubleValue != doubleExpected) { - test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); - } - if (vector4Value != vector4Expected) { + } + if (charValue != charExpected) { + test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), + static_cast(charExpected))); + } + if (stringValue != stringExpected) { + test.Fail(std::format("Wrong stringValue param '{}', expected '{}'", stringValue, stringExpected)); + } + if (char16Value != char16Expected) { + test.Fail(std::format("Wrong char16Value param {}, expected {}", static_cast(char16Value), + static_cast(char16Expected))); + } + }); + _tests.Add("ParamRef9", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{-1234}; + const auto floatExpected = 123.45f; + const auto doubleExpected = -678.9; + const auto vector4Expected = plg::vec4{987.65f, 432.1f, 123.456f, 789.123f}; + const auto longListExpected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1, 5, 9}; + const auto charExpected = 'W'; + const auto stringExpected = plg::string{"Testing, 1 2 3"}; + const auto char16Expected = 'B'; + const auto shortExpected = int16_t{42}; + int32_t intValue{}; + float floatValue{}; + double doubleValue{}; + plg::vec4 vector4Value{}; + plg::vector longListValue{}; + char charValue{}; + plg::string stringValue{}; + char16_t char16Value{}; + int16_t shortValue{}; + cross_call_worker::ParamRef9(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, + stringValue, char16Value, shortValue); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + if (floatValue != floatExpected) { + test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); + } + if (doubleValue != doubleExpected) { + test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); + } + if (vector4Value != vector4Expected) { test.Fail(std::format("Wrong vector4Value param {}, expected {}", vector4Value, vector4Expected)); - } - if (longListValue != longListExpected) { + } + if (longListValue != longListExpected) { test.Fail(std::format("Wrong longListValue param {}, expected {}", longListValue, longListExpected)); - } - if (charValue != charExpected) { - test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), static_cast(charExpected))); - } - if (stringValue != stringExpected) { - test.Fail(std::format("Wrong stringValue param '{}', expected '{}'", stringValue, stringExpected)); - } - if (char16Value != char16Expected) { - test.Fail(std::format("Wrong char16Value param {}, expected {}", static_cast(char16Value), static_cast(char16Expected))); - } - if (shortValue != shortExpected) { - test.Fail(std::format("Wrong shortValue param {}, expected {}", shortValue, shortExpected)); - } - }); - _tests.Add("ParamRef10", [](SimpleTests::Test& test) { - const auto intExpected = int32_t{987}; - const auto floatExpected = -0.123f; - const auto doubleExpected = 456.789; - const auto vector4Expected = plg::vec4{-123.456f, 0.987f, 654.321f, -789.123f}; - const auto longListExpected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1, 5, 9, 4, -7}; - const auto charExpected = 'V'; - const auto stringExpected = plg::string{"Another string"}; - const auto char16Expected = 'C'; - const auto shortExpected = int16_t{-444}; - const auto ptrExpected = reinterpret_cast(0x12345678); - int32_t intValue{}; - float floatValue{}; - double doubleValue{}; - plg::vec4 vector4Value{}; - plg::vector longListValue{}; - char charValue{}; - plg::string stringValue{}; - char16_t char16Value{}; - int16_t shortValue{}; - void* ptrValue{}; - cross_call_worker::ParamRef10(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, stringValue, char16Value, shortValue, ptrValue); - if (intValue != intExpected) { - test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); - } - if (floatValue != floatExpected) { - test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); - } - if (doubleValue != doubleExpected) { - test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); - } - if (vector4Value != vector4Expected) { + } + if (charValue != charExpected) { + test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), + static_cast(charExpected))); + } + if (stringValue != stringExpected) { + test.Fail(std::format("Wrong stringValue param '{}', expected '{}'", stringValue, stringExpected)); + } + if (char16Value != char16Expected) { + test.Fail(std::format("Wrong char16Value param {}, expected {}", static_cast(char16Value), + static_cast(char16Expected))); + } + if (shortValue != shortExpected) { + test.Fail(std::format("Wrong shortValue param {}, expected {}", shortValue, shortExpected)); + } + }); + _tests.Add("ParamRef10", [](SimpleTests::Test &test) { + const auto intExpected = int32_t{987}; + const auto floatExpected = -0.123f; + const auto doubleExpected = 456.789; + const auto vector4Expected = plg::vec4{-123.456f, 0.987f, 654.321f, -789.123f}; + const auto longListExpected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1, 5, 9, 4, -7}; + const auto charExpected = 'V'; + const auto stringExpected = plg::string{"Another string"}; + const auto char16Expected = 'C'; + const auto shortExpected = int16_t{-444}; + const auto ptrExpected = reinterpret_cast(0x12345678); + int32_t intValue{}; + float floatValue{}; + double doubleValue{}; + plg::vec4 vector4Value{}; + plg::vector longListValue{}; + char charValue{}; + plg::string stringValue{}; + char16_t char16Value{}; + int16_t shortValue{}; + void *ptrValue{}; + cross_call_worker::ParamRef10(intValue, floatValue, doubleValue, vector4Value, longListValue, charValue, + stringValue, char16Value, shortValue, ptrValue); + if (intValue != intExpected) { + test.Fail(std::format("Wrong intValue param {}, expected {}", intValue, intExpected)); + } + if (floatValue != floatExpected) { + test.Fail(std::format("Wrong floatValue param {}, expected {}", floatValue, floatExpected)); + } + if (doubleValue != doubleExpected) { + test.Fail(std::format("Wrong doubleValue param {}, expected {}", doubleValue, doubleExpected)); + } + if (vector4Value != vector4Expected) { test.Fail(std::format("Wrong vector4Value param {}, expected {}", vector4Value, vector4Expected)); - } - if (longListValue != longListExpected) { + } + if (longListValue != longListExpected) { test.Fail(std::format("Wrong longListValue param {}, expected {}", longListValue, longListExpected)); - } - if (charValue != charExpected) { - test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), static_cast(charExpected))); - } - if (stringValue != stringExpected) { - test.Fail(std::format("Wrong stringValue param '{}', expected '{}'", stringValue, stringExpected)); - } - if (char16Value != char16Expected) { - test.Fail(std::format("Wrong char16Value param {}, expected {}", static_cast(char16Value), static_cast(char16Expected))); - } - if (shortValue != shortExpected) { - test.Fail(std::format("Wrong shortValue param {}, expected {}", shortValue, shortExpected)); - } - if (ptrValue != ptrExpected) { - test.Fail(std::format("Wrong ptrValue param {}, expected {}", ptrValue, ptrExpected)); - } - }); + } + if (charValue != charExpected) { + test.Fail(std::format("Wrong charValue param {}, expected {}", static_cast(charValue), + static_cast(charExpected))); + } + if (stringValue != stringExpected) { + test.Fail(std::format("Wrong stringValue param '{}', expected '{}'", stringValue, stringExpected)); + } + if (char16Value != char16Expected) { + test.Fail(std::format("Wrong char16Value param {}, expected {}", static_cast(char16Value), + static_cast(char16Expected))); + } + if (shortValue != shortExpected) { + test.Fail(std::format("Wrong shortValue param {}, expected {}", shortValue, shortExpected)); + } + if (ptrValue != ptrExpected) { + test.Fail(std::format("Wrong ptrValue param {}, expected {}", ptrValue, ptrExpected)); + } + }); #endif// TEST_CASES & TEST_PARAMS_WITH_REFS - } + } - void ParamsRefVectors() { + void ParamsRefVectors() { #if TEST_CASES & TEST_PARAMS_REF_ARRAYS - _tests.Add("ParamRefArrays", [](SimpleTests::Test& test) { - const auto boolArrayExpected = plg::vector{true}; - const auto char8ArrayExpected = plg::vector{'a', 'b', 'c'}; - const auto char16ArrayExpected = plg::vector{'d', 'e', 'f'}; - const auto sbyteArrayExpected = plg::vector{-3, -2, -1, 0, 1, 2, 3}; - const auto shortArrayExpected = plg::vector{-4, -3, -2, -1, 0, 1, 2, 3, 4}; - const auto intArrayExpected = plg::vector{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; - const auto longArrayExpected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6}; - const auto byteArrayExpected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7}; - const auto ushortArrayExpected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8}; - const auto uintArrayExpected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - const auto ulongArrayExpected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - const auto intPtrArrayExpected = plg::vector{reinterpret_cast(0), reinterpret_cast(1), reinterpret_cast(2)}; - const auto floatArrayExpected = plg::vector{-12.34f, 0.0f, 12.34f}; - const auto doubleArrayExpected = plg::vector{-12.345, 0.0, 12.345}; - const auto stringArrayExpected = plg::vector{"1", "12", "123", "1234", "12345", "123456"}; - plg::vector boolArray{true, false, true}; - plg::vector char8Array{'A', 'B', 'C'}; - plg::vector char16Array{'D', 'E', 'F'}; - plg::vector sbyteArray{-1, -2, -3}; - plg::vector shortArray{10, 20, 30}; - plg::vector intArray{100, 200, 300}; - plg::vector longArray{1000, 2000, 3000}; - plg::vector byteArray{1, 2, 3}; - plg::vector ushortArray{1000, 2000, 3000}; - plg::vector uintArray{10000, 20000, 30000}; - plg::vector ulongArray{100000, 200000, 300000}; - plg::vector intPtrArray{nullptr, nullptr, nullptr}; - plg::vector floatArray{1.1f, 2.2f, 3.3f}; - plg::vector doubleArray{1.1, 2.2, 3.3}; - plg::vector stringArray{"Hello", "World", "!"}; - cross_call_worker::ParamRefVectors(boolArray, char8Array, char16Array, sbyteArray, shortArray, intArray, longArray, - byteArray, ushortArray, uintArray, ulongArray, intPtrArray, floatArray, doubleArray, stringArray); - if (boolArray != boolArrayExpected) { - test.Fail(std::format("Wrong boolArray param {}, expected {}", char8Array, char8ArrayExpected)); - } - if (char8Array != char8ArrayExpected) { - test.Fail(std::format("Wrong char8Array array {}, expected {}", char8Array, char8ArrayExpected)); - } - if (char16Array != char16ArrayExpected) { - test.Fail(std::format("Wrong char16Array array {}, expected {}", char16Array, char16ArrayExpected)); - } - if (sbyteArray != sbyteArrayExpected) { - test.Fail(std::format("Wrong sbyteArray array {}, expected {}", sbyteArray, sbyteArrayExpected)); - } - if (shortArray != shortArrayExpected) { - test.Fail(std::format("Wrong shortArray array {}, expected {}", shortArray, shortArrayExpected)); - } - if (intArray != intArrayExpected) { - test.Fail(std::format("Wrong intArray array {}, expected {}", intArray, intArrayExpected)); - } - if (longArray != longArrayExpected) { - test.Fail(std::format("Wrong longArray array {}, expected {}", longArray, longArrayExpected)); - } - if (byteArray != byteArrayExpected) { - test.Fail(std::format("Wrong byteArray array {}, expected {}", byteArray, byteArrayExpected)); - } - if (ushortArray != ushortArrayExpected) { - test.Fail(std::format("Wrong ushortArray array {}, expected {}", ushortArray, ushortArrayExpected)); - } - if (uintArray != uintArrayExpected) { - test.Fail(std::format("Wrong uintArray array {}, expected {}", uintArray, uintArrayExpected)); - } - if (ulongArray != ulongArrayExpected) { - test.Fail(std::format("Wrong ulongArray array {}, expected {}", ulongArray, ulongArrayExpected)); - } - if (intPtrArray != intPtrArrayExpected) { - test.Fail(std::format("Wrong intPtrArray array {}, expected {}", intPtrArray, intPtrArrayExpected)); - } - if (floatArray != floatArrayExpected) { - test.Fail(std::format("Wrong floatArray array {}, expected {}", floatArray, floatArrayExpected)); - } - if (doubleArray != doubleArrayExpected) { - test.Fail(std::format("Wrong doubleArray array {}, expected {}", doubleArray, doubleArrayExpected)); - } - if (stringArray != stringArrayExpected) { - test.Fail(std::format("Wrong stringArray array {}, expected {}", stringArray, stringArrayExpected)); - } - }); + _tests.Add("ParamRefArrays", [](SimpleTests::Test &test) { + const auto boolArrayExpected = plg::vector{true}; + const auto char8ArrayExpected = plg::vector{'a', 'b', 'c'}; + const auto char16ArrayExpected = plg::vector{'d', 'e', 'f'}; + const auto sbyteArrayExpected = plg::vector{-3, -2, -1, 0, 1, 2, 3}; + const auto shortArrayExpected = plg::vector{-4, -3, -2, -1, 0, 1, 2, 3, 4}; + const auto intArrayExpected = plg::vector{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + const auto longArrayExpected = plg::vector{-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6}; + const auto byteArrayExpected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7}; + const auto ushortArrayExpected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8}; + const auto uintArrayExpected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + const auto ulongArrayExpected = plg::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + const auto intPtrArrayExpected = plg::vector{ + reinterpret_cast(0), reinterpret_cast(1), reinterpret_cast(2) + }; + const auto floatArrayExpected = plg::vector{-12.34f, 0.0f, 12.34f}; + const auto doubleArrayExpected = plg::vector{-12.345, 0.0, 12.345}; + const auto stringArrayExpected = plg::vector{"1", "12", "123", "1234", "12345", "123456"}; + plg::vector boolArray{true, false, true}; + plg::vector char8Array{'A', 'B', 'C'}; + plg::vector char16Array{'D', 'E', 'F'}; + plg::vector sbyteArray{-1, -2, -3}; + plg::vector shortArray{10, 20, 30}; + plg::vector intArray{100, 200, 300}; + plg::vector longArray{1000, 2000, 3000}; + plg::vector byteArray{1, 2, 3}; + plg::vector ushortArray{1000, 2000, 3000}; + plg::vector uintArray{10000, 20000, 30000}; + plg::vector ulongArray{100000, 200000, 300000}; + plg::vector intPtrArray{nullptr, nullptr, nullptr}; + plg::vector floatArray{1.1f, 2.2f, 3.3f}; + plg::vector doubleArray{1.1, 2.2, 3.3}; + plg::vector stringArray{"Hello", "World", "!"}; + cross_call_worker::ParamRefVectors(boolArray, char8Array, char16Array, sbyteArray, shortArray, intArray, + longArray, + byteArray, ushortArray, uintArray, ulongArray, intPtrArray, floatArray, + doubleArray, stringArray); + if (boolArray != boolArrayExpected) { + test.Fail(std::format("Wrong boolArray param {}, expected {}", char8Array, char8ArrayExpected)); + } + if (char8Array != char8ArrayExpected) { + test.Fail(std::format("Wrong char8Array array {}, expected {}", char8Array, char8ArrayExpected)); + } + if (char16Array != char16ArrayExpected) { + test.Fail(std::format("Wrong char16Array array {}, expected {}", char16Array, char16ArrayExpected)); + } + if (sbyteArray != sbyteArrayExpected) { + test.Fail(std::format("Wrong sbyteArray array {}, expected {}", sbyteArray, sbyteArrayExpected)); + } + if (shortArray != shortArrayExpected) { + test.Fail(std::format("Wrong shortArray array {}, expected {}", shortArray, shortArrayExpected)); + } + if (intArray != intArrayExpected) { + test.Fail(std::format("Wrong intArray array {}, expected {}", intArray, intArrayExpected)); + } + if (longArray != longArrayExpected) { + test.Fail(std::format("Wrong longArray array {}, expected {}", longArray, longArrayExpected)); + } + if (byteArray != byteArrayExpected) { + test.Fail(std::format("Wrong byteArray array {}, expected {}", byteArray, byteArrayExpected)); + } + if (ushortArray != ushortArrayExpected) { + test.Fail(std::format("Wrong ushortArray array {}, expected {}", ushortArray, ushortArrayExpected)); + } + if (uintArray != uintArrayExpected) { + test.Fail(std::format("Wrong uintArray array {}, expected {}", uintArray, uintArrayExpected)); + } + if (ulongArray != ulongArrayExpected) { + test.Fail(std::format("Wrong ulongArray array {}, expected {}", ulongArray, ulongArrayExpected)); + } + if (intPtrArray != intPtrArrayExpected) { + test.Fail(std::format("Wrong intPtrArray array {}, expected {}", intPtrArray, intPtrArrayExpected)); + } + if (floatArray != floatArrayExpected) { + test.Fail(std::format("Wrong floatArray array {}, expected {}", floatArray, floatArrayExpected)); + } + if (doubleArray != doubleArrayExpected) { + test.Fail(std::format("Wrong doubleArray array {}, expected {}", doubleArray, doubleArrayExpected)); + } + if (stringArray != stringArrayExpected) { + test.Fail(std::format("Wrong stringArray array {}, expected {}", stringArray, stringArrayExpected)); + } + }); #endif// TEST_CASES & TEST_PARAMS_REF_ARRAYS - } + } - void ParamsAllPrimitives() { + void ParamsAllPrimitives() { #if TEST_CASES & TEST_PARAMS_ALL_PRIMITIVES - _tests.Add("ParamAllPrimitives", [](SimpleTests::Test& test) { - const auto expected = int64_t{56}; - const auto boolValue = true; - const auto charValue = 'a'; - const auto char16Value = char16_t{'d'}; - const auto sbyteValue = int8_t{-3}; - const auto shortValue = int16_t{-4}; - const auto intValue = int32_t{-5}; - const auto longValue = int64_t{-6}; - const auto byteValue = uint8_t{7}; - const auto ushortValue = uint16_t{8}; - const auto uintValue = uint32_t{9}; - const auto ulongValue = uint64_t{10}; - const auto intPtrValue = reinterpret_cast(0); - const auto floatValue = 1.1f; - const auto doubleValue = 1.1; - const auto result = cross_call_worker::ParamAllPrimitives(boolValue, charValue, char16Value, sbyteValue, shortValue, intValue, longValue, - byteValue, ushortValue, uintValue, ulongValue, intPtrValue, floatValue, doubleValue); - if (result != expected) { - test.Fail(std::format("Wrong return {}, expected {}", result, expected)); - } - }); - _tests.Add("ParamEnum", [](SimpleTests::Test& test) { + _tests.Add("ParamAllPrimitives", [](SimpleTests::Test &test) { + const auto expected = int64_t{56}; + const auto boolValue = true; + const auto charValue = 'a'; + const auto char16Value = char16_t{'d'}; + const auto sbyteValue = int8_t{-3}; + const auto shortValue = int16_t{-4}; + const auto intValue = int32_t{-5}; + const auto longValue = int64_t{-6}; + const auto byteValue = uint8_t{7}; + const auto ushortValue = uint16_t{8}; + const auto uintValue = uint32_t{9}; + const auto ulongValue = uint64_t{10}; + const auto intPtrValue = reinterpret_cast(0); + const auto floatValue = 1.1f; + const auto doubleValue = 1.1; + const auto result = cross_call_worker::ParamAllPrimitives(boolValue, charValue, char16Value, sbyteValue, + shortValue, intValue, longValue, + byteValue, ushortValue, uintValue, ulongValue, + intPtrValue, floatValue, doubleValue); + if (result != expected) { + test.Fail(std::format("Wrong return {}, expected {}", result, expected)); + } + }); + _tests.Add("ParamEnum", [](SimpleTests::Test &test) { const auto expected = int64_t{10}; const auto enumValue = Example::Forth; const auto enumArrayValue = plg::vector{Example::First, Example::Second, Example::Third}; @@ -1345,7 +1440,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong return {}, expected {}", result, expected)); } }); - _tests.Add("ParamEnumRef", [](SimpleTests::Test& test) { + _tests.Add("ParamEnumRef", [](SimpleTests::Test &test) { const auto expected = int64_t{10}; const auto enumValueExpected = Example::Forth; const auto enumArrayValueExpected = plg::vector{Example::First, Example::Second, Example::Third}; @@ -1359,123 +1454,125 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong doubleArray array {}, expected {}", enumValue, enumValueExpected)); } if (enumArrayValue != enumArrayValueExpected) { - test.Fail(std::format("Wrong stringArray array {}, expected {}", enumArrayValue, enumArrayValueExpected)); + test.Fail( + std::format("Wrong stringArray array {}, expected {}", enumArrayValue, enumArrayValueExpected)); } }); #endif// TEST_CASES & TEST_PARAMS_ALL_PRIMITIVES - } + } - void ParamsFunctions() { + void ParamsFunctions() { #if TEST_CASES & TEST_PARAMS_FUNCTIONS - _tests.Add("CallFuncVoid", [](SimpleTests::Test&) { - cross_call_worker::CallFuncVoid(&MockVoid); + _tests.Add("CallFuncVoid", [](SimpleTests::Test &) { + cross_call_worker::CallFuncVoid(&MockVoid); }); - _tests.Add("CallFuncBool", [](SimpleTests::Test& test) { + _tests.Add("CallFuncBool", [](SimpleTests::Test &test) { const bool expected = MockBool(); // Adjust this if needed const auto result = cross_call_worker::CallFuncBool(&MockBool); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncChar8", [](SimpleTests::Test& test) { + _tests.Add("CallFuncChar8", [](SimpleTests::Test &test) { const char expected = MockChar8(); // Adjust this if needed const auto result = cross_call_worker::CallFuncChar8(&MockChar8); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncChar16", [](SimpleTests::Test& test) { + _tests.Add("CallFuncChar16", [](SimpleTests::Test &test) { const char16_t expected = MockChar16(); // Adjust this if needed const auto result = cross_call_worker::CallFuncChar16(&MockChar16); if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", static_cast(result), static_cast(expected))); + test.Fail(std::format("Wrong ref params return {}, expected {}", static_cast(result), + static_cast(expected))); } }); - _tests.Add("CallFuncInt8", [](SimpleTests::Test& test) { + _tests.Add("CallFuncInt8", [](SimpleTests::Test &test) { const int8_t expected = MockInt8(); // Adjust this if needed const auto result = cross_call_worker::CallFuncInt8(&MockInt8); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncInt16", [](SimpleTests::Test& test) { + _tests.Add("CallFuncInt16", [](SimpleTests::Test &test) { const int16_t expected = MockInt16(); // Adjust this if needed const auto result = cross_call_worker::CallFuncInt16(&MockInt16); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncInt32", [](SimpleTests::Test& test) { + _tests.Add("CallFuncInt32", [](SimpleTests::Test &test) { const int32_t expected = MockInt32(); // Adjust this if needed const auto result = cross_call_worker::CallFuncInt32(&MockInt32); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncInt64", [](SimpleTests::Test& test) { + _tests.Add("CallFuncInt64", [](SimpleTests::Test &test) { const int64_t expected = MockInt64(); // Adjust this if needed const auto result = cross_call_worker::CallFuncInt64(&MockInt64); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncUInt8", [](SimpleTests::Test& test) { + _tests.Add("CallFuncUInt8", [](SimpleTests::Test &test) { const uint8_t expected = MockUInt8(); // Adjust this if needed const auto result = cross_call_worker::CallFuncUInt8(&MockUInt8); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncUInt16", [](SimpleTests::Test& test) { + _tests.Add("CallFuncUInt16", [](SimpleTests::Test &test) { const uint16_t expected = MockUInt16(); // Adjust this if needed const auto result = cross_call_worker::CallFuncUInt16(&MockUInt16); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncUInt32", [](SimpleTests::Test& test) { + _tests.Add("CallFuncUInt32", [](SimpleTests::Test &test) { const uint32_t expected = MockUInt32(); // Adjust this if needed const auto result = cross_call_worker::CallFuncUInt32(&MockUInt32); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncUInt64", [](SimpleTests::Test& test) { + _tests.Add("CallFuncUInt64", [](SimpleTests::Test &test) { const uint64_t expected = MockUInt64(); // Adjust this if needed const auto result = cross_call_worker::CallFuncUInt64(&MockUInt64); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncPtr", [](SimpleTests::Test& test) { - const void* expected = MockPtr(); // Adjust this if needed + _tests.Add("CallFuncPtr", [](SimpleTests::Test &test) { + const void *expected = MockPtr(); // Adjust this if needed const auto result = cross_call_worker::CallFuncPtr(&MockPtr); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncFloat", [](SimpleTests::Test& test) { + _tests.Add("CallFuncFloat", [](SimpleTests::Test &test) { const float expected = MockFloat(); // Adjust this if needed const auto result = cross_call_worker::CallFuncFloat(&MockFloat); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncDouble", [](SimpleTests::Test& test) { + _tests.Add("CallFuncDouble", [](SimpleTests::Test &test) { const double expected = MockDouble(); // Adjust this if needed const auto result = cross_call_worker::CallFuncDouble(&MockDouble); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncString", [](SimpleTests::Test& test) { + _tests.Add("CallFuncString", [](SimpleTests::Test &test) { const plg::string expected = MockString(); // Adjust this if needed const auto result = cross_call_worker::CallFuncString(&MockString); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncAny", [](SimpleTests::Test& test) { + _tests.Add("CallFuncAny", [](SimpleTests::Test &test) { const plg::any expected = MockAny(); // Adjust this if needed const auto result = cross_call_worker::CallFuncAny(&MockAny); if (result.index() != expected.index() && std::format("{}", result) != std::format("{}", expected)) { @@ -1489,161 +1586,161 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } });*/ - _tests.Add("CallFuncBoolVector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncBoolVector", [](SimpleTests::Test &test) { const plg::vector expected = MockBoolVector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncBoolVector(&MockBoolVector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncChar8Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncChar8Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockChar8Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncChar8Vector(&MockChar8Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncChar16Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncChar16Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockChar16Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncChar16Vector(&MockChar16Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncInt8Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncInt8Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockInt8Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncInt8Vector(&MockInt8Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncInt16Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncInt16Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockInt16Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncInt16Vector(&MockInt16Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncInt32Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncInt32Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockInt32Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncInt32Vector(&MockInt32Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncInt64Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncInt64Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockInt64Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncInt64Vector(&MockInt64Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncUInt8Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncUInt8Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockUInt8Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncUInt8Vector(&MockUInt8Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncUInt16Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncUInt16Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockUInt16Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncUInt16Vector(&MockUInt16Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncUInt32Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncUInt32Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockUInt32Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncUInt32Vector(&MockUInt32Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncUInt64Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncUInt64Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockUInt64Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncUInt64Vector(&MockUInt64Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncPtrVector", [](SimpleTests::Test& test) { - const plg::vector expected = MockPtrVector(); // Adjust this if needed + _tests.Add("CallFuncPtrVector", [](SimpleTests::Test &test) { + const plg::vector expected = MockPtrVector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncPtrVector(&MockPtrVector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncFloatVector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncFloatVector", [](SimpleTests::Test &test) { const plg::vector expected = MockFloatVector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncFloatVector(&MockFloatVector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncDoubleVector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncDoubleVector", [](SimpleTests::Test &test) { const plg::vector expected = MockDoubleVector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncDoubleVector(&MockDoubleVector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncStringVector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncStringVector", [](SimpleTests::Test &test) { const plg::vector expected = MockStringVector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncStringVector(&MockStringVector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncVec2Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncVec2Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockVec2Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncVec2Vector(&MockVec2Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncVec3Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncVec3Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockVec3Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncVec3Vector(&MockVec3Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncVec4Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncVec4Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockVec4Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncVec4Vector(&MockVec4Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncMat4x4Vector", [](SimpleTests::Test& test) { + _tests.Add("CallFuncMat4x4Vector", [](SimpleTests::Test &test) { const plg::vector expected = MockMat4x4Vector(); // Adjust this if needed const auto result = cross_call_worker::CallFuncMat4x4Vector(&MockMat4x4Vector); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncVec2", [](SimpleTests::Test& test) { + _tests.Add("CallFuncVec2", [](SimpleTests::Test &test) { const plg::vec2 expected = MockVec2(); // Adjust this if needed const auto result = cross_call_worker::CallFuncVec2(&MockVec2); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncVec3", [](SimpleTests::Test& test) { + _tests.Add("CallFuncVec3", [](SimpleTests::Test &test) { const plg::vec3 expected = MockVec3(); // Adjust this if needed const auto result = cross_call_worker::CallFuncVec3(&MockVec3); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncVec4", [](SimpleTests::Test& test) { + _tests.Add("CallFuncVec4", [](SimpleTests::Test &test) { const plg::vec4 expected = MockVec4(); // Adjust this if needed const auto result = cross_call_worker::CallFuncVec4(&MockVec4); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFuncMat4x4", [](SimpleTests::Test& test) { + _tests.Add("CallFuncMat4x4", [](SimpleTests::Test &test) { const plg::mat4x4 expected = MockMat4x4(); // Adjust this if needed const auto result = cross_call_worker::CallFuncMat4x4(&MockMat4x4); if (result != expected) { @@ -1651,7 +1748,7 @@ class CrossCallMaster final : public plg::IPluginEntry { } }); - _tests.Add("CallFunc1", [](SimpleTests::Test& test) { + _tests.Add("CallFunc1", [](SimpleTests::Test &test) { plg::vec3 vec{4.5f, 5.6f, 6.7f}; // Changed to random values const int32_t expected = MockFunc1(vec); const auto result = cross_call_worker::CallFunc1(&MockFunc1); @@ -1659,7 +1756,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc2", [](SimpleTests::Test& test) { + _tests.Add("CallFunc2", [](SimpleTests::Test &test) { float f = 2.71f; // Changed to random float int64_t i64 = 200; // Changed to random int64_t const char expected = MockFunc2(f, i64); @@ -1668,10 +1765,10 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc3", [](SimpleTests::Test&) { + _tests.Add("CallFunc3", [](SimpleTests::Test &) { cross_call_worker::CallFunc3(&MockFunc3); }); - _tests.Add("CallFunc4", [](SimpleTests::Test& test) { + _tests.Add("CallFunc4", [](SimpleTests::Test &test) { bool b = false; // Changed to random bool int32_t u32 = 42; // Changed to random uint32_t char16_t ch16 = 'B'; // Changed to random character @@ -1682,10 +1779,10 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc5", [](SimpleTests::Test& test) { + _tests.Add("CallFunc5", [](SimpleTests::Test &test) { int8_t i8 = 10; // Changed to random int8_t plg::vec2 vec2{3.4f, 5.6f}; // Changed to random values - void* ptr = reinterpret_cast(67890); // Example pointer changed + void *ptr = reinterpret_cast(67890); // Example pointer changed double d = 1.618; // Changed to random double plg::vector vec64{4, 5, 6}; // Changed to random values const bool expected = MockFunc5(i8, vec2, ptr, d, vec64); @@ -1694,20 +1791,20 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc6", [](SimpleTests::Test& test) { + _tests.Add("CallFunc6", [](SimpleTests::Test &test) { plg::string str = "AnotherString"; // Changed string float f = 4.56f; // Changed to random float plg::vector vecF{4.0f, 5.0f, 6.0f}; // Changed to random values int16_t i16 = 30; // Changed to random int16_t plg::vector vecU8{3, 4, 5}; // Changed to random values - void* ptr = reinterpret_cast(24680); // Example pointer changed + void *ptr = reinterpret_cast(24680); // Example pointer changed const int64_t expected = MockFunc6(str, f, vecF, i16, vecU8, ptr); const auto result = cross_call_worker::CallFunc6(&MockFunc6); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc7", [](SimpleTests::Test& test) { + _tests.Add("CallFunc7", [](SimpleTests::Test &test) { plg::vector vecC{'X', 'Y', 'Z'}; // Changed to random chars uint16_t u16 = 20; // Changed to random uint16_t char16_t ch16 = 'C'; // Changed to random character @@ -1721,13 +1818,13 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc8", [](SimpleTests::Test& test) { + _tests.Add("CallFunc8", [](SimpleTests::Test &test) { plg::vec3 vec3{4.0f, 5.0f, 6.0f}; // Changed to random values plg::vector vecU32{4, 5, 6}; // Changed to random values int16_t i16 = 30; // Changed to random int16_t bool b = false; // Changed to random bool plg::vec4 vec4{4.5f, 5.6f, 6.7f, 7.8f}; // Changed to random values - plg::vector vecC16{ 'D', 'E' }; // Changed to random chars + plg::vector vecC16{'D', 'E'}; // Changed to random chars char16_t ch16 = L'B'; // Changed to random character int32_t i32 = 50; // Changed to random int32_t const plg::mat4x4 expected = MockFunc8(vec3, vecU32, i16, b, vec4, vecC16, ch16, i32); @@ -1736,10 +1833,10 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc9", [](SimpleTests::Test&) { + _tests.Add("CallFunc9", [](SimpleTests::Test &) { cross_call_worker::CallFunc9(&MockFunc9); }); - _tests.Add("CallFunc10", [](SimpleTests::Test& test) { + _tests.Add("CallFunc10", [](SimpleTests::Test &test) { plg::vec4 vec4{5.6f, 7.8f, 8.9f, 9.0f}; // Changed to random values plg::mat4x4 mat; // Assume it's initialized properly plg::vector vecU32{4, 5, 6}; // Changed to random values @@ -1756,7 +1853,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc11", [](SimpleTests::Test& test) { + _tests.Add("CallFunc11", [](SimpleTests::Test &test) { plg::vector vecB{false, true, false}; // Changed to random bools char16_t ch16 = 'C'; // Changed to random character uint8_t u8 = 10; // Changed to random uint8_t @@ -1768,14 +1865,14 @@ class CrossCallMaster final : public plg::IPluginEntry { float f = 2.0f; // Changed to random float plg::vec2 vec2{4.5f, 6.7f}; // Changed to random values uint32_t u32 = 30; // Changed to random uint32_t - const void* expected = MockFunc11(vecB, ch16, u8, d, vec3, vecI8, i64, u16, f, vec2, u32); + const void *expected = MockFunc11(vecB, ch16, u8, d, vec3, vecI8, i64, u16, f, vec2, u32); const auto result = cross_call_worker::CallFunc11(&MockFunc11); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc12", [](SimpleTests::Test& test) { - void* ptr = reinterpret_cast(98765); // Example pointer changed + _tests.Add("CallFunc12", [](SimpleTests::Test &test) { + void *ptr = reinterpret_cast(98765); // Example pointer changed plg::vector vecD{4.0, 5.0, 6.0}; // Changed to random values uint32_t u32 = 30; // Changed to random uint32_t double d = 1.41; // Changed to random double @@ -1784,7 +1881,9 @@ class CrossCallMaster final : public plg::IPluginEntry { int8_t i8 = 10; // Changed to random int8_t uint64_t u64 = 300; // Changed to random uint64_t float f = 2.72f; // Changed to random float - plg::vector vecPtr{reinterpret_cast(2), reinterpret_cast(3), reinterpret_cast(4)}; // Changed to random values + plg::vector vecPtr{ + reinterpret_cast(2), reinterpret_cast(3), reinterpret_cast(4) + }; // Changed to random values int64_t i64 = 200; // Changed to random int64_t char ch = 'B'; // Changed to random character const bool expected = MockFunc12(ptr, vecD, u32, d, b, i32, i8, u64, f, vecPtr, i64, ch); @@ -1793,7 +1892,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc13", [](SimpleTests::Test& test) { + _tests.Add("CallFunc13", [](SimpleTests::Test &test) { int64_t i64 = 75; // Changed to random int64_t plg::vector vecC{'D', 'E', 'F'}; // Changed to random chars uint16_t u16 = 20; // Changed to random uint16_t @@ -1803,855 +1902,880 @@ class CrossCallMaster final : public plg::IPluginEntry { plg::string str = "RandomString"; // Changed string int32_t i32 = 30; // Changed to random int32_t plg::vec3 vec3{4.0f, 5.0f, 6.0f}; // Changed to random values - void* ptr = reinterpret_cast(13579); // Example pointer changed + void *ptr = reinterpret_cast(13579); // Example pointer changed plg::vec2 vec2{4.5f, 6.7f}; // Changed to random values plg::vector vecU8{2, 3, 4}; // Changed to random values int16_t i16 = 20; // Changed to random int16_t - const plg::string expected = MockFunc13(i64, vecC, u16, f, vecB, vec4, str, i32, vec3, ptr, vec2, vecU8, i16); + const plg::string expected = MockFunc13(i64, vecC, u16, f, vecB, vec4, str, i32, vec3, ptr, vec2, vecU8, + i16); const auto result = cross_call_worker::CallFunc13(&MockFunc13); if (result != expected) { test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); } }); - _tests.Add("CallFunc14", [](SimpleTests::Test& test) { - plg::vector vecC{'D', 'E', 'F'}; // Changed to random chars - plg::vector vecU32{4, 5, 6}; // Changed to random values - plg::mat4x4 mat; // Assume it's initialized properly - bool b = false; // Changed to random bool - char16_t ch16 = L'B'; // Changed to random character - int32_t i32 = 25; // Changed to random int32_t - plg::vector vecF{4.0f, 5.0f, 6.0f}; // Changed to random values - uint16_t u16 = 30; // Changed to random uint16_t - plg::vector vecU8{3, 4, 5}; // Changed to random values - int8_t i8 = 10; // Changed to random int8_t - plg::vec3 vec3{4.0f, 5.0f, 6.0f}; // Changed to random values - plg::vec4 vec4{5.6f, 7.8f, 9.0f, 10.1f}; // Changed to random values - double d = 2.72; // Changed to random double - void* ptr = reinterpret_cast(54321); // Example pointer changed - const plg::vector expected = MockFunc14(vecC, vecU32, mat, b, ch16, i32, vecF, u16, vecU8, i8, vec3, vec4, d, ptr); - const auto result = cross_call_worker::CallFunc14(&MockFunc14); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("CallFunc14", [](SimpleTests::Test &test) { + plg::vector vecC{'D', 'E', 'F'}; // Changed to random chars + plg::vector vecU32{4, 5, 6}; // Changed to random values + plg::mat4x4 mat; // Assume it's initialized properly + bool b = false; // Changed to random bool + char16_t ch16 = L'B'; // Changed to random character + int32_t i32 = 25; // Changed to random int32_t + plg::vector vecF{4.0f, 5.0f, 6.0f}; // Changed to random values + uint16_t u16 = 30; // Changed to random uint16_t + plg::vector vecU8{3, 4, 5}; // Changed to random values + int8_t i8 = 10; // Changed to random int8_t + plg::vec3 vec3{4.0f, 5.0f, 6.0f}; // Changed to random values + plg::vec4 vec4{5.6f, 7.8f, 9.0f, 10.1f}; // Changed to random values + double d = 2.72; // Changed to random double + void *ptr = reinterpret_cast(54321); // Example pointer changed + const plg::vector expected = MockFunc14(vecC, vecU32, mat, b, ch16, i32, vecF, u16, vecU8, i8, + vec3, vec4, d, ptr); + const auto result = cross_call_worker::CallFunc14(&MockFunc14); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc15", [](SimpleTests::Test &test) { + plg::vector vecI16{4, 5, 6}; // Changed to random values + plg::mat4x4 mat; // Assume it's initialized properly + plg::vec4 vec4{7.8f, 8.9f, 9.0f, 10.1f}; // Changed to random values + void *ptr = reinterpret_cast(12345); // Example pointer changed + uint64_t u64 = 200; // Changed to random uint64_t + plg::vector vecU32{5, 6, 7}; // Changed to random values + bool b = false; // Changed to random bool + float f = 3.14f; // Changed to random float + plg::vector vecC16{'D', 'E'}; // Changed to random chars + uint8_t u8 = 6; // Changed to random uint8_t + int32_t i32 = 25; // Changed to random int32_t + plg::vec2 vec2{5.6f, 7.8f}; // Changed to random values + uint16_t u16 = 40; // Changed to random uint16_t + double d = 2.71; // Changed to random double + plg::vector vecU8{1, 3, 5}; // Changed to random values + const int16_t expected = MockFunc15(vecI16, mat, vec4, ptr, u64, vecU32, b, f, vecC16, u8, i32, vec2, u16, + d, vecU8); + const auto result = cross_call_worker::CallFunc15(&MockFunc15); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc16", [](SimpleTests::Test &test) { + plg::vector vecB{true, true, false}; // Changed to random bools + int16_t i16 = 20; // Changed to random int16_t + plg::vector vecI8{2, 3, 4}; // Changed to random values + plg::vec4 vec4{7.8f, 8.9f, 9.0f, 10.1f}; // Changed to random values + plg::mat4x4 mat; // Assume it's initialized properly + plg::vec2 vec2{5.6f, 7.8f}; // Changed to random values + plg::vector vecU64{5, 6, 7}; // Changed to random values + plg::vector vecC{'D', 'E', 'F'}; // Changed to random chars + plg::string str = "DifferentString"; // Changed string + int64_t i64 = 300; // Changed to random int64_t + plg::vector vecU32{6, 7, 8}; // Changed to random values + plg::vec3 vec3{5.0f, 6.0f, 7.0f}; // Changed to random values + float f = 3.14f; // Changed to random float + double d = 2.718; // Changed to random double + int8_t i8 = 6; // Changed to random int8_t + uint16_t u16 = 30; // Changed to random uint16_t + const void *expected = MockFunc16(vecB, i16, vecI8, vec4, mat, vec2, vecU64, vecC, str, i64, vecU32, vec3, + f, d, i8, u16); + const auto result = cross_call_worker::CallFunc16(&MockFunc16); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc17", [](SimpleTests::Test &test) { + const plg::string expected = "62"; + const auto result = cross_call_worker::CallFunc17(&MockFunc17); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc18", [](SimpleTests::Test &test) { + const plg::string expected = "{10, 20}|10|20"; + const auto result = cross_call_worker::CallFunc18(&MockFunc18); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc19", [](SimpleTests::Test &test) { + const plg::string expected = "84|{4, 5, 6}|{4, 5, 6}"; + const auto result = cross_call_worker::CallFunc19(&MockFunc19); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc20", [](SimpleTests::Test &test) { + const plg::string expected = "1|103|{5, 6, 7, 8}|{300, 400}|G"; + const auto result = cross_call_worker::CallFunc20(&MockFunc20); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc21", [](SimpleTests::Test &test) { + const plg::string expected = + "1|{{1.5, 0.7, 0.9, 0.6}, {0.8, 1.2, 0.3, 0.5}, {1.1, 0.4, 1.3, 0.8}, {0.6, 1, 0.4, 0.9}}|{10, 20, 30}|{3, 4}|false|6.28"; + const auto result = cross_call_worker::CallFunc21(&MockFunc21); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc22", [](SimpleTests::Test &test) { + const plg::string expected = "2|0x1|150|{4.4, 5.5, 6.6}|456|World|{5, 6, 7, 8}"; + const auto result = cross_call_worker::CallFunc22(&MockFunc22); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc23", [](SimpleTests::Test &test) { + const plg::string expected = "100|{6, 7}|{4, 5, 6, 7}|8551|2|2|{4, 5, 6}"; + const auto result = cross_call_worker::CallFunc23(&MockFunc23); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc24", [](SimpleTests::Test &test) { + const plg::string expected = + "{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}|{d, e, f}|128|{7, 8, 9}|{5, 6, 7, 8}|1099511627775|{0xffffddddffffdddd}|3.14|{0x3, 0x4}"; + const auto result = cross_call_worker::CallFunc24(&MockFunc24); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc25", [](SimpleTests::Test &test) { + const plg::string expected = + "1|200|{0xdeadbeefdeadbeef}|true|128|UpdatedMockFunc25|{4, 5, 6}|2023|{8, 9, 10, 11}|64222"; + const auto result = cross_call_worker::CallFunc25(&MockFunc25); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc26", [](SimpleTests::Test &test) { + const plg::string expected = + "B|65|{4, 5}|{{0.5, 0.3, 0.1, 0.4}, {1.5, 0.7, 0.6, 0.8}, {1.1, 0.4, 0.2, 1}, {0.9, 0.8, 0.6, 1}}|{3.3, 4.4}|64|64|{150, 250}|0xbadcafe|false"; + const auto result = cross_call_worker::CallFunc26(&MockFunc26); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc27", [](SimpleTests::Test &test) { + const plg::string expected = + "27|9|{7, 8, 9}|0xdeadbeefdeadbeef|{5, 6}|{3, 6, 9}|{{1.5, 2.5, 3.5, 4.5}, {5.5, 6.5, 7.5, 8.5}, {9.5, 10.5, 11.5, 12.5}, {13.5, 14.5, 15.5, 16.5}}|true|{2, 3, 4, 5}|10|20|{1, 55, 66, 87, 99, 23, 123}"; + const auto result = cross_call_worker::CallFunc27(&MockFunc27); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc28", [](SimpleTests::Test &test) { + const plg::string expected = + "Updated MockFunc28|0x7fffffffffff|60000|{10, 20, 30, 40, 50, 60}|{{2.1, 0.9, 0.4, 0.8}, {0.5, 1.2, 0.7, 0.4}, {1, 0.6, 1.5, 0.2}, {0.8, 0.3, 0.9, 1.1}}|7.5|{2, 3, 4, 5}|Updated MockFunc28|{10, 20, 30}|900000000000|false|{40, 50, 60}|{10, -500, 1000}"; + const auto result = cross_call_worker::CallFunc28(&MockFunc28); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc29", [](SimpleTests::Test &test) { + const plg::string expected = + "{'Updated Example', 'Updated MockFunc29'}|{2.5, 3.5, 4.5, 5.5}|50|{100, 99, 98}|6.28|false|10|{150, 250}|2.5|Updated MockFunc29|{{0.6, 1.1, 0.7, 0.2}, {1.3, 0.9, 0.5, 1}, {0.8, 0.4, 1.6, 0.7}, {0.2, 1, 0.9, 1.5}}|128|{4, 5, 6}|{4, 5, 6}"; + const auto result = cross_call_worker::CallFunc29(&MockFunc29); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc30", [](SimpleTests::Test &test) { + const plg::string expected = + "77|0x7fffffffffff|{2, 4, 6, 8}|2000|{300, 400}|true|Updated MockFunc30|{4, 5, 6}|{128, 64, 255, 0, 100, 50}|3.3|{4, 5}|{{0.6, 0.2, 1.5, 0.9}, {1.2, 0.4, 0.7, 0.8}, {0.5, 0.1, 1.7, 0.4}, {0.8, 0.6, 1.2, 1.3}}|10|{3, 3, 4, 4}|3.14159"; + const auto result = cross_call_worker::CallFunc30(&MockFunc30); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc31", [](SimpleTests::Test &test) { + const plg::string expected = + "{1, 2, 3}|D|54321|{18446744073709551615, 18446744073709551614, 18446744073709551613}|{5, 6, 7, 8}|Updated MockFunc31|false|987654321|{6, 7}|9|500|{5, 10}|{{1, 0.2, 1.1, 0.4}, {1.1, 0.8, 0.3, 0.9}, {0.5, 0.7, 1.8, 0.6}, {0.3, 0.6, 1.4, 0.8}}|{10, 20, 30}|8.8|{0.2, 0.4, 0.6}"; + const auto result = cross_call_worker::CallFunc31(&MockFunc31); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc32", [](SimpleTests::Test &test) { + const plg::string expected = + "100|512|{5, 10}|{8, 9, 10, 11}|0xdeadbeafdeadbeaf|{400, 500}|{{0.5, 0.3, 0.2, 0.1}, {0.8, 0.9, 0.4, 0.6}, {0.1, 0.7, 1, 0.5}, {0.4, 0.2, 0.3, 1.2}}|987654321|Updated MockFunc32|2000|{5.5, 6.5}|{6, 7, 8, 9}|true|{1, 2, 3}|15|{120, 121, 122}"; + const auto result = cross_call_worker::CallFunc32(&MockFunc32); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFunc33", [](SimpleTests::Test &test) { + const plg::string expected = "Updated MockFunc33"; + const auto result = cross_call_worker::CallFunc33(&MockFunc33); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); + _tests.Add("CallFuncEnum", [](SimpleTests::Test &test) { + const plg::string expected = "{4, 1}|{4, 3, 2}"; + const auto result = cross_call_worker::CallFuncEnum(&MockFuncEnum); + if (result != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + } + }); +#endif// TEST_CASES & TEST_PARAMS_FUNCTIONS + } + + void ReverseNoParamOnlyReturn() { +#if TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_PRIMITIVES + _tests.Add("ReverseNoParamReturnVoid", [](SimpleTests::Test & /*test*/) { + cross_call_worker::ReverseCall("NoParamReturnVoid"); + }); + _tests.Add("ReverseNoParamReturnBool", [&](SimpleTests::Test &test) { + const plg::string expected = "true"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnBool"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnChar8", [&](SimpleTests::Test &test) { + const plg::string expected = "P"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnChar8"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnChar16", [&](SimpleTests::Test &test) { + const plg::string expected = "1060"; // Ф + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnChar16"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnInt8", [&](SimpleTests::Test &test) { + const plg::string expected = "123"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnInt8"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnInt16", [&](SimpleTests::Test &test) { + const plg::string expected = "32765"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnInt16"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnInt32", [&](SimpleTests::Test &test) { + const plg::string expected = "2112211221"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnInt32"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnInt64", [&](SimpleTests::Test &test) { + const plg::string expected = "8526495038839145831"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnInt64"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnUInt8", [&](SimpleTests::Test &test) { + const plg::string expected = "205"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnUInt8"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnUInt16", [&](SimpleTests::Test &test) { + const plg::string expected = "52685"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnUInt16"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnUInt32", [&](SimpleTests::Test &test) { + const plg::string expected = "3452816845"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnUInt32"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnUInt64", [&](SimpleTests::Test &test) { + const plg::string expected = "14829735431805717965"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnUInt64"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnPointer", [&](SimpleTests::Test &test) { + const plg::string expected = "0xaabbccdd87655678"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnPointer"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnFloat", [&](SimpleTests::Test &test) { + const plg::string expected = "0.123"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnFloat"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnDouble", [&](SimpleTests::Test &test) { + const plg::string expected = "987.321"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnDouble"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); +#endif// TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_PRIMITIVES + +#if TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_OBJECTS + _tests.Add("ReverseNoParamReturnFunction", [&](SimpleTests::Test &test) { + const plg::string expected = "365"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnFunction"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnString", [&](SimpleTests::Test &test) { + const plg::string expected = "Convertiplane"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnString"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); + } + }); +#endif// TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_OBJECTS + +#if TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_ARRAYS + _tests.Add("ReverseNoParamReturnArrayBool", [&](SimpleTests::Test &test) { + const plg::string expected = "{false, true, true}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayBool"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayChar8", [&](SimpleTests::Test &test) { + const plg::string expected = "{p, l, u, g}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayChar8"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayChar16", [&](SimpleTests::Test &test) { + const plg::string expected = "{1095, 1072, 1088, 33}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayChar16"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayInt8", [&](SimpleTests::Test &test) { + const plg::string expected = "{10, -15, 20}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayInt8"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayInt16", [&](SimpleTests::Test &test) { + const plg::string expected = "{10, -15, 20, -25}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayInt16"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayInt32", [&](SimpleTests::Test &test) { + const plg::string expected = "{10, -15, 20, -25, 30}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayInt32"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayInt64", [&](SimpleTests::Test &test) { + const plg::string expected = "{10, -15, 20, -25, 30, -35}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayInt64"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayUInt8", [&](SimpleTests::Test &test) { + const plg::string expected = "{1, 2, 3, 200}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayUInt8"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayUInt16", [&](SimpleTests::Test &test) { + const plg::string expected = "{1, 2, 3, 200, 60000}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayUInt16"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayUInt32", [&](SimpleTests::Test &test) { + const plg::string expected = "{1, 2, 3, 200, 60000, 4000000000}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayUInt32"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayUInt64", [&](SimpleTests::Test &test) { + const plg::string expected = "{1, 2, 3, 200, 60000, 4000000000, 12223334445556667778}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayUInt64"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayPointer", [&](SimpleTests::Test &test) { + const plg::string expected = "{0x0, 0xdeadbeaf, 0xcdccddcccdddcccc}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayPointer"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayFloat", [&](SimpleTests::Test &test) { + const plg::string expected = "{1.1, -10.82, 555.555}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayFloat"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayDouble", [&](SimpleTests::Test &test) { + const plg::string expected = "{1.1, -10.82, 555.555, 55555.55555, 123456789.98765}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayDouble"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnArrayString", [&](SimpleTests::Test &test) { + const plg::string expected = + "{'5', 'true', '0.0', 'Hello', 'And Goodbay', 'Another long string to test. Pi equal 3,1415926535 8979323846 2643383279 5028841971 6939937510'}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnArrayString"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); +#endif// TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_ARRAYS + +#if TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_VECTORS + _tests.Add("ReverseNoParamReturnVector2", [&](SimpleTests::Test &test) { + const plg::string expected = "{100.9, 200.8}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnVector2"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseNoParamReturnVector3", [&](SimpleTests::Test &test) { + const plg::string expected = "{100.9, 200.8, 300.7}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnVector3"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFunc15", [](SimpleTests::Test& test) { - plg::vector vecI16{4, 5, 6}; // Changed to random values - plg::mat4x4 mat; // Assume it's initialized properly - plg::vec4 vec4{7.8f, 8.9f, 9.0f, 10.1f}; // Changed to random values - void* ptr = reinterpret_cast(12345); // Example pointer changed - uint64_t u64 = 200; // Changed to random uint64_t - plg::vector vecU32{5, 6, 7}; // Changed to random values - bool b = false; // Changed to random bool - float f = 3.14f; // Changed to random float - plg::vector vecC16{'D', 'E'}; // Changed to random chars - uint8_t u8 = 6; // Changed to random uint8_t - int32_t i32 = 25; // Changed to random int32_t - plg::vec2 vec2{5.6f, 7.8f}; // Changed to random values - uint16_t u16 = 40; // Changed to random uint16_t - double d = 2.71; // Changed to random double - plg::vector vecU8{1, 3, 5}; // Changed to random values - const int16_t expected = MockFunc15(vecI16, mat, vec4, ptr, u64, vecU32, b, f, vecC16, u8, i32, vec2, u16, d, vecU8); - const auto result = cross_call_worker::CallFunc15(&MockFunc15); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseNoParamReturnVector4", [&](SimpleTests::Test &test) { + const plg::string expected = "{100.9, 200.8, 300.7, 400.6}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnVector4"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFunc16", [](SimpleTests::Test& test) { - plg::vector vecB{true, true, false}; // Changed to random bools - int16_t i16 = 20; // Changed to random int16_t - plg::vector vecI8{2, 3, 4}; // Changed to random values - plg::vec4 vec4{7.8f, 8.9f, 9.0f, 10.1f}; // Changed to random values - plg::mat4x4 mat; // Assume it's initialized properly - plg::vec2 vec2{5.6f, 7.8f}; // Changed to random values - plg::vector vecU64{5, 6, 7}; // Changed to random values - plg::vector vecC{'D', 'E', 'F'}; // Changed to random chars - plg::string str = "DifferentString"; // Changed string - int64_t i64 = 300; // Changed to random int64_t - plg::vector vecU32{6, 7, 8}; // Changed to random values - plg::vec3 vec3{5.0f, 6.0f, 7.0f}; // Changed to random values - float f = 3.14f; // Changed to random float - double d = 2.718; // Changed to random double - int8_t i8 = 6; // Changed to random int8_t - uint16_t u16 = 30; // Changed to random uint16_t - const void* expected = MockFunc16(vecB, i16, vecI8, vec4, mat, vec2, vecU64, vecC, str, i64, vecU32, vec3, f, d, i8, u16); - const auto result = cross_call_worker::CallFunc16(&MockFunc16); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseNoParamReturnMatrix4x4", [&](SimpleTests::Test &test) { + const plg::string expected = + "{{1.1, 2.2, 3.3, 4.4}, {9.9, 1.1, 2.2, 3.3}, {8.8, 9.9, 1.1, 2.2}, {7.7, 8.8, 9.9, 1.1}}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("NoParamReturnMatrix4x4"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFunc17", [](SimpleTests::Test& test) { - const plg::string expected = "62"; - const auto result = cross_call_worker::CallFunc17(&MockFunc17); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); +#endif// TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_VECTORS + } + + void ReverseParamsNoRefs() { +#if TEST_CASES & TEST_REVERSE_PARAMS_NO_REFS + _tests.Add("ReverseParam1", [&](SimpleTests::Test &test) { + const plg::string expected = "999"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param1"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc18", [](SimpleTests::Test& test) { - const plg::string expected = "{10, 20}|10|20"; - const auto result = cross_call_worker::CallFunc18(&MockFunc18); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParam2", [&](SimpleTests::Test &test) { + const plg::string expected = "888|9.9"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param2"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc19", [](SimpleTests::Test& test) { - const plg::string expected = "84|{4, 5, 6}|{4, 5, 6}"; - const auto result = cross_call_worker::CallFunc19(&MockFunc19); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParam3", [&](SimpleTests::Test &test) { + const plg::string expected = "777|8.8|9.8765"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param3"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc20", [](SimpleTests::Test& test) { - const plg::string expected = "1|103|{5, 6, 7, 8}|{300, 400}|G"; - const auto result = cross_call_worker::CallFunc20(&MockFunc20); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParam4", [&](SimpleTests::Test &test) { + const plg::string expected = "666|7.7|8.7659|{100.1, 200.2, 300.3, 400.4}"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param4"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc21", [](SimpleTests::Test& test) { - const plg::string expected = "1|{{1.5, 0.7, 0.9, 0.6}, {0.8, 1.2, 0.3, 0.5}, {1.1, 0.4, 1.3, 0.8}, {0.6, 1, 0.4, 0.9}}|{10, 20, 30}|{3, 4}|false|6.28"; - const auto result = cross_call_worker::CallFunc21(&MockFunc21); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParam5", [&](SimpleTests::Test &test) { + const plg::string expected = "555|6.6|7.6598|{-105.1, -205.2, -305.3, -405.4}|{}"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param5"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc22", [](SimpleTests::Test& test) { - const plg::string expected = "2|0x1|150|{4.4, 5.5, 6.6}|456|World|{5, 6, 7, 8}"; - const auto result = cross_call_worker::CallFunc22(&MockFunc22); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParam6", [&](SimpleTests::Test &test) { + const plg::string expected = "444|5.5|6.5987|{110.1, 210.2, 310.3, 410.4}|{90000, -100, 20000}|65"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param6"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc23", [](SimpleTests::Test& test) { - const plg::string expected = "100|{6, 7}|{4, 5, 6, 7}|8551|2|2|{4, 5, 6}"; - const auto result = cross_call_worker::CallFunc23(&MockFunc23); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParam7", [&](SimpleTests::Test &test) { + const plg::string expected = + "333|4.4|5.9876|{-115.1, -215.2, -315.3, -415.4}|{800000, 30000, -4000000}|66|red gold"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param7"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc24", [](SimpleTests::Test& test) { - const plg::string expected = "{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}|{d, e, f}|128|{7, 8, 9}|{5, 6, 7, 8}|1099511627775|{0xffffddddffffdddd}|3.14|{0x3, 0x4}"; - const auto result = cross_call_worker::CallFunc24(&MockFunc24); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParam8", [&](SimpleTests::Test &test) { + const plg::string expected = + "222|3.3|1.2345|{120.1, 220.2, 320.3, 420.4}|{7000000, 5000000, -600000000}|67|blue ice|90"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param8"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc25", [](SimpleTests::Test& test) { - const plg::string expected = "1|200|{0xdeadbeefdeadbeef}|true|128|UpdatedMockFunc25|{4, 5, 6}|2023|{8, 9, 10, 11}|64222"; - const auto result = cross_call_worker::CallFunc25(&MockFunc25); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParam9", [&](SimpleTests::Test &test) { + const plg::string expected = + "111|2.2|5.1234|{-125.1, -225.2, -325.3, -425.4}|{60000000, -700000000, 80000000000}|68|pink metal|89|-100"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param9"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc26", [](SimpleTests::Test& test) { - const plg::string expected = "B|65|{4, 5}|{{0.5, 0.3, 0.1, 0.4}, {1.5, 0.7, 0.6, 0.8}, {1.1, 0.4, 0.2, 1}, {0.9, 0.8, 0.6, 1}}|{3.3, 4.4}|64|64|{150, 250}|0xbadcafe|false"; - const auto result = cross_call_worker::CallFunc26(&MockFunc26); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParam10", [&](SimpleTests::Test &test) { + const plg::string expected = + "1234|1.1|4.5123|{130.1, 230.2, 330.3, 430.4}|{500000000, 90000000000, 1000000000000}|69|green wood|88|-200|0xabeba"; + _reverseParams.reset(); + cross_call_worker::ReverseCall("Param10"); + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != expected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); } }); - _tests.Add("CallFunc27", [](SimpleTests::Test& test) { - const plg::string expected = "27|9|{7, 8, 9}|0xdeadbeefdeadbeef|{5, 6}|{3, 6, 9}|{{1.5, 2.5, 3.5, 4.5}, {5.5, 6.5, 7.5, 8.5}, {9.5, 10.5, 11.5, 12.5}, {13.5, 14.5, 15.5, 16.5}}|true|{2, 3, 4, 5}|10|20|{1, 55, 66, 87, 99, 23, 123}"; - const auto result = cross_call_worker::CallFunc27(&MockFunc27); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); +#endif// TEST_CASES & TEST_REVERSE_PARAMS_NO_REFS + } + + void ReverseParamsWithRefs() { +#if TEST_CASES & TEST_REVERSE_PARAMS_WITH_REFS + _tests.Add("ReverseParamRef1", [&](SimpleTests::Test &test) { + const plg::string expected = "147"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef1"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFunc28", [](SimpleTests::Test& test) { - const plg::string expected = "Updated MockFunc28|0x7fffffffffff|60000|{10, 20, 30, 40, 50, 60}|{{2.1, 0.9, 0.4, 0.8}, {0.5, 1.2, 0.7, 0.4}, {1, 0.6, 1.5, 0.2}, {0.8, 0.3, 0.9, 1.1}}|7.5|{2, 3, 4, 5}|Updated MockFunc28|{10, 20, 30}|900000000000|false|{40, 50, 60}|{10, -500, 1000}"; - const auto result = cross_call_worker::CallFunc28(&MockFunc28); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParamRef2", [&](SimpleTests::Test &test) { + const plg::string expected = "852|0.1"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef2"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFunc29", [](SimpleTests::Test& test) { - const plg::string expected = "{'Updated Example', 'Updated MockFunc29'}|{2.5, 3.5, 4.5, 5.5}|50|{100, 99, 98}|6.28|false|10|{150, 250}|2.5|Updated MockFunc29|{{0.6, 1.1, 0.7, 0.2}, {1.3, 0.9, 0.5, 1}, {0.8, 0.4, 1.6, 0.7}, {0.2, 1, 0.9, 1.5}}|128|{4, 5, 6}|{4, 5, 6}"; - const auto result = cross_call_worker::CallFunc29(&MockFunc29); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParamRef3", [&](SimpleTests::Test &test) { + const plg::string expected = "369|0.2|11111.11111"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef3"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFunc30", [](SimpleTests::Test& test) { - const plg::string expected = "77|0x7fffffffffff|{2, 4, 6, 8}|2000|{300, 400}|true|Updated MockFunc30|{4, 5, 6}|{128, 64, 255, 0, 100, 50}|3.3|{4, 5}|{{0.6, 0.2, 1.5, 0.9}, {1.2, 0.4, 0.7, 0.8}, {0.5, 0.1, 1.7, 0.4}, {0.8, 0.6, 1.2, 1.3}}|10|{3, 3, 4, 4}|3.14159"; - const auto result = cross_call_worker::CallFunc30(&MockFunc30); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParamRef4", [&](SimpleTests::Test &test) { + const plg::string expected = "987|0.3|22222.22222|{4.4, 3.3, 2.2, 1.1}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef4"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFunc31", [](SimpleTests::Test& test) { - const plg::string expected = "{1, 2, 3}|D|54321|{18446744073709551615, 18446744073709551614, 18446744073709551613}|{5, 6, 7, 8}|Updated MockFunc31|false|987654321|{6, 7}|9|500|{5, 10}|{{1, 0.2, 1.1, 0.4}, {1.1, 0.8, 0.3, 0.9}, {0.5, 0.7, 1.8, 0.6}, {0.3, 0.6, 1.4, 0.8}}|{10, 20, 30}|8.8|{0.2, 0.4, 0.6}"; - const auto result = cross_call_worker::CallFunc31(&MockFunc31); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParamRef5", [&](SimpleTests::Test &test) { + const plg::string expected = "456|0.4|33333.33333|{1.4, 4.3, 3.2, 2.1}|{}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef5"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFunc32", [](SimpleTests::Test& test) { - const plg::string expected = "100|512|{5, 10}|{8, 9, 10, 11}|0xdeadbeafdeadbeaf|{400, 500}|{{0.5, 0.3, 0.2, 0.1}, {0.8, 0.9, 0.4, 0.6}, {0.1, 0.7, 1, 0.5}, {0.4, 0.2, 0.3, 1.2}}|987654321|Updated MockFunc32|2000|{5.5, 6.5}|{6, 7, 8, 9}|true|{1, 2, 3}|15|{120, 121, 122}"; - const auto result = cross_call_worker::CallFunc32(&MockFunc32); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParamRef6", [&](SimpleTests::Test &test) { + const plg::string expected = "321|0.5|44444.44444|{1.1, 4.4, 3.3, 2.2}|{99}|122"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef6"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFunc33", [](SimpleTests::Test& test) { - const plg::string expected = "Updated MockFunc33"; - const auto result = cross_call_worker::CallFunc33(&MockFunc33); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParamRef7", [&](SimpleTests::Test &test) { + const plg::string expected = "157|0.6|55555.55555|{2.1, 1.4, 4.3, 3.2}|{99, 8888}|121|my string"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef7"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("CallFuncEnum", [](SimpleTests::Test& test) { - const plg::string expected = "{4, 1}|{4, 3, 2}"; - const auto result = cross_call_worker::CallFuncEnum(&MockFuncEnum); - if (result != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", result, expected)); + _tests.Add("ReverseParamRef8", [&](SimpleTests::Test &test) { + const plg::string expected = + "759|0.7|66666.66666|{2.2, 1.1, 4.4, 3.3}|{99, 8888, 777777}|120|his string|1098"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef8"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseParamRef9", [&](SimpleTests::Test &test) { + const plg::string expected = + "953|0.8|77777.77777|{3.2, 2.1, 1.4, 4.3}|{99, 8888, 777777, 66666666}|119|her string|1099|-30003"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef9"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); + } + }); + _tests.Add("ReverseParamRef10", [&](SimpleTests::Test &test) { + const plg::string expected = + "351|0.9|88888.88888|{3.3, 2.2, 1.1, 4.4}|{99, 8888, 777777, 66666666, 5555555555}|118|they string|1100|30003|0xabcdef"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRef10"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); -#endif// TEST_CASES & TEST_PARAMS_FUNCTIONS - } - - void ReverseNoParamOnlyReturn() { -#if TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_PRIMITIVES - _tests.Add("ReverseNoParamReturnVoid", [](SimpleTests::Test& /*test*/) { - cross_call_worker::ReverseCall("NoParamReturnVoid"); - }); - _tests.Add("ReverseNoParamReturnBool", [&](SimpleTests::Test& test) { - const plg::string expected = "true"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnBool"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnChar8", [&](SimpleTests::Test& test) { - const plg::string expected = "P"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnChar8"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnChar16", [&](SimpleTests::Test& test) { - const plg::string expected = "1060"; // Ф - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnChar16"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnInt8", [&](SimpleTests::Test& test) { - const plg::string expected = "123"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnInt8"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnInt16", [&](SimpleTests::Test& test) { - const plg::string expected = "32765"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnInt16"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnInt32", [&](SimpleTests::Test& test) { - const plg::string expected = "2112211221"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnInt32"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnInt64", [&](SimpleTests::Test& test) { - const plg::string expected = "8526495038839145831"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnInt64"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnUInt8", [&](SimpleTests::Test& test) { - const plg::string expected = "205"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnUInt8"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnUInt16", [&](SimpleTests::Test& test) { - const plg::string expected = "52685"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnUInt16"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnUInt32", [&](SimpleTests::Test& test) { - const plg::string expected = "3452816845"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnUInt32"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnUInt64", [&](SimpleTests::Test& test) { - const plg::string expected = "14829735431805717965"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnUInt64"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnPointer", [&](SimpleTests::Test& test) { - const plg::string expected = "0xaabbccdd87655678"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnPointer"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnFloat", [&](SimpleTests::Test& test) { - const plg::string expected = "0.123"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnFloat"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnDouble", [&](SimpleTests::Test& test) { - const plg::string expected = "987.321"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnDouble"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); -#endif// TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_PRIMITIVES - -#if TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_OBJECTS - _tests.Add("ReverseNoParamReturnFunction", [&](SimpleTests::Test& test) { - const plg::string expected = "365"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnFunction"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnString", [&](SimpleTests::Test& test) { - const plg::string expected = "Convertiplane"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnString"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return '{}', expected '{}'", *_reverseReturn, expected)); - } - }); -#endif// TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_OBJECTS - -#if TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_ARRAYS - _tests.Add("ReverseNoParamReturnArrayBool", [&](SimpleTests::Test& test) { - const plg::string expected = "{false, true, true}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayBool"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayChar8", [&](SimpleTests::Test& test) { - const plg::string expected = "{p, l, u, g}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayChar8"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - - }); - _tests.Add("ReverseNoParamReturnArrayChar16", [&](SimpleTests::Test& test) { - const plg::string expected = "{1095, 1072, 1088, 33}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayChar16"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayInt8", [&](SimpleTests::Test& test) { - const plg::string expected = "{10, -15, 20}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayInt8"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayInt16", [&](SimpleTests::Test& test) { - const plg::string expected = "{10, -15, 20, -25}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayInt16"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayInt32", [&](SimpleTests::Test& test) { - const plg::string expected = "{10, -15, 20, -25, 30}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayInt32"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayInt64", [&](SimpleTests::Test& test) { - const plg::string expected = "{10, -15, 20, -25, 30, -35}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayInt64"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayUInt8", [&](SimpleTests::Test& test) { - const plg::string expected = "{1, 2, 3, 200}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayUInt8"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayUInt16", [&](SimpleTests::Test& test) { - const plg::string expected = "{1, 2, 3, 200, 60000}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayUInt16"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayUInt32", [&](SimpleTests::Test& test) { - const plg::string expected = "{1, 2, 3, 200, 60000, 4000000000}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayUInt32"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayUInt64", [&](SimpleTests::Test& test) { - const plg::string expected = "{1, 2, 3, 200, 60000, 4000000000, 12223334445556667778}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayUInt64"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayPointer", [&](SimpleTests::Test& test) { - const plg::string expected = "{0x0, 0xdeadbeaf, 0xcdccddcccdddcccc}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayPointer"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayFloat", [&](SimpleTests::Test& test) { - const plg::string expected = "{1.1, -10.82, 555.555}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayFloat"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayDouble", [&](SimpleTests::Test& test) { - const plg::string expected = "{1.1, -10.82, 555.555, 55555.55555, 123456789.98765}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayDouble"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnArrayString", [&](SimpleTests::Test& test) { - const plg::string expected = "{'5', 'true', '0.0', 'Hello', 'And Goodbay', 'Another long string to test. Pi equal 3,1415926535 8979323846 2643383279 5028841971 6939937510'}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnArrayString"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); -#endif// TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_ARRAYS - -#if TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_VECTORS - _tests.Add("ReverseNoParamReturnVector2", [&](SimpleTests::Test& test) { - const plg::string expected = "{100.9, 200.8}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnVector2"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnVector3", [&](SimpleTests::Test& test) { - const plg::string expected = "{100.9, 200.8, 300.7}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnVector3"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnVector4", [&](SimpleTests::Test& test) { - const plg::string expected = "{100.9, 200.8, 300.7, 400.6}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnVector4"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseNoParamReturnMatrix4x4", [&](SimpleTests::Test& test) { - const plg::string expected = "{{1.1, 2.2, 3.3, 4.4}, {9.9, 1.1, 2.2, 3.3}, {8.8, 9.9, 1.1, 2.2}, {7.7, 8.8, 9.9, 1.1}}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("NoParamReturnMatrix4x4"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, expected)); - } - }); -#endif// TEST_CASES & TEST_REVERSE_NO_PARAM_ONLY_RETURN_VECTORS - } - - void ReverseParamsNoRefs() { -#if TEST_CASES & TEST_REVERSE_PARAMS_NO_REFS - _tests.Add("ReverseParam1", [&](SimpleTests::Test& test) { - const plg::string expected = "999"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param1"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); - _tests.Add("ReverseParam2", [&](SimpleTests::Test& test) { - const plg::string expected = "888|9.9"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param2"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); - _tests.Add("ReverseParam3", [&](SimpleTests::Test& test) { - const plg::string expected = "777|8.8|9.8765"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param3"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); - _tests.Add("ReverseParam4", [&](SimpleTests::Test& test) { - const plg::string expected = "666|7.7|8.7659|{100.1, 200.2, 300.3, 400.4}"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param4"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); - _tests.Add("ReverseParam5", [&](SimpleTests::Test& test) { - const plg::string expected = "555|6.6|7.6598|{-105.1, -205.2, -305.3, -405.4}|{}"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param5"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); - _tests.Add("ReverseParam6", [&](SimpleTests::Test& test) { - const plg::string expected = "444|5.5|6.5987|{110.1, 210.2, 310.3, 410.4}|{90000, -100, 20000}|65"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param6"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); - _tests.Add("ReverseParam7", [&](SimpleTests::Test& test) { - const plg::string expected = "333|4.4|5.9876|{-115.1, -215.2, -315.3, -415.4}|{800000, 30000, -4000000}|66|red gold"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param7"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); - _tests.Add("ReverseParam8", [&](SimpleTests::Test& test) { - const plg::string expected = "222|3.3|1.2345|{120.1, 220.2, 320.3, 420.4}|{7000000, 5000000, -600000000}|67|blue ice|90"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param8"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); - _tests.Add("ReverseParam9", [&](SimpleTests::Test& test) { - const plg::string expected = "111|2.2|5.1234|{-125.1, -225.2, -325.3, -425.4}|{60000000, -700000000, 80000000000}|68|pink metal|89|-100"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param9"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); - _tests.Add("ReverseParam10", [&](SimpleTests::Test& test) { - const plg::string expected = "1234|1.1|4.5123|{130.1, 230.2, 330.3, 430.4}|{500000000, 90000000000, 1000000000000}|69|green wood|88|-200|0xabeba"; - _reverseParams.reset(); - cross_call_worker::ReverseCall("Param10"); - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != expected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, expected)); - } - }); -#endif// TEST_CASES & TEST_REVERSE_PARAMS_NO_REFS - } - - void ReverseParamsWithRefs() { -#if TEST_CASES & TEST_REVERSE_PARAMS_WITH_REFS - _tests.Add("ReverseParamRef1", [&](SimpleTests::Test& test) { - const plg::string expected = "147"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef1"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseParamRef2", [&](SimpleTests::Test& test) { - const plg::string expected = "852|0.1"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef2"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseParamRef3", [&](SimpleTests::Test& test) { - const plg::string expected = "369|0.2|11111.11111"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef3"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseParamRef4", [&](SimpleTests::Test& test) { - const plg::string expected = "987|0.3|22222.22222|{4.4, 3.3, 2.2, 1.1}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef4"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseParamRef5", [&](SimpleTests::Test& test) { - const plg::string expected = "456|0.4|33333.33333|{1.4, 4.3, 3.2, 2.1}|{}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef5"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseParamRef6", [&](SimpleTests::Test& test) { - const plg::string expected = "321|0.5|44444.44444|{1.1, 4.4, 3.3, 2.2}|{99}|122"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef6"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseParamRef7", [&](SimpleTests::Test& test) { - const plg::string expected = "157|0.6|55555.55555|{2.1, 1.4, 4.3, 3.2}|{99, 8888}|121|my string"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef7"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseParamRef8", [&](SimpleTests::Test& test) { - const plg::string expected = "759|0.7|66666.66666|{2.2, 1.1, 4.4, 3.3}|{99, 8888, 777777}|120|his string|1098"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef8"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseParamRef9", [&](SimpleTests::Test& test) { - const plg::string expected = "953|0.8|77777.77777|{3.2, 2.1, 1.4, 4.3}|{99, 8888, 777777, 66666666}|119|her string|1099|-30003"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef9"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); - _tests.Add("ReverseParamRef10", [&](SimpleTests::Test& test) { - const plg::string expected = "351|0.9|88888.88888|{3.3, 2.2, 1.1, 4.4}|{99, 8888, 777777, 66666666, 5555555555}|118|they string|1100|30003|0xabcdef"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRef10"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); #endif// TEST_CASES & TEST_REVERSE_PARAMS_WITH_REFS - } + } - void ReverseParamsRefVectors() { + void ReverseParamsRefVectors() { #if TEST_CASES & TEST_REVERSE_PARAMS_REF_ARRAYS - _tests.Add("ReverseParamRefArrays", [&](SimpleTests::Test& test) { - const plg::string expected = "{true, false}|{^}|{1103, 1094}|{-4, -3, -2, -1}|{-555, -444, -333}|{-66666, -77777}|{-7666555444}|" - "{0, 1, 1, 2, 3, 5}|{32999}|{3000000000, 1}|{1, 22, 333, 4444, 55555, 999999999999}|{0xd, 0x9, 0x5, 0x1}|" - "{91.23, 12.34, 23.45, 8.08}|{777.777777}|{'one', '1 two', '1 2 three'}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamRefArrays"); - if (!_reverseReturn) { - test.Fail("Params return not set"); - } else if (*_reverseReturn != expected) { - test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); - } - }); + _tests.Add("ReverseParamRefArrays", [&](SimpleTests::Test &test) { + const plg::string expected = + "{true, false}|{^}|{1103, 1094}|{-4, -3, -2, -1}|{-555, -444, -333}|{-66666, -77777}|{-7666555444}|" + "{0, 1, 1, 2, 3, 5}|{32999}|{3000000000, 1}|{1, 22, 333, 4444, 55555, 999999999999}|{0xd, 0x9, 0x5, 0x1}|" + "{91.23, 12.34, 23.45, 8.08}|{777.777777}|{'one', '1 two', '1 2 three'}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamRefArrays"); + if (!_reverseReturn) { + test.Fail("Params return not set"); + } else if (*_reverseReturn != expected) { + test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); + } + }); #endif// TEST_CASES & TEST_REVERSE_PARAMS_REF_ARRAYS - } + } - void ReverseParamsAllPrimitives() { + void ReverseParamsAllPrimitives() { #if TEST_CASES & TEST_REVERSE_PARAMS_ALL_PRIMITIVES - _tests.Add("ReverseParamAllPrimitives", [&](SimpleTests::Test& test) { - const plg::string returnExpected = "65"; - const plg::string paramsExpected = "true|37|9762|-1|-1000|-1000000|-1000000000000|200|50000|3000000000|9999999999|0xfedcbaabcdef|0.001|987654.456789"; - _reverseReturn.reset(); - _reverseParams.reset(); - cross_call_worker::ReverseCall("ParamAllPrimitives"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != returnExpected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, returnExpected)); - } - if (!_reverseParams) { - test.Fail("Params not set"); - } else if (*_reverseParams != paramsExpected) { - test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, paramsExpected)); - } - }); - _tests.Add("ReverseParamEnum", [&](SimpleTests::Test& test) { - const plg::string returnExpected = "10"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamEnum"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != returnExpected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, returnExpected)); - } - }); - _tests.Add("ReverseParamRefEnum", [&](SimpleTests::Test& test) { - const plg::string returnExpected = "5|1|{1, 1, 2}"; - _reverseReturn.reset(); - cross_call_worker::ReverseCall("ParamEnumRef"); - if (!_reverseReturn) { - test.Fail("Return not set"); - } else if (*_reverseReturn != returnExpected) { - test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, returnExpected)); - } - }); + _tests.Add("ReverseParamAllPrimitives", [&](SimpleTests::Test &test) { + const plg::string returnExpected = "65"; + const plg::string paramsExpected = + "true|37|9762|-1|-1000|-1000000|-1000000000000|200|50000|3000000000|9999999999|0xfedcbaabcdef|0.001|987654.456789"; + _reverseReturn.reset(); + _reverseParams.reset(); + cross_call_worker::ReverseCall("ParamAllPrimitives"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != returnExpected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, returnExpected)); + } + if (!_reverseParams) { + test.Fail("Params not set"); + } else if (*_reverseParams != paramsExpected) { + test.Fail(std::format("Wrong param values {}, expected {}", *_reverseParams, paramsExpected)); + } + }); + _tests.Add("ReverseParamEnum", [&](SimpleTests::Test &test) { + const plg::string returnExpected = "10"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamEnum"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != returnExpected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, returnExpected)); + } + }); + _tests.Add("ReverseParamRefEnum", [&](SimpleTests::Test &test) { + const plg::string returnExpected = "5|1|{1, 1, 2}"; + _reverseReturn.reset(); + cross_call_worker::ReverseCall("ParamEnumRef"); + if (!_reverseReturn) { + test.Fail("Return not set"); + } else if (*_reverseReturn != returnExpected) { + test.Fail(std::format("Wrong return {}, expected {}", *_reverseReturn, returnExpected)); + } + }); #endif// TEST_CASES & TEST_REVERSE_PARAMS_ALL_PRIMITIVES - } + } - void ReverseParamsVariants() { + void ReverseParamsVariants() { #if TEST_CASES & TEST_REVERSE_PARAMS_VARIANTS - _tests.Add("ReverseParamVariant", [&](SimpleTests::Test&) { + _tests.Add("ReverseParamVariant", [&](SimpleTests::Test &) { cross_call_worker::ReverseCall("ParamVariant"); - }); - _tests.Add("ReverseParamVariantRef", [&](SimpleTests::Test& test) { - const plg::string paramsExpected = "{1, 2, 3}|{true, 3.14, some really long string for avoid SSO optimization}"; + }); + _tests.Add("ReverseParamVariantRef", [&](SimpleTests::Test &test) { + const plg::string paramsExpected = + "{1, 2, 3}|{true, 3.14, some really long string for avoid SSO optimization}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("ParamVariantRef"); if (!_reverseReturn) { @@ -2659,16 +2783,16 @@ class CrossCallMaster final : public plg::IPluginEntry { } else if (*_reverseReturn != paramsExpected) { test.Fail(std::format("Wrong param values {}, expected {}", *_reverseReturn, paramsExpected)); } - }); + }); #endif// TEST_CASES & TEST_REVERSE_PARAMS_VARIANTS - } + } - void ReverseParamsFunctions() { + void ReverseParamsFunctions() { #if TEST_CASES & TEST_REVERSE_PARAMS_FUNCTIONS - _tests.Add("ReverseCallFuncVoid", [](SimpleTests::Test&) { + _tests.Add("ReverseCallFuncVoid", [](SimpleTests::Test &) { cross_call_worker::ReverseCall("CallFuncVoid"); }); - _tests.Add("ReverseCallFuncBool", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncBool", [&](SimpleTests::Test &test) { const plg::string expected = "true"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncBool"); @@ -2678,7 +2802,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncChar8", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncChar8", [&](SimpleTests::Test &test) { const plg::string expected = "65"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncChar8"); @@ -2688,7 +2812,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncChar16", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncChar16", [&](SimpleTests::Test &test) { const plg::string expected = "90"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncChar16"); @@ -2698,7 +2822,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncInt8", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncInt8", [&](SimpleTests::Test &test) { const plg::string expected = "10"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncInt8"); @@ -2708,7 +2832,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncInt16", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncInt16", [&](SimpleTests::Test &test) { const plg::string expected = "100"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncInt16"); @@ -2718,7 +2842,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncInt32", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncInt32", [&](SimpleTests::Test &test) { const plg::string expected = "1000"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncInt32"); @@ -2728,7 +2852,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncInt64", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncInt64", [&](SimpleTests::Test &test) { const plg::string expected = "10000"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncInt64"); @@ -2738,7 +2862,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncUInt8", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncUInt8", [&](SimpleTests::Test &test) { const plg::string expected = "20"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncUInt8"); @@ -2748,7 +2872,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncUInt16", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncUInt16", [&](SimpleTests::Test &test) { const plg::string expected = "200"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncUInt16"); @@ -2758,7 +2882,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncUInt32", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncUInt32", [&](SimpleTests::Test &test) { const plg::string expected = "2000"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncUInt32"); @@ -2768,7 +2892,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncUInt64", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncUInt64", [&](SimpleTests::Test &test) { const plg::string expected = "20000"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncUInt64"); @@ -2778,7 +2902,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncPtr", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncPtr", [&](SimpleTests::Test &test) { const plg::string expected = "0x0"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncPtr"); @@ -2788,7 +2912,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncFloat", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncFloat", [&](SimpleTests::Test &test) { const plg::string expected = "3.14"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncFloat"); @@ -2798,7 +2922,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncDouble", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncDouble", [&](SimpleTests::Test &test) { const plg::string expected = "6.28"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncDouble"); @@ -2808,7 +2932,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncString", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncString", [&](SimpleTests::Test &test) { const plg::string expected = "Test string"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncString"); @@ -2818,7 +2942,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncAny", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncAny", [&](SimpleTests::Test &test) { const plg::string expected = "A"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncAny"); @@ -2838,7 +2962,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } });*/ - _tests.Add("ReverseCallFuncBoolVector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncBoolVector", [&](SimpleTests::Test &test) { const plg::string expected = "{true, false}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncBoolVector"); @@ -2848,7 +2972,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncChar8Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncChar8Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{A, B}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncChar8Vector"); @@ -2858,7 +2982,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncChar16Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncChar16Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{65, 66}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncChar16Vector"); @@ -2868,7 +2992,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncInt8Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncInt8Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{10, 20}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncInt8Vector"); @@ -2878,7 +3002,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncInt16Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncInt16Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{100, 200}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncInt16Vector"); @@ -2888,7 +3012,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncInt32Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncInt32Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{1000, 2000}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncInt32Vector"); @@ -2898,7 +3022,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncInt64Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncInt64Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{10000, 20000}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncInt64Vector"); @@ -2908,7 +3032,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncUInt8Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncUInt8Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{20, 30}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncUInt8Vector"); @@ -2918,7 +3042,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncUInt16Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncUInt16Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{200, 300}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncUInt16Vector"); @@ -2928,7 +3052,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncUInt32Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncUInt32Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{2000, 3000}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncUInt32Vector"); @@ -2938,7 +3062,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncUInt64Vector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncUInt64Vector", [&](SimpleTests::Test &test) { const plg::string expected = "{20000, 30000}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncUInt64Vector"); @@ -2948,7 +3072,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncPtrVector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncPtrVector", [&](SimpleTests::Test &test) { const plg::string expected = "{0x0, 0x1}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncPtrVector"); @@ -2958,7 +3082,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncFloatVector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncFloatVector", [&](SimpleTests::Test &test) { const plg::string expected = "{1.1, 2.2}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncFloatVector"); @@ -2968,7 +3092,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncDoubleVector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncDoubleVector", [&](SimpleTests::Test &test) { const plg::string expected = "{3.3, 4.4}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncDoubleVector"); @@ -2978,7 +3102,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncStringVector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncStringVector", [&](SimpleTests::Test &test) { const plg::string expected = "{'Hello', 'World'}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncStringVector"); @@ -2988,7 +3112,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncAnyVector", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncAnyVector", [&](SimpleTests::Test &test) { const plg::string expected = "{Hello, 3.14, 6.28, 1, 3735928495}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncAnyVector"); @@ -2998,8 +3122,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncVec2Vector", [&](SimpleTests::Test& test) { - const plg::string expected = "{{0.5, -1.2}, {3.4, 7.8}, {-6.7, 2.3}, {8.9, -4.5}, {0, 0}}"; // Adjust this if needed + _tests.Add("ReverseCallFuncVec2Vector", [&](SimpleTests::Test &test) { + const plg::string expected = "{{0.5, -1.2}, {3.4, 7.8}, {-6.7, 2.3}, {8.9, -4.5}, {0, 0}}"; + // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncVec2Vector"); if (!_reverseReturn) { @@ -3008,8 +3133,10 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncVec3Vector", [&](SimpleTests::Test& test) { - const plg::string expected = "{{2.1, 3.2, 4.3}, {-5.4, 6.5, -7.6}, {8.7, 9.8, 0.1}, {1.2, -3.3, 4.4}, {-5.5, 6.6, -7.7}}"; // Adjust this if needed + _tests.Add("ReverseCallFuncVec3Vector", [&](SimpleTests::Test &test) { + const plg::string expected = + "{{2.1, 3.2, 4.3}, {-5.4, 6.5, -7.6}, {8.7, 9.8, 0.1}, {1.2, -3.3, 4.4}, {-5.5, 6.6, -7.7}}"; + // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncVec3Vector"); if (!_reverseReturn) { @@ -3018,8 +3145,10 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncVec4Vector", [&](SimpleTests::Test& test) { - const plg::string expected = "{{0.1, 1.2, 2.3, 3.4}, {-4.5, 5.6, 6.7, -7.8}, {8.9, -9, 10.1, -11.2}, {12.3, 13.4, 14.5, 15.6}, {-16.7, 17.8, 18.9, -19}}"; // Adjust this if needed + _tests.Add("ReverseCallFuncVec4Vector", [&](SimpleTests::Test &test) { + const plg::string expected = + "{{0.1, 1.2, 2.3, 3.4}, {-4.5, 5.6, 6.7, -7.8}, {8.9, -9, 10.1, -11.2}, {12.3, 13.4, 14.5, 15.6}, {-16.7, 17.8, 18.9, -19}}"; + // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncVec4Vector"); if (!_reverseReturn) { @@ -3028,8 +3157,10 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncMat4x4Vector", [&](SimpleTests::Test& test) { - const plg::string expected = "{{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}, {{0.5, 1, 1.5, 2}, {2.5, 3, 3.5, 4}, {4.5, 5, 5.5, 6}, {6.5, 7, 7.5, 8}}, {{-1, -2, -3, -4}, {-5, -6, -7, -8}, {-9, -10, -11, -12}, {-13, -14, -15, -16}}, {{1.1, 2.2, 3.3, 4.4}, {5.5, 6.6, 7.7, 8.8}, {9.9, 10, 11.1, 12.2}, {13.3, 14.4, 15.5, 16.6}}}"; // Adjust this if needed + _tests.Add("ReverseCallFuncMat4x4Vector", [&](SimpleTests::Test &test) { + const plg::string expected = + "{{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}, {{0.5, 1, 1.5, 2}, {2.5, 3, 3.5, 4}, {4.5, 5, 5.5, 6}, {6.5, 7, 7.5, 8}}, {{-1, -2, -3, -4}, {-5, -6, -7, -8}, {-9, -10, -11, -12}, {-13, -14, -15, -16}}, {{1.1, 2.2, 3.3, 4.4}, {5.5, 6.6, 7.7, 8.8}, {9.9, 10, 11.1, 12.2}, {13.3, 14.4, 15.5, 16.6}}}"; + // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncMat4x4Vector"); if (!_reverseReturn) { @@ -3038,7 +3169,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncVec2", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncVec2", [&](SimpleTests::Test &test) { const plg::string expected = "{1, 2}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncVec2"); @@ -3048,7 +3179,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncVec3", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncVec3", [&](SimpleTests::Test &test) { const plg::string expected = "{1, 2, 3}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncVec3"); @@ -3058,7 +3189,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncVec4", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncVec4", [&](SimpleTests::Test &test) { const plg::string expected = "{1, 2, 3, 4}"; // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncVec4"); @@ -3068,8 +3199,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncMat4x4", [&](SimpleTests::Test& test) { - const plg::string expected = "{{1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}"; // Adjust this if needed + _tests.Add("ReverseCallFuncMat4x4", [&](SimpleTests::Test &test) { + const plg::string expected = "{{1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}"; + // Adjust this if needed _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncMat4x4"); if (!_reverseReturn) { @@ -3079,7 +3211,7 @@ class CrossCallMaster final : public plg::IPluginEntry { } }); - _tests.Add("ReverseCallFunc1", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc1", [&](SimpleTests::Test &test) { const plg::string expected = "6"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc1"); @@ -3089,7 +3221,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc2", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc2", [&](SimpleTests::Test &test) { const plg::string expected = "&"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc2"); @@ -3099,10 +3231,10 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc3", [](SimpleTests::Test&) { + _tests.Add("ReverseCallFunc3", [](SimpleTests::Test &) { cross_call_worker::ReverseCall("CallFunc3"); }); - _tests.Add("ReverseCallFunc4", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc4", [&](SimpleTests::Test &test) { const plg::string expected = "{1, 2, 3, 4}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc4"); @@ -3112,7 +3244,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc5", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc5", [&](SimpleTests::Test &test) { const plg::string expected = "true"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc5"); @@ -3122,7 +3254,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc6", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc6", [&](SimpleTests::Test &test) { const plg::string expected = "11"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc6"); @@ -3132,7 +3264,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc7", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc7", [&](SimpleTests::Test &test) { const plg::string expected = "3.14"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc7"); @@ -3142,7 +3274,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc8", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc8", [&](SimpleTests::Test &test) { const plg::string expected = "{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc8"); @@ -3152,10 +3284,10 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc9", [](SimpleTests::Test&) { + _tests.Add("ReverseCallFunc9", [](SimpleTests::Test &) { cross_call_worker::ReverseCall("CallFunc9"); }); - _tests.Add("ReverseCallFunc10", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc10", [&](SimpleTests::Test &test) { const plg::string expected = "42"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc10"); @@ -3165,7 +3297,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc11", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc11", [&](SimpleTests::Test &test) { const plg::string expected = "0x0"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc11"); @@ -3175,7 +3307,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc12", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc12", [&](SimpleTests::Test &test) { const plg::string expected = "false"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc12"); @@ -3185,7 +3317,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc13", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc13", [&](SimpleTests::Test &test) { const plg::string expected = "Dummy String"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc13"); @@ -3195,7 +3327,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc14", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc14", [&](SimpleTests::Test &test) { const plg::string expected = "{'String1', 'String2'}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc14"); @@ -3205,7 +3337,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc15", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc15", [&](SimpleTests::Test &test) { const plg::string expected = "257"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc15"); @@ -3215,7 +3347,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc16", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc16", [&](SimpleTests::Test &test) { const plg::string expected = "0x0"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc16"); @@ -3225,7 +3357,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc17", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc17", [&](SimpleTests::Test &test) { const plg::string expected = "30"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc17"); @@ -3235,7 +3367,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc18", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc18", [&](SimpleTests::Test &test) { const plg::string expected = "{5, 10}|5|10"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc18"); @@ -3245,7 +3377,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc19", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc19", [&](SimpleTests::Test &test) { const plg::string expected = "42|{1, 2, 3}|{1, 2, 3}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc19"); @@ -3255,7 +3387,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc20", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc20", [&](SimpleTests::Test &test) { const plg::string expected = "0|116|{1, 2, 3, 4}|{100, 200}|F"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc20"); @@ -3265,8 +3397,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc21", [&](SimpleTests::Test& test) { - const plg::string expected = "0|{{1.3, 0.6, 0.8, 0.5}, {0.7, 1.1, 0.2, 0.4}, {0.9, 0.3, 1.2, 0.7}, {0.2, 0.8, 0.5, 1}}|{1, 2, 3}|{1, 2}|true|3.14"; + _tests.Add("ReverseCallFunc21", [&](SimpleTests::Test &test) { + const plg::string expected = + "0|{{1.3, 0.6, 0.8, 0.5}, {0.7, 1.1, 0.2, 0.4}, {0.9, 0.3, 1.2, 0.7}, {0.2, 0.8, 0.5, 1}}|{1, 2, 3}|{1, 2}|true|3.14"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc21"); if (!_reverseReturn) { @@ -3275,7 +3408,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc22", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc22", [&](SimpleTests::Test &test) { const plg::string expected = "0|0x0|99|{1.1, 2.2, 3.3}|123|Hello|{1, 2, 3, 4}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc22"); @@ -3285,7 +3418,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc23", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc23", [&](SimpleTests::Test &test) { const plg::string expected = "50|{3, 4}|{1, 2, 3, 4}|8548|1.5|-1|{1, 2, 3}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc23"); @@ -3295,8 +3428,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc24", [&](SimpleTests::Test& test) { - const plg::string expected = "{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}|{a, b, c}|64|{5, 6, 7}|{1, 2, 3, 4}|4294967295|{0x0}|2.71|{0x1, 0x1, 0x2, 0x2}"; + _tests.Add("ReverseCallFunc24", [&](SimpleTests::Test &test) { + const plg::string expected = + "{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}|{a, b, c}|64|{5, 6, 7}|{1, 2, 3, 4}|4294967295|{0x0}|2.71|{0x1, 0x1, 0x2, 0x2}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc24"); if (!_reverseReturn) { @@ -3305,7 +3439,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc25", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc25", [&](SimpleTests::Test &test) { const plg::string expected = "0|100|{0x0}|false|250|MockFunc25|{1, 2, 3}|1337|{4, 5, 6, 7}|64222"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc25"); @@ -3315,8 +3449,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc26", [&](SimpleTests::Test& test) { - const plg::string expected = "A|90|{2, 3}|{{0.9, 0.2, 0.4, 0.8}, {0.1, 1, 0.6, 0.3}, {0.7, 0.5, 0.2, 0.9}, {0.3, 0.4, 1.5, 0.1}}|{1.1, 2.2}|64|32|{100, 200}|0xdeadbeafdeadbeaf|true"; + _tests.Add("ReverseCallFunc26", [&](SimpleTests::Test &test) { + const plg::string expected = + "A|90|{2, 3}|{{0.9, 0.2, 0.4, 0.8}, {0.1, 1, 0.6, 0.3}, {0.7, 0.5, 0.2, 0.9}, {0.3, 0.4, 1.5, 0.1}}|{1.1, 2.2}|64|32|{100, 200}|0xdeadbeafdeadbeaf|true"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc26"); if (!_reverseReturn) { @@ -3325,8 +3460,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc27", [&](SimpleTests::Test& test) { - const plg::string expected = "0|1|{-1, -2, -3}|0xdeadbeafdeadbeaf|{-111, 111}|{1, 2, 3, 4}|{{1, 0.5, 0.3, 0.7}, {0.8, 1.2, 0.6, 0.9}, {1.5, 1.1, 0.4, 0.2}, {0.3, 0.9, 0.7, 1}}|true|{1, 2, 3, 4}|111|30"; + _tests.Add("ReverseCallFunc27", [&](SimpleTests::Test &test) { + const plg::string expected = + "0|1|{-1, -2, -3}|0xdeadbeafdeadbeaf|{-111, 111}|{1, 2, 3, 4}|{{1, 0.5, 0.3, 0.7}, {0.8, 1.2, 0.6, 0.9}, {1.5, 1.1, 0.4, 0.2}, {0.3, 0.9, 0.7, 1}}|true|{1, 2, 3, 4}|111|30"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc27"); if (!_reverseReturn) { @@ -3335,8 +3471,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc28", [&](SimpleTests::Test& test) { - const plg::string expected = "MockFunc28|0x0|65500|{1, 2, 3, 4, 5, 7}|{{1.4, 0.7, 0.2, 0.5}, {0.3, 1.1, 0.6, 0.8}, {0.9, 0.4, 1.3, 0.1}, {0.6, 0.2, 0.7, 1}}|5.5|{1, 2, 3, 4}|MockFunc28|{1, 2}|834748377834|true|{10, 20, 30}"; + _tests.Add("ReverseCallFunc28", [&](SimpleTests::Test &test) { + const plg::string expected = + "MockFunc28|0x0|65500|{1, 2, 3, 4, 5, 7}|{{1.4, 0.7, 0.2, 0.5}, {0.3, 1.1, 0.6, 0.8}, {0.9, 0.4, 1.3, 0.1}, {0.6, 0.2, 0.7, 1}}|5.5|{1, 2, 3, 4}|MockFunc28|{1, 2}|834748377834|true|{10, 20, 30}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc28"); if (!_reverseReturn) { @@ -3345,8 +3482,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc29", [&](SimpleTests::Test& test) { - const plg::string expected = "{'Example', 'MockFunc29'}|{1, 2, 3, 4}|30|{127, 126, 125}|3.14|true|8|{100, 200}|1.5|MockFunc29|{{0.4, 1, 0.6, 0.3}, {1.2, 0.8, 0.5, 0.9}, {0.7, 0.3, 1.4, 0.6}, {0.1, 0.9, 0.8, 1.3}}|64"; + _tests.Add("ReverseCallFunc29", [&](SimpleTests::Test &test) { + const plg::string expected = + "{'Example', 'MockFunc29'}|{1, 2, 3, 4}|30|{127, 126, 125}|3.14|true|8|{100, 200}|1.5|MockFunc29|{{0.4, 1, 0.6, 0.3}, {1.2, 0.8, 0.5, 0.9}, {0.7, 0.3, 1.4, 0.6}, {0.1, 0.9, 0.8, 1.3}}|64"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc29"); if (!_reverseReturn) { @@ -3355,8 +3493,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc30", [&](SimpleTests::Test& test) { - const plg::string expected = "42|0x0|{1, 2, 3, 4}|1000|{100, 200}|false|MockFunc30|{1, 2, 3}|{255, 0, 255, 200, 100, 200}|1.1|{3, 4}|{{0.5, 0.3, 1, 0.7}, {1.1, 0.9, 0.6, 0.4}, {0.2, 0.8, 1.5, 0.3}, {0.7, 0.4, 0.9, 1}}|8|{1, 1, 2, 2}"; + _tests.Add("ReverseCallFunc30", [&](SimpleTests::Test &test) { + const plg::string expected = + "42|0x0|{1, 2, 3, 4}|1000|{100, 200}|false|MockFunc30|{1, 2, 3}|{255, 0, 255, 200, 100, 200}|1.1|{3, 4}|{{0.5, 0.3, 1, 0.7}, {1.1, 0.9, 0.6, 0.4}, {0.2, 0.8, 1.5, 0.3}, {0.7, 0.4, 0.9, 1}}|8|{1, 1, 2, 2}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc30"); if (!_reverseReturn) { @@ -3365,8 +3504,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc31", [&](SimpleTests::Test& test) { - const plg::string expected = "C|12345|{1, 2, 3, 4, 5}|{1, 2, 3, 4}|MockFunc31|true|123456789|{5, 6}|7|255|{1, 2}|{{0.8, 0.5, 1.2, 0.3}, {1, 0.7, 0.4, 0.6}, {0.9, 0.2, 0.5, 1.4}, {0.6, 0.8, 1.1, 0.7}}|{1, 2, 3}"; + _tests.Add("ReverseCallFunc31", [&](SimpleTests::Test &test) { + const plg::string expected = + "C|12345|{1, 2, 3, 4, 5}|{1, 2, 3, 4}|MockFunc31|true|123456789|{5, 6}|7|255|{1, 2}|{{0.8, 0.5, 1.2, 0.3}, {1, 0.7, 0.4, 0.6}, {0.9, 0.2, 0.5, 1.4}, {0.6, 0.8, 1.1, 0.7}}|{1, 2, 3}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc31"); if (!_reverseReturn) { @@ -3375,8 +3515,9 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc32", [&](SimpleTests::Test& test) { - const plg::string expected = "42|255|{0, 1}|{4, 5, 6, 7}|0x0|{100, 200}|{{1, 0.4, 0.3, 0.9}, {0.7, 1.2, 0.5, 0.8}, {0.2, 0.6, 1.1, 0.4}, {0.9, 0.3, 0.8, 1.5}}|123456789|MockFunc32|1000|{2.5, 3.5}|{1, 2, 3, 4, 5, 9}|false|{0, 0, 0}|8|{97, 98, 99}"; + _tests.Add("ReverseCallFunc32", [&](SimpleTests::Test &test) { + const plg::string expected = + "42|255|{0, 1}|{4, 5, 6, 7}|0x0|{100, 200}|{{1, 0.4, 0.3, 0.9}, {0.7, 1.2, 0.5, 0.8}, {0.2, 0.6, 1.1, 0.4}, {0.9, 0.3, 0.8, 1.5}}|123456789|MockFunc32|1000|{2.5, 3.5}|{1, 2, 3, 4, 5, 9}|false|{0, 0, 0}|8|{97, 98, 99}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc32"); if (!_reverseReturn) { @@ -3385,7 +3526,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFunc33", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFunc33", [&](SimpleTests::Test &test) { const plg::string expected = "MockFunc33"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFunc33"); @@ -3395,7 +3536,7 @@ class CrossCallMaster final : public plg::IPluginEntry { test.Fail(std::format("Wrong ref params return {}, expected {}", *_reverseReturn, expected)); } }); - _tests.Add("ReverseCallFuncEnum", [&](SimpleTests::Test& test) { + _tests.Add("ReverseCallFuncEnum", [&](SimpleTests::Test &test) { const plg::string expected = "{1, 4}|{1, 2, 3}"; _reverseReturn.reset(); cross_call_worker::ReverseCall("CallFuncEnum"); @@ -3407,20 +3548,21 @@ class CrossCallMaster final : public plg::IPluginEntry { }); #endif// TEST_CASES & TEST_REVERSE_PARAMS_FUNCTIONS - } + } public: - void ReverseReturn(const plg::string& returnString) { - _reverseReturn = {returnString}; - } - void ReverseParams(const plg::string& paramsString) { - _reverseParams = {paramsString}; - } + void ReverseReturn(const plg::string &returnString) { + _reverseReturn = {returnString}; + } + + void ReverseParams(const plg::string ¶msString) { + _reverseParams = {paramsString}; + } private: - SimpleTests _tests; - std::optional _reverseReturn; - std::optional _reverseParams; + SimpleTests _tests; + std::optional _reverseReturn; + std::optional _reverseParams; }; CrossCallMaster g_plugin; @@ -3429,14 +3571,16 @@ EXPOSE_PLUGIN(PLUGIN_API, CrossCallMaster, &g_plugin) PLUGIFY_WARN_PUSH() #if defined(__clang__) -PLUGIFY_WARN_IGNORE("-Wreturn-type-c-linkage") +PLUGIFY_WARN_IGNORE ("-Wreturn-type-c-linkage") #elif defined(_MSC_VER) -PLUGIFY_WARN_IGNORE(4190) +PLUGIFY_WARN_IGNORE ( +4190 +) #endif extern "C" -PLUGIN_API void ReverseReturn(const plg::string& returnString) { - g_plugin.ReverseReturn(returnString); +PLUGIN_API void ReverseReturn(const plg::string &returnString) { + g_plugin.ReverseReturn(returnString); } extern "C" @@ -3445,88 +3589,88 @@ PLUGIN_API void NoParamReturnVoidCallback() { extern "C" PLUGIN_API bool NoParamReturnBoolCallback() { - return true; + return true; } extern "C" PLUGIN_API char NoParamReturnChar8Callback() { - return 'P'; + return 'P'; } extern "C" PLUGIN_API char16_t NoParamReturnChar16Callback() { - return u'Ф'; + return u'Ф'; } extern "C" PLUGIN_API int8_t NoParamReturnInt8Callback() { - return 123; + return 123; } extern "C" PLUGIN_API int16_t NoParamReturnInt16Callback() { - return 32765; + return 32765; } extern "C" PLUGIN_API int32_t NoParamReturnInt32Callback() { - return 2112211221; + return 2112211221; } extern "C" PLUGIN_API int64_t NoParamReturnInt64Callback() { - return 0x7654321001234567; + return 0x7654321001234567; } extern "C" PLUGIN_API uint8_t NoParamReturnUInt8Callback() { - return 0xCD; + return 0xCD; } extern "C" PLUGIN_API uint16_t NoParamReturnUInt16Callback() { - return 0xCDCD; + return 0xCDCD; } extern "C" PLUGIN_API uint32_t NoParamReturnUInt32Callback() { - return 0xCDCDCDCD; + return 0xCDCDCDCD; } extern "C" PLUGIN_API uint64_t NoParamReturnUInt64Callback() { - return 0xCDCDCDCDCDCDCDCD; + return 0xCDCDCDCDCDCDCDCD; } extern "C" -PLUGIN_API void* NoParamReturnPointerCallback() { - return reinterpret_cast(0xAABBCCDD87655678); +PLUGIN_API void *NoParamReturnPointerCallback() { + return reinterpret_cast(0xAABBCCDD87655678); } extern "C" PLUGIN_API float NoParamReturnFloatCallback() { - return 0.123f; + return 0.123f; } extern "C" PLUGIN_API double NoParamReturnDoubleCallback() { - return 987.321; + return 987.321; } using NoParamReturnFunctionCallbackFunc = int32_t (*)(); int32_t DaysInYear() { - return 365; + return 365; } extern "C" PLUGIN_API NoParamReturnFunctionCallbackFunc NoParamReturnFunctionCallback() { - return &DaysInYear; + return &DaysInYear; } extern "C" PLUGIN_API plg::string NoParamReturnStringCallback() { - return "Convertiplane"; + return "Convertiplane"; } extern "C" @@ -3537,82 +3681,91 @@ PLUGIN_API plg::any NoParamReturnAnyCallback() { extern "C" PLUGIN_API plg::vector NoParamReturnArrayBoolCallback() { - return {false, true, true}; + return {false, true, true}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayChar8Callback() { - return {'p', 'l', 'u', 'g'}; + return {'p', 'l', 'u', 'g'}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayChar16Callback() { - return {u'ч', u'а', u'р', u'!'}; + return {u'ч', u'а', u'р', u'!'}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayInt8Callback() { - return {10, -15, 20}; + return {10, -15, 20}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayInt16Callback() { - return {10, -15, 20, -25}; + return {10, -15, 20, -25}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayInt32Callback() { - return {10, -15, 20, -25, 30}; + return {10, -15, 20, -25, 30}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayInt64Callback() { - return {10, -15, 20, -25, 30, -35}; + return {10, -15, 20, -25, 30, -35}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayUInt8Callback() { - return {1, 2, 3, 200}; + return {1, 2, 3, 200}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayUInt16Callback() { - return {1, 2, 3, 200, 60000}; + return {1, 2, 3, 200, 60000}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayUInt32Callback() { - return {1, 2, 3, 200, 60000, 4000000000}; + return {1, 2, 3, 200, 60000, 4000000000}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayUInt64Callback() { - return {1, 2, 3, 200, 60000, 4000000000, 12223334445556667778ULL}; + return {1, 2, 3, 200, 60000, 4000000000, 12223334445556667778ULL}; } extern "C" -PLUGIN_API plg::vector NoParamReturnArrayPointerCallback() { - return {reinterpret_cast(0x0), reinterpret_cast(0xdeadbeafLL), reinterpret_cast(0xcdccddcccdddcccc)}; +PLUGIN_API plg::vector NoParamReturnArrayPointerCallback() { + return { + reinterpret_cast(0x0), reinterpret_cast(0xdeadbeafLL), + reinterpret_cast(0xcdccddcccdddcccc) + }; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayFloatCallback() { - return {1.1f, -10.82f, 555.555f}; + return {1.1f, -10.82f, 555.555f}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayDoubleCallback() { - return {1.1, -10.82, 555.555, 55555.55555, 123456789.98765}; + return {1.1, -10.82, 555.555, 55555.55555, 123456789.98765}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayStringCallback() { - return {"5", "true", "0.0", "Hello", "And Goodbay", "Another long string to test. Pi equal 3,1415926535 8979323846 2643383279 5028841971 6939937510"}; + return { + "5", "true", "0.0", "Hello", "And Goodbay", + "Another long string to test. Pi equal 3,1415926535 8979323846 2643383279 5028841971 6939937510" + }; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayAnyCallback() { - plg::vector result{5, true, 0.0, "Hello", nullptr, "Short string to test.", 3.1415926535f, 8979323846, 2643383279, 5028841971, 6939937510, plg::vector{1, 2, 3, 4, 5}}; + plg::vector result{ + 5, true, 0.0, "Hello", nullptr, "Short string to test.", 3.1415926535f, 8979323846, 2643383279, 5028841971, + 6939937510, plg::vector{1, 2, 3, 4, 5} + }; return result; } @@ -3652,250 +3805,271 @@ PLUGIN_API plg::vector NoParamReturnArrayVector4Callback() { extern "C" PLUGIN_API plg::vector NoParamReturnArrayMatrix4x4Callback() { return { - // Identity matrix - { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }, - // Random matrix #1 - { - 1.5f, 2.0f, 3.0f, 4.0f, - 5.0f, 6.5f, 7.0f, 8.0f, - 9.0f, 10.5f, 11.0f, 12.0f, - 13.0f, 14.5f, 15.0f, 16.0f - }, - // Random matrix #2 - { - 0.0f, -1.0f, -2.0f, -3.0f, - 4.0f, 0.0f, -5.0f, -6.0f, - 7.0f, 8.0f, 0.0f, -9.0f, - 10.0f, 11.0f, 12.0f, 0.0f - } + // Identity matrix + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }, + // Random matrix #1 + { + 1.5f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.5f, 7.0f, 8.0f, + 9.0f, 10.5f, 11.0f, 12.0f, + 13.0f, 14.5f, 15.0f, 16.0f + }, + // Random matrix #2 + { + 0.0f, -1.0f, -2.0f, -3.0f, + 4.0f, 0.0f, -5.0f, -6.0f, + 7.0f, 8.0f, 0.0f, -9.0f, + 10.0f, 11.0f, 12.0f, 0.0f + } }; } extern "C" PLUGIN_API plg::vec2 NoParamReturnVector2Callback() { - return {100.9f, 200.8f}; + return {100.9f, 200.8f}; } extern "C" PLUGIN_API plg::vec3 NoParamReturnVector3Callback() { - return {100.9f, 200.8f, 300.7f}; + return {100.9f, 200.8f, 300.7f}; } extern "C" PLUGIN_API plg::vec4 NoParamReturnVector4Callback() { - return {100.9f, 200.8f, 300.7f, 400.6f}; + return {100.9f, 200.8f, 300.7f, 400.6f}; } extern "C" PLUGIN_API plg::mat4x4 NoParamReturnMatrix4x4Callback() { - return {1.1f, 2.2f, 3.3f, 4.4f, 9.9f, 1.1f, 2.2f, 3.3f, 8.8f, 9.9f, 1.1f, 2.2f, 7.7f, 8.8f, 9.9f, 1.1f}; + return {1.1f, 2.2f, 3.3f, 4.4f, 9.9f, 1.1f, 2.2f, 3.3f, 8.8f, 9.9f, 1.1f, 2.2f, 7.7f, 8.8f, 9.9f, 1.1f}; } extern "C" PLUGIN_API void Param1Callback(int32_t a) { - g_plugin.ReverseParams(std::format("{}", a)); + g_plugin.ReverseParams(std::format("{}", a)); } extern "C" PLUGIN_API void Param2Callback(int32_t a, float b) { - g_plugin.ReverseParams(std::format("{}|{}", a, b)); + g_plugin.ReverseParams(std::format("{}|{}", a, b)); } extern "C" PLUGIN_API void Param3Callback(int32_t a, float b, double c) { - g_plugin.ReverseParams(std::format("{}|{}|{}", a, b, c)); + g_plugin.ReverseParams(std::format("{}|{}|{}", a, b, c)); } extern "C" -PLUGIN_API void Param4Callback(int32_t a, float b, double c, const plg::vec4& d) { - g_plugin.ReverseParams(std::format("{}|{}|{}|{}", a, b, c, d)); +PLUGIN_API void Param4Callback(int32_t a, float b, double c, const plg::vec4 &d) { + g_plugin.ReverseParams(std::format("{}|{}|{}|{}", a, b, c, d)); } extern "C" -PLUGIN_API void Param5Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e) { - g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}", a, b, c, d, e)); +PLUGIN_API void Param5Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e) { + g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}", a, b, c, d, e)); } extern "C" -PLUGIN_API void Param6Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f) { - g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f))); +PLUGIN_API void Param6Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, + char f) { + g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f))); } extern "C" -PLUGIN_API void Param7Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g) { - g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f), g)); +PLUGIN_API void Param7Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g) { + g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f), g)); } extern "C" -PLUGIN_API void Param8Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h) { - g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f), g, static_cast(h))); +PLUGIN_API void Param8Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h) { + g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f), g, + static_cast(h))); } extern "C" -PLUGIN_API void Param9Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h, int16_t k) { - g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f), g, static_cast(h), k)); +PLUGIN_API void Param9Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h, int16_t k) { + g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f), g, + static_cast(h), k)); } extern "C" -PLUGIN_API void Param10Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h, int16_t k, void* l) { - g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f), g, static_cast(h), k, l)); +PLUGIN_API void Param10Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h, int16_t k, void *l) { + g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f), g, + static_cast(h), k, l)); } extern "C" -PLUGIN_API void ParamRef1Callback(int32_t& a) { - a = 147; +PLUGIN_API void ParamRef1Callback(int32_t &a) { + a = 147; } extern "C" -PLUGIN_API void ParamRef2Callback(int32_t& a, float& b) { - a = 852; - b = 0.1f; +PLUGIN_API void ParamRef2Callback(int32_t &a, float &b) { + a = 852; + b = 0.1f; } extern "C" -PLUGIN_API void ParamRef3Callback(int32_t& a, float& b, double& c) { - a = 369; - b = 0.2f; - c = 11111.11111; +PLUGIN_API void ParamRef3Callback(int32_t &a, float &b, double &c) { + a = 369; + b = 0.2f; + c = 11111.11111; } extern "C" -PLUGIN_API void ParamRef4Callback(int32_t& a, float& b, double& c, plg::vec4& d) { - a = 987; - b = 0.3f; - c = 22222.22222; - d = {4.4f, 3.3f, 2.2f, 1.1f}; +PLUGIN_API void ParamRef4Callback(int32_t &a, float &b, double &c, plg::vec4 &d) { + a = 987; + b = 0.3f; + c = 22222.22222; + d = {4.4f, 3.3f, 2.2f, 1.1f}; } extern "C" -PLUGIN_API void ParamRef5Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e) { - a = 456; - b = 0.4f; - c = 33333.33333; - d = {1.4f, 4.3f, 3.2f, 2.1f}; - e = {}; +PLUGIN_API void ParamRef5Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e) { + a = 456; + b = 0.4f; + c = 33333.33333; + d = {1.4f, 4.3f, 3.2f, 2.1f}; + e = {}; } extern "C" -PLUGIN_API void ParamRef6Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f) { - a = 321; - b = 0.5f; - c = 44444.44444; - d = {1.1f, 4.4f, 3.3f, 2.2f}; - e = {99}; - f = 'z'; +PLUGIN_API void ParamRef6Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f) { + a = 321; + b = 0.5f; + c = 44444.44444; + d = {1.1f, 4.4f, 3.3f, 2.2f}; + e = {99}; + f = 'z'; } extern "C" -PLUGIN_API void ParamRef7Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g) { - a = 157; - b = 0.6f; - c = 55555.55555; - d = {2.1f, 1.4f, 4.3f, 3.2f}; - e = {99, 8888}; - f = 'y'; - g = "my string"; +PLUGIN_API void ParamRef7Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g) { + a = 157; + b = 0.6f; + c = 55555.55555; + d = {2.1f, 1.4f, 4.3f, 3.2f}; + e = {99, 8888}; + f = 'y'; + g = "my string"; } extern "C" -PLUGIN_API void ParamRef8Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h) { - a = 759; - b = 0.7f; - c = 66666.66666; - d = {2.2f, 1.1f, 4.4f, 3.3f}; - e = {99, 8888, 777777}; - f = 'x'; - g = "his string"; - h = u'ъ'; +PLUGIN_API void ParamRef8Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h) { + a = 759; + b = 0.7f; + c = 66666.66666; + d = {2.2f, 1.1f, 4.4f, 3.3f}; + e = {99, 8888, 777777}; + f = 'x'; + g = "his string"; + h = u'ъ'; } extern "C" -PLUGIN_API void ParamRef9Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h, int16_t& k) { - a = 953; - b = 0.8f; - c = 77777.77777; - d = {3.2f, 2.1f, 1.4f, 4.3f}; - e = {99, 8888, 777777, 66666666}; - f = 'w'; - g = "her string"; - h = u'ы'; - k = -30003; +PLUGIN_API void ParamRef9Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h, int16_t &k) { + a = 953; + b = 0.8f; + c = 77777.77777; + d = {3.2f, 2.1f, 1.4f, 4.3f}; + e = {99, 8888, 777777, 66666666}; + f = 'w'; + g = "her string"; + h = u'ы'; + k = -30003; } extern "C" -PLUGIN_API void ParamRef10Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h, int16_t& k, void*& l) { - a = 351; - b = 0.9f; - c = 88888.88888; - d = {3.3f, 2.2f, 1.1f, 4.4f}; - e = {99, 8888, 777777, 66666666, 5555555555}; - f = 'v'; - g = "they string"; - h = u'ь'; - k = 30003; - l = reinterpret_cast(0xabcdefLL); +PLUGIN_API void ParamRef10Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h, int16_t &k, void *&l) { + a = 351; + b = 0.9f; + c = 88888.88888; + d = {3.3f, 2.2f, 1.1f, 4.4f}; + e = {99, 8888, 777777, 66666666, 5555555555}; + f = 'v'; + g = "they string"; + h = u'ь'; + k = 30003; + l = reinterpret_cast(0xabcdefLL); } extern "C" -PLUGIN_API void ParamRefVectorsCallback(plg::vector& p1, plg::vector& p2, plg::vector& p3, plg::vector& p4, plg::vector& p5, - plg::vector& p6, plg::vector& p7, plg::vector& p8, plg::vector& p9, plg::vector& p10, plg::vector& p11, - plg::vector& p12, plg::vector& p13, plg::vector& p14, plg::vector& p15 +PLUGIN_API void ParamRefVectorsCallback(plg::vector &p1, plg::vector &p2, plg::vector &p3, + plg::vector &p4, plg::vector &p5, + plg::vector &p6, plg::vector &p7, plg::vector &p8, + plg::vector &p9, plg::vector &p10, + plg::vector &p11, + plg::vector &p12, plg::vector &p13, plg::vector &p14, + plg::vector &p15 ) { - p1 = {true, false}; - p2 = {'^'}; - p3 = {u'я', u'ц'}; - p4 = {-4, -3, -2, -1}; - p5 = {-555, -444, -333}; - p6 = {-66666, -77777}; - p7 = {-7666555444}; - p8 = {0, 1, 1, 2, 3, 5}; - p9 = {32999}; - p10 = {3000000000, 1}; - p11 = {1, 22, 333, 4444, 55555, 999999999999}; - p12 = {reinterpret_cast(13LL), reinterpret_cast(9LL), reinterpret_cast(5LL), reinterpret_cast(1LL)}; - p13 = {91.23f, 12.34f, 23.45f, 8.08f}; - p14 = {777.777777}; - p15 = {"one", "1 two", "1 2 three"}; -} - -extern "C" -PLUGIN_API int64_t ParamAllPrimitivesCallback(bool p1, char p2, char16_t p3, int8_t p4, int16_t p5, int32_t p6, int64_t p7, uint8_t p8, uint16_t p9, uint32_t p10, - uint64_t p11, void* p12, float p13, double p14 + p1 = {true, false}; + p2 = {'^'}; + p3 = {u'я', u'ц'}; + p4 = {-4, -3, -2, -1}; + p5 = {-555, -444, -333}; + p6 = {-66666, -77777}; + p7 = {-7666555444}; + p8 = {0, 1, 1, 2, 3, 5}; + p9 = {32999}; + p10 = {3000000000, 1}; + p11 = {1, 22, 333, 4444, 55555, 999999999999}; + p12 = { + reinterpret_cast(13LL), reinterpret_cast(9LL), reinterpret_cast(5LL), + reinterpret_cast(1LL) + }; + p13 = {91.23f, 12.34f, 23.45f, 8.08f}; + p14 = {777.777777}; + p15 = {"one", "1 two", "1 2 three"}; +} + +extern "C" +PLUGIN_API int64_t ParamAllPrimitivesCallback(bool p1, char p2, char16_t p3, int8_t p4, int16_t p5, int32_t p6, + int64_t p7, uint8_t p8, uint16_t p9, uint32_t p10, + uint64_t p11, void *p12, float p13, double p14 ) { - g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", p1, static_cast(p2), static_cast(p3), p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14)); - return 65; + g_plugin.ReverseParams(std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", p1, static_cast(p2), + static_cast(p3), p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14)); + return 65; } extern "C" -PLUGIN_API int32_t ParamEnumCallback(Example p1, const plg::vector& p2) { +PLUGIN_API int32_t ParamEnumCallback(Example p1, const plg::vector &p2) { return static_cast(p1) + std::accumulate(p2.begin(), p2.end(), int32_t{0}, - [](int32_t sum, const Example& e) { - return sum + static_cast(e); - }); + [](int32_t sum, const Example &e) { + return sum + static_cast(e); + }); } extern "C" -PLUGIN_API int32_t ParamEnumRefCallback(Example& p1, plg::vector& p2) { +PLUGIN_API int32_t ParamEnumRefCallback(Example &p1, plg::vector &p2) { p1 = Example::First; p2 = plg::vector{Example::First, Example::First, Example::Second}; return static_cast(p1) + std::accumulate(p2.begin(), p2.end(), int32_t{0}, - [](int32_t sum, const Example& e) { - return sum + static_cast(e); - }); + [](int32_t sum, const Example &e) { + return sum + static_cast(e); + }); } extern "C" -PLUGIN_API void ParamVariantCallback(const plg::any& p1, const plg::vector& p2) { +PLUGIN_API void ParamVariantCallback(const plg::any &p1, const plg::vector &p2) { g_plugin.ReverseParams(std::format("{}|{}", p1, p2)); } extern "C" -PLUGIN_API void ParamVariantRefCallback(plg::any& p1, plg::vector& p2) { +PLUGIN_API void ParamVariantRefCallback(plg::any &p1, plg::vector &p2) { p1 = plg::vector{1, 2, 3}; p2.resize(3); p2[0] = true; @@ -3976,8 +4150,8 @@ PLUGIN_API uint64_t CallFuncUInt64Callback(cross_call_worker::FuncUInt64 func) { } extern "C" -PLUGIN_API void* CallFuncPtrCallback(cross_call_worker::FuncPtr func) { - void* result = func(); +PLUGIN_API void *CallFuncPtrCallback(cross_call_worker::FuncPtr func) { + void *result = func(); return result; } @@ -3994,8 +4168,8 @@ PLUGIN_API double CallFuncDoubleCallback(cross_call_worker::FuncDouble func) { } extern "C" -PLUGIN_API void* CallFuncFunctionCallback(cross_call_worker::FuncFunction func) { - void* result = func(); +PLUGIN_API void *CallFuncFunctionCallback(cross_call_worker::FuncFunction func) { + void *result = func(); return result; } @@ -4079,8 +4253,8 @@ PLUGIN_API plg::vector CallFuncUInt64VectorCallback(cross_call_worker: } extern "C" -PLUGIN_API plg::vector CallFuncPtrVectorCallback(cross_call_worker::FuncPtrVector func) { - plg::vector result = func(); +PLUGIN_API plg::vector CallFuncPtrVectorCallback(cross_call_worker::FuncPtrVector func) { + plg::vector result = func(); return std::move(result); } @@ -4175,7 +4349,7 @@ PLUGIN_API char CallFunc2Callback(cross_call_worker::Func2 func) { // 3 parameters extern "C" PLUGIN_API void CallFunc3Callback(cross_call_worker::Func3 func) { - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer plg::vec4 vec4{1.0f, 2.0f, 3.0f, 4.0f}; plg::string str = "Test"; func(ptr, vec4, str); @@ -4196,7 +4370,7 @@ extern "C" PLUGIN_API bool CallFunc5Callback(cross_call_worker::Func5 func) { int8_t i8 = 5; plg::vec2 vec2{1.0f, 2.0f}; - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer double d = 3.14; plg::vector vec64{1, 2, 3}; return func(i8, vec2, ptr, d, vec64); @@ -4210,7 +4384,7 @@ PLUGIN_API int64_t CallFunc6Callback(cross_call_worker::Func6 func) { plg::vector vecF{1.0f, 2.0f, 3.0f}; int16_t i16 = 10; plg::vector vecU8{0, 1, 2}; - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer return func(str, f, vecF, i16, vecU8, ptr); } @@ -4235,7 +4409,7 @@ PLUGIN_API plg::mat4x4 CallFunc8Callback(cross_call_worker::Func8 func) { int16_t i16 = 10; bool b = true; plg::vec4 vec4{1.0f, 2.0f, 3.0f, 4.0f}; - plg::vector vecC16{ 'A', 'B' }; + plg::vector vecC16{'A', 'B'}; char16_t ch16 = L'A'; int32_t i32 = 20; return func(vec3, vecU32, i16, b, vec4, vecC16, ch16, i32); @@ -4252,7 +4426,7 @@ PLUGIN_API void CallFunc9Callback(cross_call_worker::Func9 func) { plg::string str = "Test"; plg::vec4 vec4{1.0f, 2.0f, 3.0f, 4.0f}; int16_t i16 = 10; - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer func(f, vec2, vecI8, u64, b, str, vec4, i16, ptr); } @@ -4274,7 +4448,7 @@ PLUGIN_API uint32_t CallFunc10Callback(cross_call_worker::Func10 func) { // 11 parameters extern "C" -PLUGIN_API void* CallFunc11Callback(cross_call_worker::Func11 func) { +PLUGIN_API void *CallFunc11Callback(cross_call_worker::Func11 func) { plg::vector vecB{true, false, true}; char16_t ch16 = 'A'; uint8_t u8 = 5; @@ -4292,7 +4466,7 @@ PLUGIN_API void* CallFunc11Callback(cross_call_worker::Func11 func) { // 12 parameters extern "C" PLUGIN_API bool CallFunc12Callback(cross_call_worker::Func12 func) { - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer plg::vector vecD{1.0, 2.0, 3.0}; uint32_t u32 = 10; double d = 3.14; @@ -4301,7 +4475,7 @@ PLUGIN_API bool CallFunc12Callback(cross_call_worker::Func12 func) { int8_t i8 = 5; uint64_t u64 = 100; float f = 1.23f; - plg::vector vecPtr{nullptr, reinterpret_cast(1), reinterpret_cast(2)}; + plg::vector vecPtr{nullptr, reinterpret_cast(1), reinterpret_cast(2)}; int64_t i64 = 50; char ch = 'A'; return func(ptr, vecD, u32, d, b, i32, i8, u64, f, vecPtr, i64, ch); @@ -4319,7 +4493,7 @@ PLUGIN_API plg::string CallFunc13Callback(cross_call_worker::Func13 func) { plg::string str = "Test"; int32_t i32 = 20; plg::vec3 vec3{1.0f, 2.0f, 3.0f}; - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer plg::vec2 vec2{1.0f, 2.0f}; plg::vector vecU8{0, 1, 2}; int16_t i16 = 10; @@ -4343,7 +4517,7 @@ PLUGIN_API plg::vector CallFunc14Callback(cross_call_worker::Func14 plg::vec3 vec3{1.0f, 2.0f, 3.0f}; plg::vec4 vec4{1.0f, 2.0f, 3.0f, 4.0f}; double d = 3.14; - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer auto ret = func(vecC, vecU32, mat, b, ch16, i32, vecF, u16, vecU8, i8, vec3, vec4, d, ptr); return std::move(ret); } @@ -4354,7 +4528,7 @@ PLUGIN_API int16_t CallFunc15Callback(cross_call_worker::Func15 func) { plg::vector vecI16{1, 2, 3}; plg::mat4x4 mat; // Assume it's initialized properly plg::vec4 vec4{1.0f, 2.0f, 3.0f, 4.0f}; - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer uint64_t u64 = 100; plg::vector vecU32{1, 2, 3}; bool b = true; @@ -4371,7 +4545,7 @@ PLUGIN_API int16_t CallFunc15Callback(cross_call_worker::Func15 func) { // 16 parameters extern "C" -PLUGIN_API void* CallFunc16Callback(cross_call_worker::Func16 func) { +PLUGIN_API void *CallFunc16Callback(cross_call_worker::Func16 func) { plg::vector vecB{true, false, true}; int16_t i16 = 10; plg::vector vecI8{1, 2, 3}; @@ -4446,7 +4620,7 @@ PLUGIN_API plg::string CallFunc21Callback(cross_call_worker::Func21 func) { // 6 parameters extern "C" PLUGIN_API plg::string CallFunc22Callback(cross_call_worker::Func22 func) { - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer uint32_t u32 = 10; plg::vector vecD{1.0, 2.0, 3.0}; int16_t i16 = 10; @@ -4478,9 +4652,12 @@ PLUGIN_API plg::string CallFunc24Callback(cross_call_worker::Func24 func) { plg::vector vecU8{0, 1, 2}; plg::vec4 vec4{1.0f, 2.0f, 3.0f, 4.0f}; uint64_t u64 = 100; - plg::vector vecPtr{ nullptr, reinterpret_cast(1), reinterpret_cast(2) }; + plg::vector vecPtr{nullptr, reinterpret_cast(1), reinterpret_cast(2)}; double d = 3.14; - plg::vector vecV2{ reinterpret_cast(1), reinterpret_cast(2), reinterpret_cast(3), reinterpret_cast(4) }; + plg::vector vecV2{ + reinterpret_cast(1), reinterpret_cast(2), reinterpret_cast(3), + reinterpret_cast(4) + }; plg::mat4x4 ret = func(vecC, i64, vecU8, vec4, u64, vecPtr, d, vecV2); return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, vecC, i64, vecU8, vec4, u64, vecPtr, d, vecV2); } @@ -4489,7 +4666,7 @@ PLUGIN_API plg::string CallFunc24Callback(cross_call_worker::Func24 func) { extern "C" PLUGIN_API plg::string CallFunc25Callback(cross_call_worker::Func25 func) { int32_t i32 = 20; - plg::vector vecPtr{ reinterpret_cast(1), reinterpret_cast(2), reinterpret_cast(3) }; + plg::vector vecPtr{reinterpret_cast(1), reinterpret_cast(2), reinterpret_cast(3)}; bool b = true; uint8_t u8 = 5; plg::string str = "Test"; @@ -4498,7 +4675,8 @@ PLUGIN_API plg::string CallFunc25Callback(cross_call_worker::Func25 func) { plg::vec4 vec4{1.0f, 2.0f, 3.0f, 4.0f}; uint16_t u16 = 10; double ret = func(i32, vecPtr, b, u8, str, vec3, i64, vec4, u16); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, i32, vecPtr, b ? "true" : "false", u8, str.c_str(), vec3, i64, vec4, u16); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, i32, vecPtr, b ? "true" : "false", u8, str.c_str(), vec3, + i64, vec4, u16); } // 10 parameters @@ -4512,10 +4690,11 @@ PLUGIN_API plg::string CallFunc26Callback(cross_call_worker::Func26 func) { uint64_t u64 = 100; uint32_t u32 = 10; plg::vector vecU16{1, 2, 3}; - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer bool b = true; char ret = func(ch16, vec2, mat, vecF, i16, u64, u32, vecU16, ptr, b); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, static_cast(ch16), vec2, mat, vecF, u64, u32, vecU16, ptr, b ? "true" : "false"); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, static_cast(ch16), vec2, mat, vecF, u64, u32, + vecU16, ptr, b ? "true" : "false"); } // 11 parameters @@ -4523,7 +4702,7 @@ extern "C" PLUGIN_API plg::string CallFunc27Callback(cross_call_worker::Func27 func) { float f = 1.23f; plg::vec3 vec3{1.0f, 2.0f, 3.0f}; - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer plg::vec2 vec2{1.0f, 2.0f}; plg::vector vecI16{1, 2, 3}; plg::mat4x4 mat; // Assume it's initialized properly @@ -4533,13 +4712,14 @@ PLUGIN_API plg::string CallFunc27Callback(cross_call_worker::Func27 func) { int32_t i32 = 20; plg::vector vecU8{0, 1, 2}; uint8_t ret = func(f, vec3, ptr, vec2, vecI16, mat, b, vec4, i8, i32, vecU8); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, f, vec3, ptr, vec2, vecI16, mat, b, vec4, i8, i32, vecU8); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, f, vec3, ptr, vec2, vecI16, mat, b, vec4, i8, i32, + vecU8); } // 12 parameters extern "C" PLUGIN_API plg::string CallFunc28Callback(cross_call_worker::Func28 func) { - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer uint16_t u16 = 10; // Example value plg::vector vecU32{1, 2, 3}; // Sample vector plg::mat4x4 mat; // Assume initialized properly @@ -4553,7 +4733,8 @@ PLUGIN_API plg::string CallFunc28Callback(cross_call_worker::Func28 func) { plg::vector vecF{1.0f, 2.0f, 3.0f}; // Sample vector of floats plg::string ret = func(ptr, u16, vecU32, mat, f, vec4, str, vecU64, i64, b, vec3, vecF); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ptr, u16, vecU32, mat, f, vec4, str, vecU64, i64, b, vec3, vecF); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ptr, u16, vecU32, mat, f, vec4, str, vecU64, i64, b, + vec3, vecF); } // 13 parameters @@ -4574,13 +4755,14 @@ PLUGIN_API plg::string CallFunc29Callback(cross_call_worker::Func29 func) { plg::vector vecI64{1000, 2000, 3000}; // Sample vector of int64 plg::vector ret = func(vec4, i32, vecI8, d, b, i8, vecU16, f, str, mat, u64, vec3, vecI64); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, vec4, i32, vecI8, d, b ? "true" : "false", i8, vecU16, f, str, mat, u64, vec3, vecI64); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, vec4, i32, vecI8, d, b ? "true" : "false", i8, + vecU16, f, str, mat, u64, vec3, vecI64); } // 14 parameters extern "C" PLUGIN_API plg::string CallFunc30Callback(cross_call_worker::Func30 func) { - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer plg::vec4 vec4{1.0f, 2.0f, 3.0f, 4.0f}; // Example Vector4 int64_t i64 = 123456789; // Example int64 plg::vector vecU32{1, 2, 3}; // Sample vector of uint32 @@ -4596,7 +4778,8 @@ PLUGIN_API plg::string CallFunc30Callback(cross_call_worker::Func30 func) { double d = 7.89; // Example double int32_t ret = func(ptr, vec4, i64, vecU32, b, str, vec3, vecU8, f, vec2, mat, i8, vecF, d); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ptr, vec4, i64, vecU32, b ? "true" : "false", str, vec3, vecU8, f, vec2, mat, i8, vecF, d); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ptr, vec4, i64, vecU32, b ? "true" : "false", + str, vec3, vecU8, f, vec2, mat, i8, vecF, d); } // 15 parameters @@ -4619,7 +4802,8 @@ PLUGIN_API plg::string CallFunc31Callback(cross_call_worker::Func31 func) { plg::vector vecD{1.0, 2.0, 3.0}; // Sample vector of doubles plg::vec3 ret = func(ch, u32, vecU64, vec4, str, b, i64, vec2, i8, u16, vecI16, mat, vec3, f, vecD); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ch, u32, vecU64, vec4, str, b ? "true" : "false", i64, vec2, i8, u16, vecI16, mat, vec3, f, vecD); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ch, u32, vecU64, vec4, str, b ? "true" : "false", i64, + vec2, i8, u16, vecI16, mat, vec3, f, vecD); } // 16 parameters @@ -4629,7 +4813,7 @@ PLUGIN_API plg::string CallFunc32Callback(cross_call_worker::Func32 func) { uint16_t u16 = 10; // Example uint16 reference plg::vector vecI8{1, 2, 3}; // Sample vector of int8 plg::vec4 vec4{1.0f, 2.0f, 3.0f, 4.0f}; // Example Vector4 - void* ptr = nullptr; // Example pointer reference + void *ptr = nullptr; // Example pointer reference plg::vector vecU32{1, 2, 3}; // Sample vector of uint32 plg::mat4x4 mat; // Assume initialized properly uint64_t u64 = 100; // Example uint64 @@ -4643,7 +4827,8 @@ PLUGIN_API plg::string CallFunc32Callback(cross_call_worker::Func32 func) { plg::vector vecC16{u'A', u'B', u'C'}; // Sample vector of char16 func(i32, u16, vecI8, vec4, ptr, vecU32, mat, u64, str, i64, vec2, vecI8_2, b, vec3, u8, vecC16); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", i32, u16, vecI8, vec4, ptr, vecU32, mat, u64, str, i64, vec2, vecI8_2, b ? "true" : "false", vec3, u8, vecC16); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", i32, u16, vecI8, vec4, ptr, vecU32, mat, u64, + str, i64, vec2, vecI8_2, b ? "true" : "false", vec3, u8, vecC16); } // 1 parameters @@ -4663,4 +4848,4 @@ PLUGIN_API plg::string CallFuncEnumCallback(cross_call_worker::FuncEnum func) { return std::format("{}|{}", ret, p2); } -PLUGIFY_WARN_POP() \ No newline at end of file +PLUGIFY_WARN_POP() diff --git a/test/cross_call_master/simple_tests.cpp b/test/cross_call_master/simple_tests.cpp index 7febcca..837cf35 100644 --- a/test/cross_call_master/simple_tests.cpp +++ b/test/cross_call_master/simple_tests.cpp @@ -4,67 +4,69 @@ #include void SimpleTests::Test::Fail(std::string error) { - _errors.push_back(std::move(error)); + _errors.push_back(std::move(error)); } -const std::string& SimpleTests::Test::GetName() const { - return _name; +const std::string &SimpleTests::Test::GetName() const { + return _name; } bool SimpleTests::Test::IsFailed() const { - return !_errors.empty(); + return !_errors.empty(); } -const std::vector& SimpleTests::Test::GetErrors() const { - return _errors; +const std::vector &SimpleTests::Test::GetErrors() const { + return _errors; } -SimpleTests::Test::Test(std::string name, std::function func) : _name(std::move(name)), _func(std::move(func)) { +SimpleTests::Test::Test(std::string name, std::function func) : _name(std::move(name)), + _func(std::move(func)) { } void SimpleTests::Test::Run() { - _errors.clear(); - _func(*this); + _errors.clear(); + _func(*this); } -void SimpleTests::Add(std::string name, std::function func) { - _tests.push_back(std::unique_ptr(new Test(std::move(name), std::move(func)))); +void SimpleTests::Add(std::string name, std::function func) { + _tests.push_back(std::unique_ptr(new Test(std::move(name), std::move(func)))); } void SimpleTests::Run() { - const size_t count = _tests.size(); - const auto count_len = std::to_string(count).length(); - const std::string number_template = std::format("[{{:0{}d}}/{{}}]", count_len); - const auto name_max_length = std::accumulate(_tests.begin(), _tests.end(), size_t{0}, [](size_t prev_max, const std::unique_ptr& next) { - const auto next_length = next->GetName().length(); - return next_length > prev_max ? next_length : prev_max; - }); - const std::string name_template = std::format("{{:{}s}}", name_max_length); + const size_t count = _tests.size(); + const auto count_len = std::to_string(count).length(); + const std::string number_template = std::format("[{{:0{}d}}/{{}}]", count_len); + const auto name_max_length = std::accumulate(_tests.begin(), _tests.end(), size_t{0}, + [](size_t prev_max, const std::unique_ptr &next) { + const auto next_length = next->GetName().length(); + return next_length > prev_max ? next_length : prev_max; + }); + const std::string name_template = std::format("{{:{}s}}", name_max_length); - size_t success = 0, failed = 0; + size_t success = 0, failed = 0; - for (size_t i = 0; i < count; ++i) { - Test& test = *_tests[i]; - const auto n = i + 1; - const auto number = std::vformat(number_template, std::make_format_args(n, count)); - const auto name = test.GetName(); - const auto formatted_name = std::vformat(name_template, std::make_format_args(name)); - std::cout << std::format("{} {} ", number, formatted_name) << std::flush; - test.Run(); - if (test.IsFailed()) { - ++failed; - std::cerr << "Failed\n"; - for (const auto& error : test.GetErrors()) { - std::cerr << " " << error << "\n"; - } - std::cerr << std::flush; - } else { - ++success; - std::cout << "Success" << std::endl; - } - } - - std::cout << std::format("Tests finished: {} success, {} failed, {} total", success, failed, count) << std::endl; + for (size_t i = 0; i < count; ++i) { + Test &test = *_tests[i]; + const auto n = i + 1; + const auto number = std::vformat(number_template, std::make_format_args(n, count)); + const auto name = test.GetName(); + const auto formatted_name = std::vformat(name_template, std::make_format_args(name)); + std::cout << std::format("{} {} ", number, formatted_name) << std::flush; + test.Run(); + if (test.IsFailed()) { + ++failed; + std::cerr << "Failed\n"; + for (const auto &error: test.GetErrors()) { + std::cerr << " " << error << "\n"; + } + std::cerr << std::flush; + } else { + ++success; + std::cout << "Success" << std::endl; + } + } + + std::cout << std::format("Tests finished: {} success, {} failed, {} total", success, failed, count) << std::endl; } void SimpleTests::Reset() { diff --git a/test/cross_call_master/simple_tests.hpp b/test/cross_call_master/simple_tests.hpp index e49a86e..6e06be7 100644 --- a/test/cross_call_master/simple_tests.hpp +++ b/test/cross_call_master/simple_tests.hpp @@ -7,31 +7,36 @@ class SimpleTests { public: - class Test { - friend SimpleTests; + class Test { + friend SimpleTests; - public: - void Fail(std::string error); + public: + void Fail(std::string error); - const std::string& GetName() const; - bool IsFailed() const; - const std::vector& GetErrors() const; + const std::string &GetName() const; - private: - Test(std::string name, std::function func); - void Run(); + bool IsFailed() const; - private: - std::string _name; - std::function _func; - std::vector _errors; - }; + const std::vector &GetErrors() const; + + private: + Test(std::string name, std::function func); + + void Run(); + + private: + std::string _name; + std::function _func; + std::vector _errors; + }; public: - void Add(std::string name, std::function func); - void Run(); - void Reset(); + void Add(std::string name, std::function func); + + void Run(); + + void Reset(); private: - std::vector> _tests; + std::vector > _tests; }; diff --git a/test/cross_call_worker/.clang-format b/test/cross_call_worker/.clang-format new file mode 100644 index 0000000..36e77ba --- /dev/null +++ b/test/cross_call_worker/.clang-format @@ -0,0 +1,92 @@ +BasedOnStyle: Mozilla +Language: Cpp +Standard: c++20 + +AccessModifierOffset: "-4" +AlignAfterOpenBracket: BlockIndent +AlignEscapedNewlinesLeft: "false" +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: "false" +AllowShortCaseLabelsOnASingleLine: "false" +AllowShortFunctionsOnASingleLine: "false" +AllowShortIfStatementsOnASingleLine: "false" +AllowShortLoopsOnASingleLine: "false" +AlwaysBreakTemplateDeclarations: "true" +BreakAfterReturnType: ExceptShortType +BinPackArguments: false +BinPackParameters: false +BreakAfterAttributes: Leave +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: "true" +BreakConstructorInitializersBeforeComma: "true" +BreakStringLiterals: "false" +ColumnLimit: "100" +ConstructorInitializerAllOnOneLineOrOnePerLine: "false" +ConstructorInitializerIndentWidth: "4" +ContinuationIndentWidth: "4" +Cpp11BracedListStyle: "false" +DerivePointerAlignment: "false" +DisableFormat: "false" +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: Always +ExperimentalAutoDetectBinPacking: "true" +IncludeBlocks: Regroup +IncludeCategories: + - Regex: <[^.]+> + Priority: -3 + - Regex: + Priority: -1 + - Regex: <.+> + Priority: -2 + - Regex: '"plugify/.+"' + Priority: 0 + - Regex: '"glaze/.+"' + Priority: 0 + - Regex: '"asmjit/.+"' + Priority: 0 + - Regex: '".+/.+"' + Priority: 1 + - Regex: '".+"' + Priority: 2 +IndentCaseLabels: "true" +IndentWidth: "4" +IndentWrappedFunctionNames: "false" +InsertBraces: true # Experimental +KeepEmptyLinesAtTheStartOfBlocks: "false" +MaxEmptyLinesToKeep: "2" +NamespaceIndentation: All +ObjCBlockIndentWidth: "4" +ObjCSpaceAfterProperty: "false" +ObjCSpaceBeforeProtocolList: "false" +PackConstructorInitializers: Never +PenaltyBreakAssignment: 100000 +PenaltyBreakBeforeFirstCallParameter: 0 +PenaltyBreakComment: 10 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakTemplateDeclaration: 0 +PenaltyExcessCharacter: 10 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 10 +PointerAlignment: Left +ReferenceAlignment: Left +QualifierAlignment: Custom # Experimental +QualifierOrder: [inline, static, constexpr, const, volatile, type] +ReflowComments: "true" +SeparateDefinitionBlocks: Always +SortIncludes: CaseInsensitive +SortUsingDeclarations: Never +SpaceAfterCStyleCast: "true" +SpaceAfterTemplateKeyword: "true" +SpaceBeforeAssignmentOperators: "true" +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: "false" +SpacesBeforeTrailingComments: "2" +SpacesInAngles: "false" +SpacesInCStyleCastParentheses: "false" +SpacesInContainerLiterals: "false" +SpacesInParentheses: "false" +SpacesInSquareBrackets: "false" +TabWidth: "4" +UseTab: "ForIndentation" \ No newline at end of file diff --git a/test/cross_call_worker/.clang-tidy b/test/cross_call_worker/.clang-tidy new file mode 100644 index 0000000..09fd31b --- /dev/null +++ b/test/cross_call_worker/.clang-tidy @@ -0,0 +1,159 @@ +# Generated from CLion Inspection settings +--- +Checks: '-*, +bugprone-argument-comment, +bugprone-assert-side-effect, +bugprone-bad-signal-to-kill-thread, +bugprone-branch-clone, +bugprone-copy-constructor-init, +bugprone-dangling-handle, +bugprone-dynamic-static-initializers, +bugprone-fold-init-type, +bugprone-forward-declaration-namespace, +bugprone-forwarding-reference-overload, +bugprone-inaccurate-erase, +bugprone-incorrect-roundings, +bugprone-integer-division, +bugprone-lambda-function-name, +bugprone-macro-parentheses, +bugprone-macro-repeated-side-effects, +bugprone-misplaced-operator-in-strlen-in-alloc, +bugprone-misplaced-pointer-arithmetic-in-alloc, +bugprone-misplaced-widening-cast, +bugprone-move-forwarding-reference, +bugprone-multiple-statement-macro, +bugprone-no-escape, +bugprone-parent-virtual-call, +bugprone-posix-return, +bugprone-reserved-identifier, +bugprone-sizeof-container, +bugprone-sizeof-expression, +bugprone-spuriously-wake-up-functions, +bugprone-string-constructor, +bugprone-string-integer-assignment, +bugprone-string-literal-with-embedded-nul, +bugprone-suspicious-enum-usage, +bugprone-suspicious-include, +bugprone-suspicious-memset-usage, +bugprone-suspicious-missing-comma, +bugprone-suspicious-semicolon, +bugprone-suspicious-string-compare, +bugprone-suspicious-memory-comparison, +bugprone-suspicious-realloc-usage, +bugprone-swapped-arguments, +bugprone-terminating-continue, +bugprone-throw-keyword-missing, +bugprone-too-small-loop-variable, +bugprone-undefined-memory-manipulation, +bugprone-undelegated-constructor, +bugprone-unhandled-self-assignment, +bugprone-unused-raii, +bugprone-unused-return-value, +bugprone-use-after-move, +bugprone-virtual-near-miss, +cert-dcl21-cpp, +cert-dcl58-cpp, +cert-err34-c, +cert-err52-cpp, +cert-err60-cpp, +cert-flp30-c, +cert-msc50-cpp, +cert-msc51-cpp, +cert-str34-c, +cppcoreguidelines-interfaces-global-init, +cppcoreguidelines-narrowing-conversions, +cppcoreguidelines-pro-type-member-init, +cppcoreguidelines-pro-type-static-cast-downcast, +cppcoreguidelines-slicing, +google-default-arguments, +google-explicit-constructor, +google-runtime-operator, +hicpp-exception-baseclass, +hicpp-multiway-paths-covered, +misc-misplaced-const, +misc-new-delete-overloads, +misc-no-recursion, +misc-non-copyable-objects, +misc-throw-by-value-catch-by-reference, +misc-unconventional-assign-operator, +misc-uniqueptr-reset-release, +modernize-avoid-bind, +modernize-concat-nested-namespaces, +modernize-deprecated-headers, +modernize-deprecated-ios-base-aliases, +modernize-loop-convert, +modernize-make-shared, +modernize-make-unique, +modernize-pass-by-value, +modernize-raw-string-literal, +modernize-redundant-void-arg, +modernize-replace-auto-ptr, +modernize-replace-disallow-copy-and-assign-macro, +modernize-replace-random-shuffle, +modernize-return-braced-init-list, +modernize-shrink-to-fit, +modernize-unary-static-assert, +modernize-use-auto, +modernize-use-bool-literals, +modernize-use-emplace, +modernize-use-equals-default, +modernize-use-equals-delete, +modernize-use-nodiscard, +modernize-use-noexcept, +modernize-use-nullptr, +modernize-use-override, +modernize-use-transparent-functors, +modernize-use-uncaught-exceptions, +mpi-buffer-deref, +mpi-type-mismatch, +openmp-use-default-none, +performance-faster-string-find, +performance-for-range-copy, +performance-implicit-conversion-in-loop, +performance-inefficient-algorithm, +performance-inefficient-string-concatenation, +performance-inefficient-vector-operation, +performance-move-const-arg, +performance-move-constructor-init, +performance-no-automatic-move, +performance-noexcept-move-constructor, +performance-trivially-destructible, +performance-type-promotion-in-math-fn, +performance-unnecessary-copy-initialization, +performance-unnecessary-value-param, +portability-simd-intrinsics, +readability-avoid-const-params-in-decls, +readability-const-return-type, +readability-container-size-empty, +readability-convert-member-functions-to-static, +readability-delete-null-pointer, +readability-deleted-default, +readability-inconsistent-declaration-parameter-name, +readability-make-member-function-const, +readability-misleading-indentation, +readability-misplaced-array-index, +readability-non-const-parameter, +readability-redundant-control-flow, +readability-redundant-declaration, +readability-redundant-function-ptr-dereference, +readability-redundant-smartptr-get, +readability-redundant-string-cstr, +readability-redundant-string-init, +readability-simplify-subscript-expr, +readability-static-accessed-through-instance, +readability-static-definition-in-anonymous-namespace, +readability-string-compare, +readability-uniqueptr-delete-release, +readability-use-anyofallof +readability-identifier-naming' +CheckOptions: + - key: readability-identifier-naming.FunctionCase + value: CamelCase + - key: readability-identifier-naming.MethodCase + value: CamelCase + - key: readability-identifier-naming.MemberCase + value: camelBack + - key: readability-identifier-naming.MemberPrefix + value: '_' + - key: readability-identifier-naming.PrivateMemberPrefix + value: '' \ No newline at end of file diff --git a/test/cross_call_worker/external/plugify/include/plg/enum.hpp b/test/cross_call_worker/external/plugify/include/plg/enum.hpp index 84f6d23..f8780e1 100644 --- a/test/cross_call_worker/external/plugify/include/plg/enum.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/enum.hpp @@ -1,121 +1,130 @@ #pragma once +#include #include +#include #include #include -#include -#include #include "plg/macro.hpp" -// from https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ +// from +// https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ namespace plg { - constexpr auto ENUM_MIN_VALUE = -128; - constexpr auto ENUM_MAX_VALUE = 128; - - template - struct static_string { - constexpr static_string(std::string_view sv) noexcept { - std::copy(sv.begin(), sv.end(), content.begin()); - } - constexpr operator std::string_view() const noexcept { return { content.data(), N }; } - - private: - std::array content{}; - }; - - constexpr auto is_pretty(char ch) noexcept { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); - } - - constexpr auto pretty_name(std::string_view sv) noexcept { - for (std::size_t n = sv.size() - 1; n > 0; --n) { - if (!is_pretty(sv[n])) { - sv.remove_prefix(n + 1); - break; - } - } - return sv; - } - - template - constexpr auto n() noexcept { - #if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG - return pretty_name({ __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2 }); - #elif PLUGIFY_COMPILER_MSVC - return pretty_name({ __FUNCSIG__, sizeof(__FUNCSIG__) - 17 }); - #endif - } - - template - constexpr auto is_valid() { - [[maybe_unused]] constexpr E v = static_cast(V); - return !n().empty(); - } - - template - constexpr auto value(std::size_t v) { - return static_cast(ENUM_MIN_VALUE + static_cast(v)); - } - - template - constexpr auto count_values(const bool (&valid)[N]) { - std::size_t count = 0; - for (std::size_t n = 0; n < N; ++n) - if (valid[n]) ++count; - return count; - } - - template - constexpr auto values(std::index_sequence) noexcept { - constexpr bool valid[sizeof...(I)] = { is_valid(I)>()... }; - constexpr auto num_valid = count_values(valid); - static_assert(num_valid > 0, "no support for empty enums"); - - std::array values = {}; - for(std::size_t offset = 0, n = 0; n < num_valid; ++offset) { - if (valid[offset]) { - values[n] = value(offset); - ++n; - } - } - - return values; - } - - template - constexpr auto values() noexcept { - constexpr auto enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1; - return values(std::make_index_sequence({})); - } - - template - inline constexpr auto values_v = values(); - - template - constexpr auto enum_name() { - constexpr auto name = n(); - return static_string(name); - } - - template - inline constexpr auto enum_name_v = enum_name(); - - template - constexpr auto entries(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {{ values_v[I], enum_name_v[I]>}...} - }; - } - - template - inline constexpr auto entries_v = entries(std::make_index_sequence.size()>()); - - template - constexpr std::string_view enum_to_string(E value) { - for (const auto& [ key, name ]: entries_v) { - if (value == key) return name; - } - return {}; - } + constexpr auto ENUM_MIN_VALUE = -128; + constexpr auto ENUM_MAX_VALUE = 128; + + template + struct static_string { + constexpr static_string(std::string_view sv) noexcept { + std::copy(sv.begin(), sv.end(), content.begin()); + } + + constexpr operator std::string_view() const noexcept { + return { content.data(), N }; + } + + private: + std::array content{}; + }; + + constexpr auto is_pretty(char ch) noexcept { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); + } + + constexpr auto pretty_name(std::string_view sv) noexcept { + for (std::size_t n = sv.size() - 1; n > 0; --n) { + if (!is_pretty(sv[n])) { + sv.remove_prefix(n + 1); + break; + } + } + return sv; + } + + template + constexpr auto n() noexcept { +#if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG + return pretty_name({ __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2 }); +#elif PLUGIFY_COMPILER_MSVC + return pretty_name({ __FUNCSIG__, sizeof(__FUNCSIG__) - 17 }); +#endif + } + + template + constexpr auto is_valid() { + [[maybe_unused]] constexpr E v = static_cast(V); + return !n().empty(); + } + + template + constexpr auto value(std::size_t v) { + return static_cast(ENUM_MIN_VALUE + static_cast(v)); + } + + template + constexpr auto count_values(const bool (&valid)[N]) { + std::size_t count = 0; + for (std::size_t n = 0; n < N; ++n) { + if (valid[n]) { + ++count; + } + } + return count; + } + + template + constexpr auto values(std::index_sequence) noexcept { + constexpr bool valid[sizeof...(I)] = { is_valid(I)>()... }; + constexpr auto num_valid = count_values(valid); + static_assert(num_valid > 0, "no support for empty enums"); + + std::array values = {}; + for (std::size_t offset = 0, n = 0; n < num_valid; ++offset) { + if (valid[offset]) { + values[n] = value(offset); + ++n; + } + } + + return values; + } + + template + constexpr auto values() noexcept { + constexpr auto enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1; + return values(std::make_index_sequence({})); + } + + template + inline constexpr auto values_v = values(); + + template + constexpr auto enum_name() { + constexpr auto name = n(); + return static_string(name); + } + + template + inline constexpr auto enum_name_v = enum_name(); + + template + constexpr auto entries(std::index_sequence) noexcept { + return std::array, sizeof...(I)>{ + { { values_v[I], enum_name_v[I]> }... } + }; + } + + template + inline constexpr auto entries_v = entries(std::make_index_sequence.size()>()); + + template + constexpr std::string_view enum_to_string(E value) { + for (const auto& [key, name] : entries_v) { + if (value == key) { + return name; + } + } + return {}; + } } diff --git a/test/cross_call_worker/external/plugify/include/plg/flat_map.hpp b/test/cross_call_worker/external/plugify/include/plg/flat_map.hpp index 9912431..7b5f7b7 100644 --- a/test/cross_call_worker/external/plugify/include/plg/flat_map.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/flat_map.hpp @@ -5,8 +5,8 @@ #ifdef __cpp_lib_flat_map #include namespace plg { - template> - using flat_map = std::flat_map; + template> + using flat_map = std::flat_map; } #else #include "plg/vector.hpp" diff --git a/test/cross_call_worker/external/plugify/include/plg/hash.hpp b/test/cross_call_worker/external/plugify/include/plg/hash.hpp index 98c9a27..296436a 100644 --- a/test/cross_call_worker/external/plugify/include/plg/hash.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/hash.hpp @@ -15,29 +15,32 @@ namespace plg { }; struct string_hash { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup auto operator()(const char* txt) const { return std::hash{}(txt); } + auto operator()(std::string_view txt) const { return std::hash{}(txt); } + auto operator()(const std::string& txt) const { return std::hash{}(txt); } - auto operator()(const plg::string& txt) const { + + auto operator()(const plg::string& txt) const { return std::hash{}(txt); } }; struct case_insensitive_hash { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup - template + template auto operator()(const T& str_like) const noexcept { std::string_view str = str_like; - std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis + std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis for (char c : str) { hash ^= static_cast(std::tolower(static_cast(c))); hash *= 0x100000001b3; @@ -47,26 +50,29 @@ namespace plg { }; struct case_insensitive_equal { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup - template + template bool operator()(const T1& lhs_like, const T2& rhs_like) const noexcept { std::string_view lhs = lhs_like; std::string_view rhs = rhs_like; - if (lhs.size() != rhs.size()) + if (lhs.size() != rhs.size()) { return false; + } for (size_t i = 0; i < lhs.size(); ++i) { - if (std::tolower(static_cast(lhs[i])) != - std::tolower(static_cast(rhs[i]))) + if (std::tolower(static_cast(lhs[i])) + != std::tolower(static_cast(rhs[i]))) { return false; + } } return true; } }; - inline void hash_combine(size_t&) { } + inline void hash_combine(size_t&) { + } template inline void hash_combine(std::size_t& seed, const T& v) { @@ -78,15 +84,15 @@ namespace plg { template inline std::size_t hash_combine_all(const Ts&... args) { std::size_t seed = 0; - (hash_combine(seed, args), ...); // fold expression + (hash_combine(seed, args), ...); // fold expression return seed; } - template - struct pair_hash { - size_t operator()(std::pair const& p) const { - return hash_combine_all(p.first, p.second); - } + template + struct pair_hash { + size_t operator()(const std::pair& p) const { + return hash_combine_all(p.first, p.second); + } }; } diff --git a/test/cross_call_worker/external/plugify/include/plg/path.hpp b/test/cross_call_worker/external/plugify/include/plg/path.hpp index 61343f3..afc3d6e 100644 --- a/test/cross_call_worker/external/plugify/include/plg/path.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/path.hpp @@ -1,14 +1,14 @@ #pragma once #include -#include #include +#include namespace plg { - using path_view = std::basic_string_view; - using path_string = std::filesystem::path::string_type; - using path_char = path_string::value_type; - using path_diff_t = path_string::difference_type; + using path_view = std::basic_string_view; + using path_string = std::filesystem::path::string_type; + using path_char = path_string::value_type; + using path_diff_t = path_string::difference_type; #if _WIN32 #define PLUGIFY_PATH_LITERAL(x) L##x @@ -16,37 +16,41 @@ namespace plg { #define PLUGIFY_PATH_LITERAL(x) x #endif - template - bool insensitive_equals(const path_char lhs, const path_char rhs) { - if constexpr (std::is_same_v) { - return std::towlower(lhs) == rhs; // NOLINT - } else { - return std::tolower(lhs) == rhs; - } - } - - inline bool insensitive_equals(const path_view lhs, const path_view rhs) { - return lhs.size() == rhs.size() && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); - } - - inline path_view extension_view(const std::filesystem::path& path) { - constexpr path_diff_t extension_size = 4; - if (!path.has_extension()) { return {}; } - const path_string& path_str = path.native(); - const auto offset = static_cast(path_str.size()) - extension_size; - if (offset <= 0) { return {}; } - return { path_str.cbegin() + offset, path_str.cend() }; - } - - inline bool has_extension(const std::filesystem::path& path, const path_view extension) { - return insensitive_equals(extension_view(path), extension); - } - - inline auto as_string(const std::filesystem::path& p) { + template + bool insensitive_equals(const path_char lhs, const path_char rhs) { + if constexpr (std::is_same_v) { + return std::towlower(lhs) == rhs; // NOLINT + } else { + return std::tolower(lhs) == rhs; + } + } + + inline bool insensitive_equals(const path_view lhs, const path_view rhs) { + return lhs.size() == rhs.size() + && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); + } + + inline path_view extension_view(const std::filesystem::path& path, size_t extension_size) { + if (!path.has_extension()) { + return {}; + } + const path_string& path_str = path.native(); + const auto offset = static_cast(path_str.size() - extension_size); + if (offset <= 0) { + return {}; + } + return { path_str.cbegin() + offset, path_str.cend() }; // NOLINT(*-dangling-handle) + } + + inline bool has_extension(const std::filesystem::path& path, const path_view extension) { + return insensitive_equals(extension_view(path, extension.size()), extension); + } + + inline auto as_string(const std::filesystem::path& p) { #if _WIN32 - return p.string(); // returns std::string by value + return p.string(); // returns std::string by value #else - return p.native(); // returns const std::string& + return p.native(); // returns const std::string& #endif - } + } } diff --git a/test/cross_call_worker/external/plugify/include/plg/string.hpp b/test/cross_call_worker/external/plugify/include/plg/string.hpp index 175bed2..830f168 100644 --- a/test/cross_call_worker/external/plugify/include/plg/string.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/string.hpp @@ -19,6 +19,7 @@ #include // for std::numeric_limits #include // for std::to_chars + #include #include #include @@ -44,63 +45,63 @@ namespace plg { namespace detail { - template - concept is_allocator = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; - - template - concept is_char_traits = requires { - // Required type definitions - typename Traits::char_type; - typename Traits::int_type; - typename Traits::off_type; - typename Traits::pos_type; - typename Traits::state_type; - } && requires( - typename Traits::char_type c1, - typename Traits::char_type c2, - typename Traits::char_type& cr, - const typename Traits::char_type& ccr, - typename Traits::char_type* p, - const typename Traits::char_type* cp, - typename Traits::int_type i1, - typename Traits::int_type i2, - std::size_t n - ) { - // Character operations - { Traits::assign(cr, ccr) } -> std::same_as; - { Traits::eq(ccr, ccr) } -> std::convertible_to; - { Traits::lt(ccr, ccr) } -> std::convertible_to; - - // String operations - { Traits::compare(cp, cp, n) } -> std::convertible_to; - { Traits::length(cp) } -> std::convertible_to; - { Traits::find(cp, n, ccr) } -> std::convertible_to; - - // Memory operations - { Traits::move(p, cp, n) } -> std::same_as; - { Traits::copy(p, cp, n) } -> std::same_as; - { Traits::assign(p, n, c1) } -> std::same_as; - - // int_type operations - { Traits::not_eof(i1) } -> std::same_as; - { Traits::to_char_type(i1) } -> std::same_as; - { Traits::to_int_type(c1) } -> std::same_as; - { Traits::eq_int_type(i1, i2) } -> std::convertible_to; - { Traits::eof() } -> std::same_as; - }; + template + concept is_allocator = requires(Alloc& a, std::size_t n) { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; + + { std::allocator_traits::allocate(a, n) } + -> std::convertible_to::pointer>; + + requires requires(typename std::allocator_traits::pointer p) { + std::allocator_traits::deallocate(a, p, n); + }; + }; + + template + concept is_char_traits = requires { + // Required type definitions + typename Traits::char_type; + typename Traits::int_type; + typename Traits::off_type; + typename Traits::pos_type; + typename Traits::state_type; + } && requires( + typename Traits::char_type c1, + typename Traits::char_type c2, + typename Traits::char_type& cr, + const typename Traits::char_type& ccr, + typename Traits::char_type* p, + const typename Traits::char_type* cp, + typename Traits::int_type i1, + typename Traits::int_type i2, + std::size_t n + ) { + // Character operations + { Traits::assign(cr, ccr) } -> std::same_as; + { Traits::eq(ccr, ccr) } -> std::convertible_to; + { Traits::lt(ccr, ccr) } -> std::convertible_to; + + // String operations + { Traits::compare(cp, cp, n) } -> std::convertible_to; + { Traits::length(cp) } -> std::convertible_to; + { Traits::find(cp, n, ccr) } -> std::convertible_to; + + // Memory operations + { Traits::move(p, cp, n) } -> std::same_as; + { Traits::copy(p, cp, n) } -> std::same_as; + { Traits::assign(p, n, c1) } -> std::same_as; + + // int_type operations + { Traits::not_eof(i1) } -> std::same_as; + { Traits::to_char_type(i1) } -> std::same_as; + { Traits::to_int_type(c1) } -> std::same_as; + { Traits::eq_int_type(i1, i2) } -> std::convertible_to; + { Traits::eof() } -> std::same_as; + }; struct uninitialized_size_tag {}; @@ -909,9 +910,9 @@ namespace plg { // const size_type alignment = 16; // size_type m = allocator_traits::max_size(_allocator); // if (m <= std::numeric_limits::max() / 2) - // return m - alignment; + // return m - alignment; // else - //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; + //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; return (allocator_traits::max_size(_allocator) - 1) / 2; } @@ -1973,21 +1974,21 @@ namespace std { template std::ostream& operator<<(std::ostream& os, const plg::basic_string& str) { - os << str.c_str(); - return os; + os << str.c_str(); + return os; } #ifndef PLUGIFY_STRING_NO_STD_FORMAT #include namespace plg { - namespace detail { - // Concept to match string-like types including char* and const char* - template - concept is_string_like = requires(T v) { - { std::string_view(v) }; - }; - } + namespace detail { + // Concept to match string-like types including char* and const char* + template + concept is_string_like = requires(T v) { + { std::string_view(v) }; + }; + } template constexpr string join(const Range& range, std::string_view separator) { diff --git a/test/cross_call_worker/external/plugify/include/plg/vector.hpp b/test/cross_call_worker/external/plugify/include/plg/vector.hpp index 3ec8750..11aada1 100644 --- a/test/cross_call_worker/external/plugify/include/plg/vector.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/vector.hpp @@ -27,30 +27,30 @@ #include "plg/allocator.hpp" namespace plg { - namespace detail { - template - concept is_alloc = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; + namespace detail { + template + concept is_alloc = requires(Alloc& a, std::size_t n) { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; + { std::allocator_traits::allocate(a, n) } + -> std::convertible_to::pointer>; - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; + requires requires(typename std::allocator_traits::pointer p) { + std::allocator_traits::deallocate(a, p, n); + }; + }; - struct initialized_value_tag {}; + struct initialized_value_tag {}; #if PLUGIFY_VECTOR_CONTAINERS_RANGES - template - concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; + template + concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; #endif - } // namespace detail + } // namespace detail template struct vector_iterator { diff --git a/test/cross_call_worker/external/plugify/include/plg/version.hpp b/test/cross_call_worker/external/plugify/include/plg/version.hpp index b12ac87..6089f12 100644 --- a/test/cross_call_worker/external/plugify/include/plg/version.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/version.hpp @@ -24,1021 +24,1021 @@ // from https://github.com/Neargye/semver namespace plg { - namespace detail { - template - struct resize_uninitialized { - constexpr static auto resize(T& str, std::size_t size) -> std::void_t { - str.resize(size); - } - }; - - template - struct resize_uninitialized().__resize_default_init(42))>> { - constexpr static void resize(T& str, std::size_t size) { - str.__resize_default_init(size); - } - }; - - template - constexpr std::size_t length(Int n) noexcept { - std::size_t digits = 0; - do { - digits++; - n /= 10; - } while (n != 0); - return digits; - } - - template - constexpr OutputIt to_chars(OutputIt dest, Int n) noexcept { - do { - *(--dest) = static_cast('0' + (n % 10)); - n /= 10; - } while (n != 0); - return dest; - } - - enum struct prerelease_identifier_type { - numeric, - alphanumeric - }; - - struct prerelease_identifier { - prerelease_identifier_type type; - string identifier; - }; - - class version_parser; - class prerelease_comparator; - } - - template - class version { - friend class detail::version_parser; - friend class detail::prerelease_comparator; - - public: - constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase - constexpr version(const version&) = default; - constexpr version(version&&) = default; - constexpr ~version() = default; - - constexpr version& operator=(const version&) = default; - constexpr version& operator=(version&&) = default; - - constexpr I1 major() const noexcept { return major_; } - constexpr I2 minor() const noexcept { return minor_; } - constexpr I3 patch() const noexcept { return patch_; } - - constexpr const string& prerelease_tag() const { return prerelease_tag_; } - constexpr const string& build_metadata() const { return build_metadata_; } - - constexpr string to_string() const; - - private: - I1 major_ = 0; - I2 minor_ = 1; - I3 patch_ = 0; - string prerelease_tag_; - string build_metadata_; - - vector prerelease_identifiers; - - constexpr std::size_t length() const noexcept { - return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 - + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) - + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); - } - - constexpr void clear() noexcept { - major_ = 0; - minor_ = 1; - patch_ = 0; - - prerelease_tag_.clear(); - prerelease_identifiers.clear(); - build_metadata_.clear(); - } - }; - - template - constexpr string version::to_string() const { - string result; - detail::resize_uninitialized{}.resize(result, length()); - - auto it = result.end(); - if (!build_metadata_.empty()) { - it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); - *(--it) = '+'; - } - - if (!prerelease_tag_.empty()) { - it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); - *(--it) = '-'; - } - - it = detail::to_chars(it, patch_); - *(--it) = '.'; - - it = detail::to_chars(it, minor_); - *(--it) = '.'; - - it = detail::to_chars(it, major_); - - return result; - } + namespace detail { + template + struct resize_uninitialized { + constexpr static auto resize(T& str, std::size_t size) -> std::void_t { + str.resize(size); + } + }; + + template + struct resize_uninitialized().__resize_default_init(42))>> { + constexpr static void resize(T& str, std::size_t size) { + str.__resize_default_init(size); + } + }; + + template + constexpr std::size_t length(Int n) noexcept { + std::size_t digits = 0; + do { + digits++; + n /= 10; + } while (n != 0); + return digits; + } + + template + constexpr OutputIt to_chars(OutputIt dest, Int n) noexcept { + do { + *(--dest) = static_cast('0' + (n % 10)); + n /= 10; + } while (n != 0); + return dest; + } + + enum struct prerelease_identifier_type { + numeric, + alphanumeric + }; + + struct prerelease_identifier { + prerelease_identifier_type type; + string identifier; + }; + + class version_parser; + class prerelease_comparator; + } + + template + class version { + friend class detail::version_parser; + friend class detail::prerelease_comparator; + + public: + constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase + constexpr version(const version&) = default; + constexpr version(version&&) = default; + constexpr ~version() = default; + + constexpr version& operator=(const version&) = default; + constexpr version& operator=(version&&) = default; + + constexpr I1 major() const noexcept { return major_; } + constexpr I2 minor() const noexcept { return minor_; } + constexpr I3 patch() const noexcept { return patch_; } + + constexpr const string& prerelease_tag() const { return prerelease_tag_; } + constexpr const string& build_metadata() const { return build_metadata_; } + + constexpr string to_string() const; + + private: + I1 major_ = 0; + I2 minor_ = 1; + I3 patch_ = 0; + string prerelease_tag_; + string build_metadata_; + + vector prerelease_identifiers; + + constexpr std::size_t length() const noexcept { + return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 + + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) + + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); + } + + constexpr void clear() noexcept { + major_ = 0; + minor_ = 1; + patch_ = 0; + + prerelease_tag_.clear(); + prerelease_identifiers.clear(); + build_metadata_.clear(); + } + }; + + template + constexpr string version::to_string() const { + string result; + detail::resize_uninitialized{}.resize(result, length()); + + auto it = result.end(); + if (!build_metadata_.empty()) { + it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); + *(--it) = '+'; + } + + if (!prerelease_tag_.empty()) { + it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); + *(--it) = '-'; + } + + it = detail::to_chars(it, patch_); + *(--it) = '.'; + + it = detail::to_chars(it, minor_); + *(--it) = '.'; + + it = detail::to_chars(it, major_); + + return result; + } #if __has_include() - struct from_chars_result : std::from_chars_result { - [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } - }; + struct from_chars_result : std::from_chars_result { + [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } + }; #else - struct from_chars_result { - const char* ptr; - std::errc ec; + struct from_chars_result { + const char* ptr; + std::errc ec; - [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } - }; + [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } + }; #endif - enum class version_compare_option : std::uint8_t { - exclude_prerelease, - include_prerelease - }; - - namespace detail { - constexpr from_chars_result success(const char* ptr) noexcept { - return from_chars_result{ ptr, std::errc{} }; - } - - constexpr from_chars_result failure(const char* ptr, std::errc error_code = std::errc::invalid_argument) noexcept { - return from_chars_result{ ptr, error_code }; - } - - constexpr bool is_digit(char c) noexcept { - return c >= '0' && c <= '9'; - } - - constexpr bool is_letter(char c) noexcept { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); - } - - constexpr std::uint8_t to_digit(char c) noexcept { - return static_cast(c - '0'); - } - - constexpr char to_char(int i) noexcept { - return '0' + (char)i; - } - - template - constexpr bool cmp_less(T t, U u) noexcept - { - if constexpr (std::is_signed_v == std::is_signed_v) - return t < u; + enum class version_compare_option : std::uint8_t { + exclude_prerelease, + include_prerelease + }; + + namespace detail { + constexpr from_chars_result success(const char* ptr) noexcept { + return from_chars_result{ ptr, std::errc{} }; + } + + constexpr from_chars_result failure(const char* ptr, std::errc error_code = std::errc::invalid_argument) noexcept { + return from_chars_result{ ptr, error_code }; + } + + constexpr bool is_digit(char c) noexcept { + return c >= '0' && c <= '9'; + } + + constexpr bool is_letter(char c) noexcept { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + + constexpr std::uint8_t to_digit(char c) noexcept { + return static_cast(c - '0'); + } + + constexpr char to_char(int i) noexcept { + return '0' + (char)i; + } + + template + constexpr bool cmp_less(T t, U u) noexcept + { + if constexpr (std::is_signed_v == std::is_signed_v) + return t < u; else if constexpr (std::is_signed_v) - return t < 0 || std::make_unsigned_t(t) < u; + return t < 0 || std::make_unsigned_t(t) < u; else - return u >= 0 && t < std::make_unsigned_t(u); + return u >= 0 && t < std::make_unsigned_t(u); } - template - constexpr bool cmp_less_equal(T t, U u) noexcept - { - return !cmp_less(u, t); - } + template + constexpr bool cmp_less_equal(T t, U u) noexcept + { + return !cmp_less(u, t); + } - template - constexpr bool cmp_greater_equal(T t, U u) noexcept - { - return !cmp_less(t, u); - } + template + constexpr bool cmp_greater_equal(T t, U u) noexcept + { + return !cmp_less(t, u); + } - template - constexpr bool number_in_range(T t) noexcept { - return cmp_greater_equal(t, std::numeric_limits::min()) && cmp_less_equal(t, std::numeric_limits::max()); - } + template + constexpr bool number_in_range(T t) noexcept { + return cmp_greater_equal(t, std::numeric_limits::min()) && cmp_less_equal(t, std::numeric_limits::max()); + } - constexpr int compare(std::string_view lhs, std::string_view rhs) { + constexpr int compare(std::string_view lhs, std::string_view rhs) { #if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) - // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html - // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html - constexpr bool workaround = true; + // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html + constexpr bool workaround = true; #else - constexpr bool workaround = false; + constexpr bool workaround = false; #endif - if constexpr (workaround) { - const auto size = std::min(lhs.size(), rhs.size()); - for (std::size_t i = 0; i < size; ++i) { - if (lhs[i] < rhs[i]) { - return -1; - } else if (lhs[i] > rhs[i]) { - return 1; - } - } - - return static_cast(lhs.size() - rhs.size()); - } else { - return lhs.compare(rhs); - } - } - - constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { - // assume that strings don't have leading zeros (we've already checked it at parsing stage). - - if (lhs.size() != rhs.size()) { - return static_cast(lhs.size() - rhs.size()); - } - - for (std::size_t i = 0; i < lhs.size(); ++i) { - int a = lhs[i] - '0'; - int b = rhs[i] - '0'; - if (a != b) { - return a - b; - } - } - - return 0; - } - - enum class token_type : std::uint8_t { - eol, - space, - dot, - plus, - hyphen, - letter, - digit, - range_operator, - logical_or - }; - - enum class range_operator : std::uint8_t { - less, - less_or_equal, - greater, - greater_or_equal, - equal - }; - - struct token { - using value_t = std::variant; - token_type type; - value_t value; - const char* lexeme; - }; - - class token_stream { - public: - constexpr token_stream() = default; - constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} - - constexpr void push(const token& token) noexcept { - tokens_.push_back(token); - } - - constexpr token advance() noexcept { - const token token = get(current_); - ++current_; - return token; - } - - constexpr token peek(std::size_t k = 0) const noexcept { - return get(current_ + k); - } - - constexpr token previous() const noexcept { - return get(current_ - 1); - } - - constexpr bool advanceIfMatch(token& token, token_type type) noexcept { - if (get(current_).type != type) { - return false; - } - - token = advance(); - return true; - } - - constexpr bool advanceIfMatch(token_type type) noexcept { - token token; - return advanceIfMatch(token, type); - } - - constexpr bool consume(token_type type) noexcept { - return advance().type == type; - } - - constexpr bool check(token_type type) const noexcept { - return peek().type == type; - } - - private: - std::size_t current_ = 0; - vector tokens_; - - constexpr token get(std::size_t i) const noexcept { - return tokens_[i]; - } - }; - - class lexer { - public: - explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} - - constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { - from_chars_result result{ text_.data(), std::errc{} }; - - while (!is_eol()) { - result = scan_token(token_stream); - if (!result) { - return result; - } - } - - token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); - - return result; - } - - private: - std::string_view text_; - std::size_t current_pos_; - - constexpr from_chars_result scan_token(token_stream& stream) noexcept { - const char c = advance(); - - switch (c) { - case ' ': - add_token(stream, token_type::space); - break; - case '.': - add_token(stream, token_type::dot); - break; - case '-': - add_token(stream, token_type::hyphen); - break; - case '+': - add_token(stream, token_type::plus); - break; - case '|': - if (advanceIfMatch('|')) { - add_token(stream, token_type::logical_or); - break; - } - return failure(get_prev_symbol()); - case '<': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); - break; - case '>': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); - break; - case '=': - add_token(stream, token_type::range_operator, range_operator::equal); - break; - default: - if (is_digit(c)) { - add_token(stream, token_type::digit, to_digit(c)); - break; - } - else if (is_letter(c)) { - add_token(stream, token_type::letter, c); - break; - } - return failure(get_prev_symbol()); - } - - return success(get_prev_symbol()); - } - - constexpr void add_token(token_stream& stream, token_type type, token::value_t value = {}) noexcept { - const char* lexeme = get_prev_symbol(); - stream.push({ type, value, lexeme}); - } - - constexpr char advance() noexcept { - char c = text_[current_pos_]; - current_pos_ += 1; - return c; - } - - constexpr bool advanceIfMatch(char c) noexcept { - if (is_eol()) { - return false; - } - - if (text_[current_pos_] != c) { - return false; - } - - current_pos_ += 1; - - return true; - } - - constexpr const char* get_prev_symbol() const noexcept { - return text_.data() + current_pos_ - 1; - } - - constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } - }; - - class prerelease_comparator { - public: - template - [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { - if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { - return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); - } - - const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); - - for (std::size_t i = 0; i < count; ++i) { - const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); - if (compare_result != 0) { - return compare_result; - } - } - - return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); - } - - private: - [[nodiscard]] constexpr int compare_identifier(const prerelease_identifier& lhs, const prerelease_identifier& rhs) const noexcept { - if (lhs.type == prerelease_identifier_type::numeric && rhs.type == prerelease_identifier_type::numeric) { - return compare_numerically(lhs.identifier, rhs.identifier); - } else if (lhs.type == prerelease_identifier_type::alphanumeric && rhs.type == prerelease_identifier_type::alphanumeric) { - return detail::compare(lhs.identifier, rhs.identifier); - } - - return lhs.type == prerelease_identifier_type::alphanumeric ? 1 : -1; - } - }; - - class version_parser { - public: - constexpr explicit version_parser(token_stream& stream) : stream_{stream} { - } - - template - constexpr from_chars_result parse(version& out) noexcept { - out.clear(); - - from_chars_result result = parse_number(out.major_); - if (!result) { - return result; - } - - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); - } - - result = parse_number(out.minor_); - if (!result) { - return result; - } - - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); - } - - result = parse_number(out.patch_); - if (!result) { - return result; - } - - if (stream_.advanceIfMatch(token_type::hyphen)) { - result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); - if (!result) { - return result; - } - } - - if (stream_.advanceIfMatch(token_type::plus)) { - result = parse_build_metadata(out.build_metadata_); - if (!result) { - return result; - } - } - - return result; - } - - - private: - token_stream& stream_; - - template - constexpr from_chars_result parse_number(Int& out) { - token token = stream_.advance(); - - if (!is_digit(token)) { - return failure(token.lexeme); - } - - const auto first_digit = std::get(token.value); - std::uint64_t result = first_digit; - - if (first_digit == 0) { - out = static_cast(result); - return success(stream_.peek().lexeme); - } - - while (stream_.advanceIfMatch(token, token_type::digit)) { - result = result * 10 + std::get(token.value); - } - - if (detail::number_in_range(result)) { - out = static_cast(result); - return success(stream_.peek().lexeme); - } - - return failure(token.lexeme, std::errc::result_out_of_range); - } - - constexpr from_chars_result parse_prerelease_tag(string& out, vector& out_identifiers) { - string result; - - do { - if (!result.empty()) { - result.push_back('.'); - } - - string identifier; - if (const auto res = parse_prerelease_identifier(identifier); !res) { - return res; - } - - result.append(identifier); - out_identifiers.push_back(make_prerelease_identifier(identifier)); - - } while (stream_.advanceIfMatch(token_type::dot)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr from_chars_result parse_build_metadata(string& out) { - string result; - - do { - if (!result.empty()) { - result.push_back('.'); - } - - string identifier; - if (const auto res = parse_build_identifier(identifier); !res) { - return res; - } - - result.append(identifier); - } while (stream_.advanceIfMatch(token_type::dot)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr from_chars_result parse_prerelease_identifier(string& out) { - string result; - token token = stream_.advance(); - - do { - switch (token.type) { - case token_type::hyphen: - result.push_back('-'); - break; - case token_type::letter: - result.push_back(std::get(token.value)); - break; - case token_type::digit: - { - const auto digit = std::get(token.value); - - // numerical prerelease identifier doesn't allow leading zero - // 1.2.3-1.alpha is valid, - // 1.2.3-01b is valid as well, but - // 1.2.3-01.alpha is not valid - - // Only check for leading zero when digit is the first character of the - // prerelease identifier. - if (result.empty() && is_leading_zero(digit)) { - return failure(token.lexeme); - } - - result.push_back(to_char(digit)); - break; - } - default: - return failure(token.lexeme); - } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { - auto type = detail::prerelease_identifier_type::numeric; - for (char c : identifier) { - if (c == '-' || detail::is_letter(c)) { - type = detail::prerelease_identifier_type::alphanumeric; - break; - } - } - return detail::prerelease_identifier{ type, identifier }; - } - - constexpr from_chars_result parse_build_identifier(string& out) { - string result; - token token = stream_.advance(); - - do { - switch (token.type) { - case token_type::hyphen: - result.push_back('-'); - break; - case token_type::letter: - result.push_back(std::get(token.value)); - break; - case token_type::digit: - { - const auto digit = std::get(token.value); - result.push_back(to_char(digit)); - break; - } - default: - return failure(token.lexeme); - } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr bool is_leading_zero(int digit) noexcept { - if (digit != 0) { - return false; - } - - size_t k = 0; - int alpha_numerics = 0; - int digits = 0; - - while (true) { - const token token = stream_.peek(k); - - if (!is_alphanumeric(token)) { - break; - } - - ++alpha_numerics; - - if (is_digit(token)) { - ++digits; - } - - ++k; - } - - return digits > 0 && digits == alpha_numerics; - } - - constexpr bool is_digit(const token& token) const noexcept { - return token.type == token_type::digit; - } - - constexpr bool is_eol(const token& token) const noexcept { - return token.type == token_type::eol; - } - - constexpr bool is_alphanumeric(const token& token) const noexcept { - return token.type == token_type::hyphen || token.type == token_type::letter || token.type == token_type::digit; - } - }; - - template - constexpr int compare_prerelease(const version& lhs, const version& rhs) noexcept { - return prerelease_comparator{}.compare(lhs, rhs); - } - - template - constexpr int compare_parsed(const version& lhs, const version& rhs, version_compare_option compare_option) { - int result = lhs.major() - rhs.major(); - if (result != 0) { - return result; - } - - result = lhs.minor() - rhs.minor(); - if (result != 0) { - return result; - } - - result = lhs.patch() - rhs.patch(); - if (result != 0) { - return result; - } - - if (compare_option == version_compare_option::include_prerelease) { - result = detail::compare_prerelease(lhs, rhs); - } - - return result; - } - - template - constexpr from_chars_result parse(std::string_view str, version& out) { - token_stream token_stream; - from_chars_result result = lexer{ str }.scan_tokens(token_stream); - if (!result) { - return result; - } - - result = version_parser{ token_stream }.parse(out); - if (!result) { - return result; - } - - if (!token_stream.consume(token_type::eol)) { - return failure(token_stream.previous().lexeme); - } - - return success(token_stream.previous().lexeme); - } - - } // namespace semver::detail - - template - [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) == 0; - } - - template - [[nodiscard]] constexpr bool operator!=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) != 0; - } - - template - [[nodiscard]] constexpr bool operator>(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) > 0; - } - - template - [[nodiscard]] constexpr bool operator>=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) >= 0; - } - - template - [[nodiscard]] constexpr bool operator<(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) < 0; - } - - template - [[nodiscard]] constexpr bool operator<=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; - } + if constexpr (workaround) { + const auto size = std::min(lhs.size(), rhs.size()); + for (std::size_t i = 0; i < size; ++i) { + if (lhs[i] < rhs[i]) { + return -1; + } else if (lhs[i] > rhs[i]) { + return 1; + } + } + + return static_cast(lhs.size() - rhs.size()); + } else { + return lhs.compare(rhs); + } + } + + constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { + // assume that strings don't have leading zeros (we've already checked it at parsing stage). + + if (lhs.size() != rhs.size()) { + return static_cast(lhs.size() - rhs.size()); + } + + for (std::size_t i = 0; i < lhs.size(); ++i) { + int a = lhs[i] - '0'; + int b = rhs[i] - '0'; + if (a != b) { + return a - b; + } + } + + return 0; + } + + enum class token_type : std::uint8_t { + eol, + space, + dot, + plus, + hyphen, + letter, + digit, + range_operator, + logical_or + }; + + enum class range_operator : std::uint8_t { + less, + less_or_equal, + greater, + greater_or_equal, + equal + }; + + struct token { + using value_t = std::variant; + token_type type; + value_t value; + const char* lexeme; + }; + + class token_stream { + public: + constexpr token_stream() = default; + constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} + + constexpr void push(const token& token) noexcept { + tokens_.push_back(token); + } + + constexpr token advance() noexcept { + const token token = get(current_); + ++current_; + return token; + } + + constexpr token peek(std::size_t k = 0) const noexcept { + return get(current_ + k); + } + + constexpr token previous() const noexcept { + return get(current_ - 1); + } + + constexpr bool advanceIfMatch(token& token, token_type type) noexcept { + if (get(current_).type != type) { + return false; + } + + token = advance(); + return true; + } + + constexpr bool advanceIfMatch(token_type type) noexcept { + token token; + return advanceIfMatch(token, type); + } + + constexpr bool consume(token_type type) noexcept { + return advance().type == type; + } + + constexpr bool check(token_type type) const noexcept { + return peek().type == type; + } + + private: + std::size_t current_ = 0; + vector tokens_; + + constexpr token get(std::size_t i) const noexcept { + return tokens_[i]; + } + }; + + class lexer { + public: + explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} + + constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { + from_chars_result result{ text_.data(), std::errc{} }; + + while (!is_eol()) { + result = scan_token(token_stream); + if (!result) { + return result; + } + } + + token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); + + return result; + } + + private: + std::string_view text_; + std::size_t current_pos_; + + constexpr from_chars_result scan_token(token_stream& stream) noexcept { + const char c = advance(); + + switch (c) { + case ' ': + add_token(stream, token_type::space); + break; + case '.': + add_token(stream, token_type::dot); + break; + case '-': + add_token(stream, token_type::hyphen); + break; + case '+': + add_token(stream, token_type::plus); + break; + case '|': + if (advanceIfMatch('|')) { + add_token(stream, token_type::logical_or); + break; + } + return failure(get_prev_symbol()); + case '<': + add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); + break; + case '>': + add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); + break; + case '=': + add_token(stream, token_type::range_operator, range_operator::equal); + break; + default: + if (is_digit(c)) { + add_token(stream, token_type::digit, to_digit(c)); + break; + } + else if (is_letter(c)) { + add_token(stream, token_type::letter, c); + break; + } + return failure(get_prev_symbol()); + } + + return success(get_prev_symbol()); + } + + constexpr void add_token(token_stream& stream, token_type type, token::value_t value = {}) noexcept { + const char* lexeme = get_prev_symbol(); + stream.push({ type, value, lexeme}); + } + + constexpr char advance() noexcept { + char c = text_[current_pos_]; + current_pos_ += 1; + return c; + } + + constexpr bool advanceIfMatch(char c) noexcept { + if (is_eol()) { + return false; + } + + if (text_[current_pos_] != c) { + return false; + } + + current_pos_ += 1; + + return true; + } + + constexpr const char* get_prev_symbol() const noexcept { + return text_.data() + current_pos_ - 1; + } + + constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } + }; + + class prerelease_comparator { + public: + template + [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { + if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { + return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); + } + + const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); + + for (std::size_t i = 0; i < count; ++i) { + const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); + if (compare_result != 0) { + return compare_result; + } + } + + return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); + } + + private: + [[nodiscard]] constexpr int compare_identifier(const prerelease_identifier& lhs, const prerelease_identifier& rhs) const noexcept { + if (lhs.type == prerelease_identifier_type::numeric && rhs.type == prerelease_identifier_type::numeric) { + return compare_numerically(lhs.identifier, rhs.identifier); + } else if (lhs.type == prerelease_identifier_type::alphanumeric && rhs.type == prerelease_identifier_type::alphanumeric) { + return detail::compare(lhs.identifier, rhs.identifier); + } + + return lhs.type == prerelease_identifier_type::alphanumeric ? 1 : -1; + } + }; + + class version_parser { + public: + constexpr explicit version_parser(token_stream& stream) : stream_{stream} { + } + + template + constexpr from_chars_result parse(version& out) noexcept { + out.clear(); + + from_chars_result result = parse_number(out.major_); + if (!result) { + return result; + } + + if (!stream_.consume(token_type::dot)) { + return failure(stream_.previous().lexeme); + } + + result = parse_number(out.minor_); + if (!result) { + return result; + } + + if (!stream_.consume(token_type::dot)) { + return failure(stream_.previous().lexeme); + } + + result = parse_number(out.patch_); + if (!result) { + return result; + } + + if (stream_.advanceIfMatch(token_type::hyphen)) { + result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); + if (!result) { + return result; + } + } + + if (stream_.advanceIfMatch(token_type::plus)) { + result = parse_build_metadata(out.build_metadata_); + if (!result) { + return result; + } + } + + return result; + } + + + private: + token_stream& stream_; + + template + constexpr from_chars_result parse_number(Int& out) { + token token = stream_.advance(); + + if (!is_digit(token)) { + return failure(token.lexeme); + } + + const auto first_digit = std::get(token.value); + std::uint64_t result = first_digit; + + if (first_digit == 0) { + out = static_cast(result); + return success(stream_.peek().lexeme); + } + + while (stream_.advanceIfMatch(token, token_type::digit)) { + result = result * 10 + std::get(token.value); + } + + if (detail::number_in_range(result)) { + out = static_cast(result); + return success(stream_.peek().lexeme); + } + + return failure(token.lexeme, std::errc::result_out_of_range); + } + + constexpr from_chars_result parse_prerelease_tag(string& out, vector& out_identifiers) { + string result; + + do { + if (!result.empty()) { + result.push_back('.'); + } + + string identifier; + if (const auto res = parse_prerelease_identifier(identifier); !res) { + return res; + } + + result.append(identifier); + out_identifiers.push_back(make_prerelease_identifier(identifier)); + + } while (stream_.advanceIfMatch(token_type::dot)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr from_chars_result parse_build_metadata(string& out) { + string result; + + do { + if (!result.empty()) { + result.push_back('.'); + } + + string identifier; + if (const auto res = parse_build_identifier(identifier); !res) { + return res; + } + + result.append(identifier); + } while (stream_.advanceIfMatch(token_type::dot)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr from_chars_result parse_prerelease_identifier(string& out) { + string result; + token token = stream_.advance(); + + do { + switch (token.type) { + case token_type::hyphen: + result.push_back('-'); + break; + case token_type::letter: + result.push_back(std::get(token.value)); + break; + case token_type::digit: + { + const auto digit = std::get(token.value); + + // numerical prerelease identifier doesn't allow leading zero + // 1.2.3-1.alpha is valid, + // 1.2.3-01b is valid as well, but + // 1.2.3-01.alpha is not valid + + // Only check for leading zero when digit is the first character of the + // prerelease identifier. + if (result.empty() && is_leading_zero(digit)) { + return failure(token.lexeme); + } + + result.push_back(to_char(digit)); + break; + } + default: + return failure(token.lexeme); + } + } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { + auto type = detail::prerelease_identifier_type::numeric; + for (char c : identifier) { + if (c == '-' || detail::is_letter(c)) { + type = detail::prerelease_identifier_type::alphanumeric; + break; + } + } + return detail::prerelease_identifier{ type, identifier }; + } + + constexpr from_chars_result parse_build_identifier(string& out) { + string result; + token token = stream_.advance(); + + do { + switch (token.type) { + case token_type::hyphen: + result.push_back('-'); + break; + case token_type::letter: + result.push_back(std::get(token.value)); + break; + case token_type::digit: + { + const auto digit = std::get(token.value); + result.push_back(to_char(digit)); + break; + } + default: + return failure(token.lexeme); + } + } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr bool is_leading_zero(int digit) noexcept { + if (digit != 0) { + return false; + } + + size_t k = 0; + int alpha_numerics = 0; + int digits = 0; + + while (true) { + const token token = stream_.peek(k); + + if (!is_alphanumeric(token)) { + break; + } + + ++alpha_numerics; + + if (is_digit(token)) { + ++digits; + } + + ++k; + } + + return digits > 0 && digits == alpha_numerics; + } + + constexpr bool is_digit(const token& token) const noexcept { + return token.type == token_type::digit; + } + + constexpr bool is_eol(const token& token) const noexcept { + return token.type == token_type::eol; + } + + constexpr bool is_alphanumeric(const token& token) const noexcept { + return token.type == token_type::hyphen || token.type == token_type::letter || token.type == token_type::digit; + } + }; + + template + constexpr int compare_prerelease(const version& lhs, const version& rhs) noexcept { + return prerelease_comparator{}.compare(lhs, rhs); + } + + template + constexpr int compare_parsed(const version& lhs, const version& rhs, version_compare_option compare_option) { + int result = lhs.major() - rhs.major(); + if (result != 0) { + return result; + } + + result = lhs.minor() - rhs.minor(); + if (result != 0) { + return result; + } + + result = lhs.patch() - rhs.patch(); + if (result != 0) { + return result; + } + + if (compare_option == version_compare_option::include_prerelease) { + result = detail::compare_prerelease(lhs, rhs); + } + + return result; + } + + template + constexpr from_chars_result parse(std::string_view str, version& out) { + token_stream token_stream; + from_chars_result result = lexer{ str }.scan_tokens(token_stream); + if (!result) { + return result; + } + + result = version_parser{ token_stream }.parse(out); + if (!result) { + return result; + } + + if (!token_stream.consume(token_type::eol)) { + return failure(token_stream.previous().lexeme); + } + + return success(token_stream.previous().lexeme); + } + + } // namespace semver::detail + + template + [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) == 0; + } + + template + [[nodiscard]] constexpr bool operator!=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) != 0; + } + + template + [[nodiscard]] constexpr bool operator>(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) > 0; + } + + template + [[nodiscard]] constexpr bool operator>=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) >= 0; + } + + template + [[nodiscard]] constexpr bool operator<(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) < 0; + } + + template + [[nodiscard]] constexpr bool operator<=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; + } #if __cpp_impl_three_way_comparison >= 201907L - template - [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { - int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); - if (compare == 0) - return std::strong_ordering::equal; + template + [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { + int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); + if (compare == 0) + return std::strong_ordering::equal; if (compare > 0) - return std::strong_ordering::greater; + return std::strong_ordering::greater; return std::strong_ordering::less; - } + } #endif - template - constexpr from_chars_result parse(std::string_view str, version& output) { - return detail::parse(str, output); - } - - constexpr bool valid(std::string_view str) { - version v{}; - return detail::parse(str, v); - } - - namespace detail { - template - class range_comparator { - public: - constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} - - constexpr bool contains(const version& other) const noexcept { - switch (op_) { - case range_operator::less: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; - case range_operator::less_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; - case range_operator::greater: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; - case range_operator::greater_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; - case range_operator::equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; - } - return false; - } - - constexpr const version& get_version() const noexcept { return v_; } - - constexpr range_operator get_operator() const noexcept { return op_; } - - constexpr string to_string() const { - string result; - switch (op_) { - case range_operator::less: result += "<"; break; - case range_operator::less_or_equal: result += "<="; break; - case range_operator::greater: result += ">"; break; - case range_operator::greater_or_equal: result += ">="; break; - case range_operator::equal: result += "="; break; - } - result += v_.to_string(); - return result; - } - - private: - version v_; - range_operator op_; - }; - - class range_parser; - - template - class range { - public: - friend class detail::range_parser; - - constexpr bool contains(const version& v, version_compare_option option) const noexcept { - if (option == version_compare_option::exclude_prerelease) { - if (!match_at_least_one_comparator_with_prerelease(v)) { - return false; - } - } - - return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { - return ranges_comparator.contains(v); - }); - } - - constexpr auto begin() const noexcept { - return ranges_comparators_.begin(); - } - - constexpr auto end() const noexcept { - return ranges_comparators_.end(); - } - - constexpr std::size_t size() const noexcept { - return ranges_comparators_.size(); - } - - constexpr bool empty() const noexcept { - return ranges_comparators_.empty(); - } - - constexpr string to_string() const { - return join(ranges_comparators_, " "); - } - - private: - vector> ranges_comparators_; - - constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { - if (v.prerelease_tag().empty()) { - return true; - } - - return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { - const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); - const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; - return has_prerelease && equal_without_prerelease; - }); - } - }; - } - - template - class range_set { - public: - friend class detail::range_parser; - - constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { - return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { - return range.contains(v, option); - }); - } - - constexpr auto begin() const noexcept { - return ranges_.begin(); - } - - constexpr auto end() const noexcept { - return ranges_.end(); - } - - constexpr std::size_t size() const noexcept { - return ranges_.size(); - } - - constexpr bool empty() const noexcept { - return ranges_.empty(); - } - - constexpr string to_string() const { - return join(ranges_, " "); - } - - private: - vector> ranges_; - }; - - namespace detail { - class range_parser { - public: - constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} - - template - constexpr from_chars_result parse(range_set& out) noexcept { - vector> ranges; - - do { - - detail::range range; - if (const auto res = parse_range(range); !res) { - return res; - } - - ranges.push_back(range); - skip_whitespaces(); - - } while (stream_.advanceIfMatch(token_type::logical_or)); - - out.ranges_ = std::move(ranges); - - return success(stream_.peek().lexeme); - } - - private: - token_stream stream_; - - template - constexpr from_chars_result parse_range(detail::range& out) noexcept { - do { - skip_whitespaces(); - - if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { - return res; - } - - skip_whitespaces(); - - } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); - - return success(stream_.peek().lexeme); - } - - template - constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { - range_operator op = range_operator::equal; - token token; - if (stream_.advanceIfMatch(token, token_type::range_operator)) { - op = std::get(token.value); - } - - skip_whitespaces(); - - version ver; - version_parser parser{ stream_ }; - if (const auto res = parser.parse(ver); !res) { - return res; - } - - out.emplace_back(ver, op); - return success(stream_.peek().lexeme); - } - - constexpr void skip_whitespaces() noexcept { - while (stream_.advanceIfMatch(token_type::space)) { - ; - } - } - }; - } // namespace semver::detail - - - template - constexpr from_chars_result parse(std::string_view str, range_set& out) { - detail::token_stream token_stream; - const from_chars_result result = detail::lexer{ str }.scan_tokens(token_stream); - if (!result) { - return result; - } - - return detail::range_parser{ std::move(token_stream) }.parse(out); - } + template + constexpr from_chars_result parse(std::string_view str, version& output) { + return detail::parse(str, output); + } + + constexpr bool valid(std::string_view str) { + version v{}; + return detail::parse(str, v); + } + + namespace detail { + template + class range_comparator { + public: + constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} + + constexpr bool contains(const version& other) const noexcept { + switch (op_) { + case range_operator::less: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; + case range_operator::less_or_equal: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; + case range_operator::greater: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; + case range_operator::greater_or_equal: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; + case range_operator::equal: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; + } + return false; + } + + constexpr const version& get_version() const noexcept { return v_; } + + constexpr range_operator get_operator() const noexcept { return op_; } + + constexpr string to_string() const { + string result; + switch (op_) { + case range_operator::less: result += "<"; break; + case range_operator::less_or_equal: result += "<="; break; + case range_operator::greater: result += ">"; break; + case range_operator::greater_or_equal: result += ">="; break; + case range_operator::equal: result += "="; break; + } + result += v_.to_string(); + return result; + } + + private: + version v_; + range_operator op_; + }; + + class range_parser; + + template + class range { + public: + friend class detail::range_parser; + + constexpr bool contains(const version& v, version_compare_option option) const noexcept { + if (option == version_compare_option::exclude_prerelease) { + if (!match_at_least_one_comparator_with_prerelease(v)) { + return false; + } + } + + return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + return ranges_comparator.contains(v); + }); + } + + constexpr auto begin() const noexcept { + return ranges_comparators_.begin(); + } + + constexpr auto end() const noexcept { + return ranges_comparators_.end(); + } + + constexpr std::size_t size() const noexcept { + return ranges_comparators_.size(); + } + + constexpr bool empty() const noexcept { + return ranges_comparators_.empty(); + } + + constexpr string to_string() const { + return join(ranges_comparators_, " "); + } + + private: + vector> ranges_comparators_; + + constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { + if (v.prerelease_tag().empty()) { + return true; + } + + return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); + const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; + return has_prerelease && equal_without_prerelease; + }); + } + }; + } + + template + class range_set { + public: + friend class detail::range_parser; + + constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { + return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { + return range.contains(v, option); + }); + } + + constexpr auto begin() const noexcept { + return ranges_.begin(); + } + + constexpr auto end() const noexcept { + return ranges_.end(); + } + + constexpr std::size_t size() const noexcept { + return ranges_.size(); + } + + constexpr bool empty() const noexcept { + return ranges_.empty(); + } + + constexpr string to_string() const { + return join(ranges_, " "); + } + + private: + vector> ranges_; + }; + + namespace detail { + class range_parser { + public: + constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} + + template + constexpr from_chars_result parse(range_set& out) noexcept { + vector> ranges; + + do { + + detail::range range; + if (const auto res = parse_range(range); !res) { + return res; + } + + ranges.push_back(range); + skip_whitespaces(); + + } while (stream_.advanceIfMatch(token_type::logical_or)); + + out.ranges_ = std::move(ranges); + + return success(stream_.peek().lexeme); + } + + private: + token_stream stream_; + + template + constexpr from_chars_result parse_range(detail::range& out) noexcept { + do { + skip_whitespaces(); + + if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { + return res; + } + + skip_whitespaces(); + + } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); + + return success(stream_.peek().lexeme); + } + + template + constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { + range_operator op = range_operator::equal; + token token; + if (stream_.advanceIfMatch(token, token_type::range_operator)) { + op = std::get(token.value); + } + + skip_whitespaces(); + + version ver; + version_parser parser{ stream_ }; + if (const auto res = parser.parse(ver); !res) { + return res; + } + + out.emplace_back(ver, op); + return success(stream_.peek().lexeme); + } + + constexpr void skip_whitespaces() noexcept { + while (stream_.advanceIfMatch(token_type::space)) { + ; + } + } + }; + } // namespace semver::detail + + + template + constexpr from_chars_result parse(std::string_view str, range_set& out) { + detail::token_stream token_stream; + const from_chars_result result = detail::lexer{ str }.scan_tokens(token_stream); + if (!result) { + return result; + } + + return detail::range_parser{ std::move(token_stream) }.parse(out); + } } // namespace semver #ifndef PLUGIFY_VECTOR_NO_STD_HASH @@ -1078,7 +1078,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); @@ -1089,7 +1089,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); @@ -1100,7 +1100,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); diff --git a/test/cross_call_worker/external/plugify/include/pps/cross_call_master.hpp b/test/cross_call_worker/external/plugify/include/pps/cross_call_master.hpp index 169472e..e1333ef 100644 --- a/test/cross_call_worker/external/plugify/include/pps/cross_call_master.hpp +++ b/test/cross_call_worker/external/plugify/include/pps/cross_call_master.hpp @@ -7,3018 +7,3226 @@ // Generated from cross_call_master.pplugin by https://github.com/untrustedmodders/plugify-module-cpp/blob/main/generator/generator.py namespace cross_call_master { - enum class Example : int32_t { - First = 1, - Second = 2, - Third = 3, - Forth = 4, - }; - - using NoParamReturnFunctionCallbackFunc = int32_t (*)(); - using FuncVoid = void (*)(); - using FuncBool = bool (*)(); - using FuncChar8 = char (*)(); - using FuncChar16 = char16_t (*)(); - using FuncInt8 = int8_t (*)(); - using FuncInt16 = int16_t (*)(); - using FuncInt32 = int32_t (*)(); - using FuncInt64 = int64_t (*)(); - using FuncUInt8 = uint8_t (*)(); - using FuncUInt16 = uint16_t (*)(); - using FuncUInt32 = uint32_t (*)(); - using FuncUInt64 = uint64_t (*)(); - using FuncPtr = void* (*)(); - using FuncFloat = float (*)(); - using FuncDouble = double (*)(); - using FuncString = plg::string (*)(); - using FuncAny = plg::any (*)(); - using FuncFunction = void* (*)(); - using FuncBoolVector = plg::vector (*)(); - using FuncChar8Vector = plg::vector (*)(); - using FuncChar16Vector = plg::vector (*)(); - using FuncInt8Vector = plg::vector (*)(); - using FuncInt16Vector = plg::vector (*)(); - using FuncInt32Vector = plg::vector (*)(); - using FuncInt64Vector = plg::vector (*)(); - using FuncUInt8Vector = plg::vector (*)(); - using FuncUInt16Vector = plg::vector (*)(); - using FuncUInt32Vector = plg::vector (*)(); - using FuncUInt64Vector = plg::vector (*)(); - using FuncPtrVector = plg::vector (*)(); - using FuncFloatVector = plg::vector (*)(); - using FuncDoubleVector = plg::vector (*)(); - using FuncStringVector = plg::vector (*)(); - using FuncAnyVector = plg::vector (*)(); - using FuncVec2Vector = plg::vector (*)(); - using FuncVec3Vector = plg::vector (*)(); - using FuncVec4Vector = plg::vector (*)(); - using FuncMat4x4Vector = plg::vector (*)(); - using FuncVec2 = plg::vec2 (*)(); - using FuncVec3 = plg::vec3 (*)(); - using FuncVec4 = plg::vec4 (*)(); - using FuncMat4x4 = plg::mat4x4 (*)(); - using Func1 = int32_t (*)(const plg::vec3&); - using Func2 = char (*)(float, int64_t); - using Func3 = void (*)(void*, const plg::vec4&, const plg::string&); - using Func4 = plg::vec4 (*)(bool, int32_t, char16_t, const plg::mat4x4&); - using Func5 = bool (*)(int8_t, const plg::vec2&, void*, double, const plg::vector&); - using Func6 = int64_t (*)(const plg::string&, float, const plg::vector&, int16_t, const plg::vector&, void*); - using Func7 = double (*)(const plg::vector&, uint16_t, char16_t, const plg::vector&, const plg::vec4&, bool, uint64_t); - using Func8 = plg::mat4x4 (*)(const plg::vec3&, const plg::vector&, int16_t, bool, const plg::vec4&, const plg::vector&, char16_t, int32_t); - using Func9 = void (*)(float, const plg::vec2&, const plg::vector&, uint64_t, bool, const plg::string&, const plg::vec4&, int16_t, void*); - using Func10 = uint32_t (*)(const plg::vec4&, const plg::mat4x4&, const plg::vector&, uint64_t, const plg::vector&, int32_t, bool, const plg::vec2&, int64_t, double); - using Func11 = void* (*)(const plg::vector&, char16_t, uint8_t, double, const plg::vec3&, const plg::vector&, int64_t, uint16_t, float, const plg::vec2&, uint32_t); - using Func12 = bool (*)(void*, const plg::vector&, uint32_t, double, bool, int32_t, int8_t, uint64_t, float, const plg::vector&, int64_t, char); - using Func13 = plg::string (*)(int64_t, const plg::vector&, uint16_t, float, const plg::vector&, const plg::vec4&, const plg::string&, int32_t, const plg::vec3&, void*, const plg::vec2&, const plg::vector&, int16_t); - using Func14 = plg::vector (*)(const plg::vector&, const plg::vector&, const plg::mat4x4&, bool, char16_t, int32_t, const plg::vector&, uint16_t, const plg::vector&, int8_t, const plg::vec3&, const plg::vec4&, double, void*); - using Func15 = int16_t (*)(const plg::vector&, const plg::mat4x4&, const plg::vec4&, void*, uint64_t, const plg::vector&, bool, float, const plg::vector&, uint8_t, int32_t, const plg::vec2&, uint16_t, double, const plg::vector&); - using Func16 = void* (*)(const plg::vector&, int16_t, const plg::vector&, const plg::vec4&, const plg::mat4x4&, const plg::vec2&, const plg::vector&, const plg::vector&, const plg::string&, int64_t, const plg::vector&, const plg::vec3&, float, double, int8_t, uint16_t); - using Func17 = void (*)(int32_t&); - using Func18 = plg::vec2 (*)(int8_t&, int16_t&); - using Func19 = void (*)(uint32_t&, plg::vec3&, plg::vector&); - using Func20 = int32_t (*)(char16_t&, plg::vec4&, plg::vector&, char&); - using Func21 = float (*)(plg::mat4x4&, plg::vector&, plg::vec2&, bool&, double&); - using Func22 = uint64_t (*)(void*&, uint32_t&, plg::vector&, int16_t&, plg::string&, plg::vec4&); - using Func23 = void (*)(uint64_t&, plg::vec2&, plg::vector&, char16_t&, float&, int8_t&, plg::vector&); - using Func24 = plg::mat4x4 (*)(plg::vector&, int64_t&, plg::vector&, plg::vec4&, uint64_t&, plg::vector&, double&, plg::vector&); - using Func25 = double (*)(int32_t&, plg::vector&, bool&, uint8_t&, plg::string&, plg::vec3&, int64_t&, plg::vec4&, uint16_t&); - using Func26 = char (*)(char16_t&, plg::vec2&, plg::mat4x4&, plg::vector&, int16_t&, uint64_t&, uint32_t&, plg::vector&, void*&, bool&); - using Func27 = uint8_t (*)(float&, plg::vec3&, void*&, plg::vec2&, plg::vector&, plg::mat4x4&, bool&, plg::vec4&, int8_t&, int32_t&, plg::vector&); - using Func28 = plg::string (*)(void*&, uint16_t&, plg::vector&, plg::mat4x4&, float&, plg::vec4&, plg::string&, plg::vector&, int64_t&, bool&, plg::vec3&, plg::vector&); - using Func29 = plg::vector (*)(plg::vec4&, int32_t&, plg::vector&, double&, bool&, int8_t&, plg::vector&, float&, plg::string&, plg::mat4x4&, uint64_t&, plg::vec3&, plg::vector&); - using Func30 = int32_t (*)(void*&, plg::vec4&, int64_t&, plg::vector&, bool&, plg::string&, plg::vec3&, plg::vector&, float&, plg::vec2&, plg::mat4x4&, int8_t&, plg::vector&, double&); - using Func31 = plg::vec3 (*)(char&, uint32_t&, plg::vector&, plg::vec4&, plg::string&, bool&, int64_t&, plg::vec2&, int8_t&, uint16_t&, plg::vector&, plg::mat4x4&, plg::vec3&, float&, plg::vector&); - using Func32 = double (*)(int32_t&, uint16_t&, plg::vector&, plg::vec4&, void*&, plg::vector&, plg::mat4x4&, uint64_t&, plg::string&, int64_t&, plg::vec2&, plg::vector&, bool&, plg::vec3&, uint8_t&, plg::vector&); - using Func33 = void (*)(plg::any&); - using FuncEnum = plg::vector (*)(Example, plg::vector&); - - /** - * @brief No description provided. - * - * @function ReverseReturn - * @param returnString (string): No description available. - */ - inline void ReverseReturn(const plg::string& returnString) { - using ReverseReturnFn = void (*)(const plg::string&); - static ReverseReturnFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ReverseReturn", reinterpret_cast(&__func)); - __func(returnString); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnVoidCallback - */ - inline void NoParamReturnVoidCallback() { - using NoParamReturnVoidCallbackFn = void (*)(); - static NoParamReturnVoidCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnVoidCallback", reinterpret_cast(&__func)); - __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnBoolCallback - * - * @return bool: No description available. - */ - inline bool NoParamReturnBoolCallback() { - using NoParamReturnBoolCallbackFn = bool (*)(); - static NoParamReturnBoolCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnBoolCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnChar8Callback - * - * @return char8: No description available. - */ - inline char NoParamReturnChar8Callback() { - using NoParamReturnChar8CallbackFn = char (*)(); - static NoParamReturnChar8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnChar8Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnChar16Callback - * - * @return char16: No description available. - */ - inline char16_t NoParamReturnChar16Callback() { - using NoParamReturnChar16CallbackFn = char16_t (*)(); - static NoParamReturnChar16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnChar16Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnInt8Callback - * - * @return int8: No description available. - */ - inline int8_t NoParamReturnInt8Callback() { - using NoParamReturnInt8CallbackFn = int8_t (*)(); - static NoParamReturnInt8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnInt8Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnInt16Callback - * - * @return int16: No description available. - */ - inline int16_t NoParamReturnInt16Callback() { - using NoParamReturnInt16CallbackFn = int16_t (*)(); - static NoParamReturnInt16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnInt16Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnInt32Callback - * - * @return int32: No description available. - */ - inline int32_t NoParamReturnInt32Callback() { - using NoParamReturnInt32CallbackFn = int32_t (*)(); - static NoParamReturnInt32CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnInt32Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnInt64Callback - * - * @return int64: No description available. - */ - inline int64_t NoParamReturnInt64Callback() { - using NoParamReturnInt64CallbackFn = int64_t (*)(); - static NoParamReturnInt64CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnInt64Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnUInt8Callback - * - * @return uint8: No description available. - */ - inline uint8_t NoParamReturnUInt8Callback() { - using NoParamReturnUInt8CallbackFn = uint8_t (*)(); - static NoParamReturnUInt8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnUInt8Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnUInt16Callback - * - * @return uint16: No description available. - */ - inline uint16_t NoParamReturnUInt16Callback() { - using NoParamReturnUInt16CallbackFn = uint16_t (*)(); - static NoParamReturnUInt16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnUInt16Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnUInt32Callback - * - * @return uint32: No description available. - */ - inline uint32_t NoParamReturnUInt32Callback() { - using NoParamReturnUInt32CallbackFn = uint32_t (*)(); - static NoParamReturnUInt32CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnUInt32Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnUInt64Callback - * - * @return uint64: No description available. - */ - inline uint64_t NoParamReturnUInt64Callback() { - using NoParamReturnUInt64CallbackFn = uint64_t (*)(); - static NoParamReturnUInt64CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnUInt64Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnPointerCallback - * - * @return ptr64: No description available. - */ - inline void* NoParamReturnPointerCallback() { - using NoParamReturnPointerCallbackFn = void* (*)(); - static NoParamReturnPointerCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnPointerCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnFloatCallback - * - * @return float: No description available. - */ - inline float NoParamReturnFloatCallback() { - using NoParamReturnFloatCallbackFn = float (*)(); - static NoParamReturnFloatCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnFloatCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnDoubleCallback - * - * @return double: No description available. - */ - inline double NoParamReturnDoubleCallback() { - using NoParamReturnDoubleCallbackFn = double (*)(); - static NoParamReturnDoubleCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnDoubleCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnFunctionCallback - * - * @return function: No description available. - */ - inline NoParamReturnFunctionCallbackFunc NoParamReturnFunctionCallback() { - using NoParamReturnFunctionCallbackFn = NoParamReturnFunctionCallbackFunc (*)(); - static NoParamReturnFunctionCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnFunctionCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnStringCallback - * - * @return string: No description available. - */ - inline plg::string NoParamReturnStringCallback() { - using NoParamReturnStringCallbackFn = plg::string (*)(); - static NoParamReturnStringCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnStringCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnAnyCallback - * - * @return any: No description available. - */ - inline plg::any NoParamReturnAnyCallback() { - using NoParamReturnAnyCallbackFn = plg::any (*)(); - static NoParamReturnAnyCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnAnyCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayBoolCallback - * - * @return bool[]: No description available. - */ - inline plg::vector NoParamReturnArrayBoolCallback() { - using NoParamReturnArrayBoolCallbackFn = plg::vector (*)(); - static NoParamReturnArrayBoolCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayBoolCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayChar8Callback - * - * @return char8[]: No description available. - */ - inline plg::vector NoParamReturnArrayChar8Callback() { - using NoParamReturnArrayChar8CallbackFn = plg::vector (*)(); - static NoParamReturnArrayChar8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayChar8Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayChar16Callback - * - * @return char16[]: No description available. - */ - inline plg::vector NoParamReturnArrayChar16Callback() { - using NoParamReturnArrayChar16CallbackFn = plg::vector (*)(); - static NoParamReturnArrayChar16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayChar16Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayInt8Callback - * - * @return int8[]: No description available. - */ - inline plg::vector NoParamReturnArrayInt8Callback() { - using NoParamReturnArrayInt8CallbackFn = plg::vector (*)(); - static NoParamReturnArrayInt8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayInt8Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayInt16Callback - * - * @return int16[]: No description available. - */ - inline plg::vector NoParamReturnArrayInt16Callback() { - using NoParamReturnArrayInt16CallbackFn = plg::vector (*)(); - static NoParamReturnArrayInt16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayInt16Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayInt32Callback - * - * @return int32[]: No description available. - */ - inline plg::vector NoParamReturnArrayInt32Callback() { - using NoParamReturnArrayInt32CallbackFn = plg::vector (*)(); - static NoParamReturnArrayInt32CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayInt32Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayInt64Callback - * - * @return int64[]: No description available. - */ - inline plg::vector NoParamReturnArrayInt64Callback() { - using NoParamReturnArrayInt64CallbackFn = plg::vector (*)(); - static NoParamReturnArrayInt64CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayInt64Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayUInt8Callback - * - * @return uint8[]: No description available. - */ - inline plg::vector NoParamReturnArrayUInt8Callback() { - using NoParamReturnArrayUInt8CallbackFn = plg::vector (*)(); - static NoParamReturnArrayUInt8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayUInt8Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayUInt16Callback - * - * @return uint16[]: No description available. - */ - inline plg::vector NoParamReturnArrayUInt16Callback() { - using NoParamReturnArrayUInt16CallbackFn = plg::vector (*)(); - static NoParamReturnArrayUInt16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayUInt16Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayUInt32Callback - * - * @return uint32[]: No description available. - */ - inline plg::vector NoParamReturnArrayUInt32Callback() { - using NoParamReturnArrayUInt32CallbackFn = plg::vector (*)(); - static NoParamReturnArrayUInt32CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayUInt32Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayUInt64Callback - * - * @return uint64[]: No description available. - */ - inline plg::vector NoParamReturnArrayUInt64Callback() { - using NoParamReturnArrayUInt64CallbackFn = plg::vector (*)(); - static NoParamReturnArrayUInt64CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayUInt64Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayPointerCallback - * - * @return ptr64[]: No description available. - */ - inline plg::vector NoParamReturnArrayPointerCallback() { - using NoParamReturnArrayPointerCallbackFn = plg::vector (*)(); - static NoParamReturnArrayPointerCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayPointerCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayFloatCallback - * - * @return float[]: No description available. - */ - inline plg::vector NoParamReturnArrayFloatCallback() { - using NoParamReturnArrayFloatCallbackFn = plg::vector (*)(); - static NoParamReturnArrayFloatCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayFloatCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayDoubleCallback - * - * @return double[]: No description available. - */ - inline plg::vector NoParamReturnArrayDoubleCallback() { - using NoParamReturnArrayDoubleCallbackFn = plg::vector (*)(); - static NoParamReturnArrayDoubleCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayDoubleCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayStringCallback - * - * @return string[]: No description available. - */ - inline plg::vector NoParamReturnArrayStringCallback() { - using NoParamReturnArrayStringCallbackFn = plg::vector (*)(); - static NoParamReturnArrayStringCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayStringCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayAnyCallback - * - * @return any[]: No description available. - */ - inline plg::vector NoParamReturnArrayAnyCallback() { - using NoParamReturnArrayAnyCallbackFn = plg::vector (*)(); - static NoParamReturnArrayAnyCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayAnyCallback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayVector2Callback - * - * @return vec2[]: No description available. - */ - inline plg::vector NoParamReturnArrayVector2Callback() { - using NoParamReturnArrayVector2CallbackFn = plg::vector (*)(); - static NoParamReturnArrayVector2CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayVector2Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayVector3Callback - * - * @return vec3[]: No description available. - */ - inline plg::vector NoParamReturnArrayVector3Callback() { - using NoParamReturnArrayVector3CallbackFn = plg::vector (*)(); - static NoParamReturnArrayVector3CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayVector3Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayVector4Callback - * - * @return vec4[]: No description available. - */ - inline plg::vector NoParamReturnArrayVector4Callback() { - using NoParamReturnArrayVector4CallbackFn = plg::vector (*)(); - static NoParamReturnArrayVector4CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayVector4Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnArrayMatrix4x4Callback - * - * @return mat4x4[]: No description available. - */ - inline plg::vector NoParamReturnArrayMatrix4x4Callback() { - using NoParamReturnArrayMatrix4x4CallbackFn = plg::vector (*)(); - static NoParamReturnArrayMatrix4x4CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayMatrix4x4Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnVector2Callback - * - * @return vec2: No description available. - */ - inline plg::vec2 NoParamReturnVector2Callback() { - using NoParamReturnVector2CallbackFn = plg::vec2 (*)(); - static NoParamReturnVector2CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnVector2Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnVector3Callback - * - * @return vec3: No description available. - */ - inline plg::vec3 NoParamReturnVector3Callback() { - using NoParamReturnVector3CallbackFn = plg::vec3 (*)(); - static NoParamReturnVector3CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnVector3Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnVector4Callback - * - * @return vec4: No description available. - */ - inline plg::vec4 NoParamReturnVector4Callback() { - using NoParamReturnVector4CallbackFn = plg::vec4 (*)(); - static NoParamReturnVector4CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnVector4Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function NoParamReturnMatrix4x4Callback - * - * @return mat4x4: No description available. - */ - inline plg::mat4x4 NoParamReturnMatrix4x4Callback() { - using NoParamReturnMatrix4x4CallbackFn = plg::mat4x4 (*)(); - static NoParamReturnMatrix4x4CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnMatrix4x4Callback", reinterpret_cast(&__func)); - return __func(); - } - - /** - * @brief No description provided. - * - * @function Param1Callback - * @param a (int32): No description available. - */ - inline void Param1Callback(int32_t a) { - using Param1CallbackFn = void (*)(int32_t); - static Param1CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param1Callback", reinterpret_cast(&__func)); - __func(a); - } - - /** - * @brief No description provided. - * - * @function Param2Callback - * @param a (int32): No description available. - * @param b (float): No description available. - */ - inline void Param2Callback(int32_t a, float b) { - using Param2CallbackFn = void (*)(int32_t, float); - static Param2CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param2Callback", reinterpret_cast(&__func)); - __func(a, b); - } - - /** - * @brief No description provided. - * - * @function Param3Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - */ - inline void Param3Callback(int32_t a, float b, double c) { - using Param3CallbackFn = void (*)(int32_t, float, double); - static Param3CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param3Callback", reinterpret_cast(&__func)); - __func(a, b, c); - } - - /** - * @brief No description provided. - * - * @function Param4Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - */ - inline void Param4Callback(int32_t a, float b, double c, const plg::vec4& d) { - using Param4CallbackFn = void (*)(int32_t, float, double, const plg::vec4&); - static Param4CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param4Callback", reinterpret_cast(&__func)); - __func(a, b, c, d); - } - - /** - * @brief No description provided. - * - * @function Param5Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - */ - inline void Param5Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e) { - using Param5CallbackFn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&); - static Param5CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param5Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e); - } - - /** - * @brief No description provided. - * - * @function Param6Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - */ - inline void Param6Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f) { - using Param6CallbackFn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char); - static Param6CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param6Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f); - } - - /** - * @brief No description provided. - * - * @function Param7Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - */ - inline void Param7Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g) { - using Param7CallbackFn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char, const plg::string&); - static Param7CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param7Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g); - } - - /** - * @brief No description provided. - * - * @function Param8Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - */ - inline void Param8Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h) { - using Param8CallbackFn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char, const plg::string&, char16_t); - static Param8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param8Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h); - } - - /** - * @brief No description provided. - * - * @function Param9Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - * @param k (int16): No description available. - */ - inline void Param9Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h, int16_t k) { - using Param9CallbackFn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char, const plg::string&, char16_t, int16_t); - static Param9CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param9Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h, k); - } - - /** - * @brief No description provided. - * - * @function Param10Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - * @param k (int16): No description available. - * @param l (ptr64): No description available. - */ - inline void Param10Callback(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h, int16_t k, void* l) { - using Param10CallbackFn = void (*)(int32_t, float, double, const plg::vec4&, const plg::vector&, char, const plg::string&, char16_t, int16_t, void*); - static Param10CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param10Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h, k, l); - } - - /** - * @brief No description provided. - * - * @function ParamRef1Callback - * @param a (int32): No description available. - */ - inline void ParamRef1Callback(int32_t& a) { - using ParamRef1CallbackFn = void (*)(int32_t&); - static ParamRef1CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef1Callback", reinterpret_cast(&__func)); - __func(a); - } - - /** - * @brief No description provided. - * - * @function ParamRef2Callback - * @param a (int32): No description available. - * @param b (float): No description available. - */ - inline void ParamRef2Callback(int32_t& a, float& b) { - using ParamRef2CallbackFn = void (*)(int32_t&, float&); - static ParamRef2CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef2Callback", reinterpret_cast(&__func)); - __func(a, b); - } - - /** - * @brief No description provided. - * - * @function ParamRef3Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - */ - inline void ParamRef3Callback(int32_t& a, float& b, double& c) { - using ParamRef3CallbackFn = void (*)(int32_t&, float&, double&); - static ParamRef3CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef3Callback", reinterpret_cast(&__func)); - __func(a, b, c); - } - - /** - * @brief No description provided. - * - * @function ParamRef4Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - */ - inline void ParamRef4Callback(int32_t& a, float& b, double& c, plg::vec4& d) { - using ParamRef4CallbackFn = void (*)(int32_t&, float&, double&, plg::vec4&); - static ParamRef4CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef4Callback", reinterpret_cast(&__func)); - __func(a, b, c, d); - } - - /** - * @brief No description provided. - * - * @function ParamRef5Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - */ - inline void ParamRef5Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e) { - using ParamRef5CallbackFn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&); - static ParamRef5CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef5Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e); - } - - /** - * @brief No description provided. - * - * @function ParamRef6Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - */ - inline void ParamRef6Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f) { - using ParamRef6CallbackFn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&); - static ParamRef6CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef6Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f); - } - - /** - * @brief No description provided. - * - * @function ParamRef7Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - */ - inline void ParamRef7Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g) { - using ParamRef7CallbackFn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&, plg::string&); - static ParamRef7CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef7Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g); - } - - /** - * @brief No description provided. - * - * @function ParamRef8Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - */ - inline void ParamRef8Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h) { - using ParamRef8CallbackFn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&, plg::string&, char16_t&); - static ParamRef8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef8Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h); - } - - /** - * @brief No description provided. - * - * @function ParamRef9Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - * @param k (int16): No description available. - */ - inline void ParamRef9Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h, int16_t& k) { - using ParamRef9CallbackFn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&, plg::string&, char16_t&, int16_t&); - static ParamRef9CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef9Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h, k); - } - - /** - * @brief No description provided. - * - * @function ParamRef10Callback - * @param a (int32): No description available. - * @param b (float): No description available. - * @param c (double): No description available. - * @param d (vec4): No description available. - * @param e (int64[]): No description available. - * @param f (char8): No description available. - * @param g (string): No description available. - * @param h (char16): No description available. - * @param k (int16): No description available. - * @param l (ptr64): No description available. - */ - inline void ParamRef10Callback(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h, int16_t& k, void*& l) { - using ParamRef10CallbackFn = void (*)(int32_t&, float&, double&, plg::vec4&, plg::vector&, char&, plg::string&, char16_t&, int16_t&, void*&); - static ParamRef10CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef10Callback", reinterpret_cast(&__func)); - __func(a, b, c, d, e, f, g, h, k, l); - } - - /** - * @brief No description provided. - * - * @function ParamRefVectorsCallback - * @param p1 (bool[]): No description available. - * @param p2 (char8[]): No description available. - * @param p3 (char16[]): No description available. - * @param p4 (int8[]): No description available. - * @param p5 (int16[]): No description available. - * @param p6 (int32[]): No description available. - * @param p7 (int64[]): No description available. - * @param p8 (uint8[]): No description available. - * @param p9 (uint16[]): No description available. - * @param p10 (uint32[]): No description available. - * @param p11 (uint64[]): No description available. - * @param p12 (ptr64[]): No description available. - * @param p13 (float[]): No description available. - * @param p14 (double[]): No description available. - * @param p15 (string[]): No description available. - */ - inline void ParamRefVectorsCallback(plg::vector& p1, plg::vector& p2, plg::vector& p3, plg::vector& p4, plg::vector& p5, plg::vector& p6, plg::vector& p7, plg::vector& p8, plg::vector& p9, plg::vector& p10, plg::vector& p11, plg::vector& p12, plg::vector& p13, plg::vector& p14, plg::vector& p15) { - using ParamRefVectorsCallbackFn = void (*)(plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&, plg::vector&); - static ParamRefVectorsCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRefVectorsCallback", reinterpret_cast(&__func)); - __func(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); - } - - /** - * @brief No description provided. - * - * @function ParamAllPrimitivesCallback - * @param p1 (bool): No description available. - * @param p2 (char8): No description available. - * @param p3 (char16): No description available. - * @param p4 (int8): No description available. - * @param p5 (int16): No description available. - * @param p6 (int32): No description available. - * @param p7 (int64): No description available. - * @param p8 (uint8): No description available. - * @param p9 (uint16): No description available. - * @param p10 (uint32): No description available. - * @param p11 (uint64): No description available. - * @param p12 (ptr64): No description available. - * @param p13 (float): No description available. - * @param p14 (double): No description available. - * - * @return int64: No description available. - */ - inline int64_t ParamAllPrimitivesCallback(bool p1, char p2, char16_t p3, int8_t p4, int16_t p5, int32_t p6, int64_t p7, uint8_t p8, uint16_t p9, uint32_t p10, uint64_t p11, void* p12, float p13, double p14) { - using ParamAllPrimitivesCallbackFn = int64_t (*)(bool, char, char16_t, int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, void*, float, double); - static ParamAllPrimitivesCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamAllPrimitivesCallback", reinterpret_cast(&__func)); - return __func(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); - } - - /** - * @brief No description provided. - * - * @function ParamEnumCallback - * @param p1 (int32): No description available. - * @param p2 (int32[]): No description available. - * - * @return int32: No description available. - */ - inline int32_t ParamEnumCallback(Example p1, const plg::vector& p2) { - using ParamEnumCallbackFn = int32_t (*)(Example, const plg::vector&); - static ParamEnumCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamEnumCallback", reinterpret_cast(&__func)); - return __func(p1, p2); - } - - /** - * @brief No description provided. - * - * @function ParamEnumRefCallback - * @param p1 (int32): No description available. - * @param p2 (int32[]): No description available. - * - * @return int32: No description available. - */ - inline int32_t ParamEnumRefCallback(Example& p1, plg::vector& p2) { - using ParamEnumRefCallbackFn = int32_t (*)(Example&, plg::vector&); - static ParamEnumRefCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamEnumRefCallback", reinterpret_cast(&__func)); - return __func(p1, p2); - } - - /** - * @brief No description provided. - * - * @function ParamVariantCallback - * @param p1 (any): No description available. - * @param p2 (any[]): No description available. - */ - inline void ParamVariantCallback(const plg::any& p1, const plg::vector& p2) { - using ParamVariantCallbackFn = void (*)(const plg::any&, const plg::vector&); - static ParamVariantCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamVariantCallback", reinterpret_cast(&__func)); - __func(p1, p2); - } - - /** - * @brief No description provided. - * - * @function ParamVariantRefCallback - * @param p1 (any): No description available. - * @param p2 (any[]): No description available. - */ - inline void ParamVariantRefCallback(plg::any& p1, plg::vector& p2) { - using ParamVariantRefCallbackFn = void (*)(plg::any&, plg::vector&); - static ParamVariantRefCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamVariantRefCallback", reinterpret_cast(&__func)); - __func(p1, p2); - } - - /** - * @brief No description provided. - * - * @function CallFuncVoidCallback - * @param func (function): No description available. - * - * @callback FuncVoid - * @brief No description provided. - * - * - * @return (callback): void: No description available. - */ - inline void CallFuncVoidCallback(FuncVoid func) { - using CallFuncVoidCallbackFn = void (*)(FuncVoid); - static CallFuncVoidCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVoidCallback", reinterpret_cast(&__func)); - __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncBoolCallback - * @param func (function): No description available. - * - * @return bool: No description available. - * - * @callback FuncBool - * @brief No description provided. - * - * - * @return (callback): bool: No description available. - */ - inline bool CallFuncBoolCallback(FuncBool func) { - using CallFuncBoolCallbackFn = bool (*)(FuncBool); - static CallFuncBoolCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncBoolCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncChar8Callback - * @param func (function): No description available. - * - * @return char8: No description available. - * - * @callback FuncChar8 - * @brief No description provided. - * - * - * @return (callback): char8: No description available. - */ - inline char CallFuncChar8Callback(FuncChar8 func) { - using CallFuncChar8CallbackFn = char (*)(FuncChar8); - static CallFuncChar8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncChar8Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncChar16Callback - * @param func (function): No description available. - * - * @return char16: No description available. - * - * @callback FuncChar16 - * @brief No description provided. - * - * - * @return (callback): char16: No description available. - */ - inline char16_t CallFuncChar16Callback(FuncChar16 func) { - using CallFuncChar16CallbackFn = char16_t (*)(FuncChar16); - static CallFuncChar16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncChar16Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt8Callback - * @param func (function): No description available. - * - * @return int8: No description available. - * - * @callback FuncInt8 - * @brief No description provided. - * - * - * @return (callback): int8: No description available. - */ - inline int8_t CallFuncInt8Callback(FuncInt8 func) { - using CallFuncInt8CallbackFn = int8_t (*)(FuncInt8); - static CallFuncInt8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt8Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt16Callback - * @param func (function): No description available. - * - * @return int16: No description available. - * - * @callback FuncInt16 - * @brief No description provided. - * - * - * @return (callback): int16: No description available. - */ - inline int16_t CallFuncInt16Callback(FuncInt16 func) { - using CallFuncInt16CallbackFn = int16_t (*)(FuncInt16); - static CallFuncInt16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt16Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt32Callback - * @param func (function): No description available. - * - * @return int32: No description available. - * - * @callback FuncInt32 - * @brief No description provided. - * - * - * @return (callback): int32: No description available. - */ - inline int32_t CallFuncInt32Callback(FuncInt32 func) { - using CallFuncInt32CallbackFn = int32_t (*)(FuncInt32); - static CallFuncInt32CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt32Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt64Callback - * @param func (function): No description available. - * - * @return int64: No description available. - * - * @callback FuncInt64 - * @brief No description provided. - * - * - * @return (callback): int64: No description available. - */ - inline int64_t CallFuncInt64Callback(FuncInt64 func) { - using CallFuncInt64CallbackFn = int64_t (*)(FuncInt64); - static CallFuncInt64CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt64Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt8Callback - * @param func (function): No description available. - * - * @return uint8: No description available. - * - * @callback FuncUInt8 - * @brief No description provided. - * - * - * @return (callback): uint8: No description available. - */ - inline uint8_t CallFuncUInt8Callback(FuncUInt8 func) { - using CallFuncUInt8CallbackFn = uint8_t (*)(FuncUInt8); - static CallFuncUInt8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt8Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt16Callback - * @param func (function): No description available. - * - * @return uint16: No description available. - * - * @callback FuncUInt16 - * @brief No description provided. - * - * - * @return (callback): uint16: No description available. - */ - inline uint16_t CallFuncUInt16Callback(FuncUInt16 func) { - using CallFuncUInt16CallbackFn = uint16_t (*)(FuncUInt16); - static CallFuncUInt16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt16Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt32Callback - * @param func (function): No description available. - * - * @return uint32: No description available. - * - * @callback FuncUInt32 - * @brief No description provided. - * - * - * @return (callback): uint32: No description available. - */ - inline uint32_t CallFuncUInt32Callback(FuncUInt32 func) { - using CallFuncUInt32CallbackFn = uint32_t (*)(FuncUInt32); - static CallFuncUInt32CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt32Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt64Callback - * @param func (function): No description available. - * - * @return uint64: No description available. - * - * @callback FuncUInt64 - * @brief No description provided. - * - * - * @return (callback): uint64: No description available. - */ - inline uint64_t CallFuncUInt64Callback(FuncUInt64 func) { - using CallFuncUInt64CallbackFn = uint64_t (*)(FuncUInt64); - static CallFuncUInt64CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt64Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncPtrCallback - * @param func (function): No description available. - * - * @return ptr64: No description available. - * - * @callback FuncPtr - * @brief No description provided. - * - * - * @return (callback): ptr64: No description available. - */ - inline void* CallFuncPtrCallback(FuncPtr func) { - using CallFuncPtrCallbackFn = void* (*)(FuncPtr); - static CallFuncPtrCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncPtrCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncFloatCallback - * @param func (function): No description available. - * - * @return float: No description available. - * - * @callback FuncFloat - * @brief No description provided. - * - * - * @return (callback): float: No description available. - */ - inline float CallFuncFloatCallback(FuncFloat func) { - using CallFuncFloatCallbackFn = float (*)(FuncFloat); - static CallFuncFloatCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncFloatCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncDoubleCallback - * @param func (function): No description available. - * - * @return double: No description available. - * - * @callback FuncDouble - * @brief No description provided. - * - * - * @return (callback): double: No description available. - */ - inline double CallFuncDoubleCallback(FuncDouble func) { - using CallFuncDoubleCallbackFn = double (*)(FuncDouble); - static CallFuncDoubleCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncDoubleCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncStringCallback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback FuncString - * @brief No description provided. - * - * - * @return (callback): string: No description available. - */ - inline plg::string CallFuncStringCallback(FuncString func) { - using CallFuncStringCallbackFn = plg::string (*)(FuncString); - static CallFuncStringCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncStringCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncAnyCallback - * @param func (function): No description available. - * - * @return any: No description available. - * - * @callback FuncAny - * @brief No description provided. - * - * - * @return (callback): any: No description available. - */ - inline plg::any CallFuncAnyCallback(FuncAny func) { - using CallFuncAnyCallbackFn = plg::any (*)(FuncAny); - static CallFuncAnyCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncAnyCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncFunctionCallback - * @param func (function): No description available. - * - * @return ptr64: No description available. - * - * @callback FuncFunction - * @brief No description provided. - * - * - * @return (callback): function: No description available. - */ - inline void* CallFuncFunctionCallback(FuncFunction func) { - using CallFuncFunctionCallbackFn = void* (*)(FuncFunction); - static CallFuncFunctionCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncFunctionCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncBoolVectorCallback - * @param func (function): No description available. - * - * @return bool[]: No description available. - * - * @callback FuncBoolVector - * @brief No description provided. - * - * - * @return (callback): bool[]: No description available. - */ - inline plg::vector CallFuncBoolVectorCallback(FuncBoolVector func) { - using CallFuncBoolVectorCallbackFn = plg::vector (*)(FuncBoolVector); - static CallFuncBoolVectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncBoolVectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncChar8VectorCallback - * @param func (function): No description available. - * - * @return char8[]: No description available. - * - * @callback FuncChar8Vector - * @brief No description provided. - * - * - * @return (callback): char8[]: No description available. - */ - inline plg::vector CallFuncChar8VectorCallback(FuncChar8Vector func) { - using CallFuncChar8VectorCallbackFn = plg::vector (*)(FuncChar8Vector); - static CallFuncChar8VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncChar8VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncChar16VectorCallback - * @param func (function): No description available. - * - * @return char16[]: No description available. - * - * @callback FuncChar16Vector - * @brief No description provided. - * - * - * @return (callback): char16[]: No description available. - */ - inline plg::vector CallFuncChar16VectorCallback(FuncChar16Vector func) { - using CallFuncChar16VectorCallbackFn = plg::vector (*)(FuncChar16Vector); - static CallFuncChar16VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncChar16VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt8VectorCallback - * @param func (function): No description available. - * - * @return int8[]: No description available. - * - * @callback FuncInt8Vector - * @brief No description provided. - * - * - * @return (callback): int8[]: No description available. - */ - inline plg::vector CallFuncInt8VectorCallback(FuncInt8Vector func) { - using CallFuncInt8VectorCallbackFn = plg::vector (*)(FuncInt8Vector); - static CallFuncInt8VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt8VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt16VectorCallback - * @param func (function): No description available. - * - * @return int16[]: No description available. - * - * @callback FuncInt16Vector - * @brief No description provided. - * - * - * @return (callback): int16[]: No description available. - */ - inline plg::vector CallFuncInt16VectorCallback(FuncInt16Vector func) { - using CallFuncInt16VectorCallbackFn = plg::vector (*)(FuncInt16Vector); - static CallFuncInt16VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt16VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt32VectorCallback - * @param func (function): No description available. - * - * @return int32[]: No description available. - * - * @callback FuncInt32Vector - * @brief No description provided. - * - * - * @return (callback): int32[]: No description available. - */ - inline plg::vector CallFuncInt32VectorCallback(FuncInt32Vector func) { - using CallFuncInt32VectorCallbackFn = plg::vector (*)(FuncInt32Vector); - static CallFuncInt32VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt32VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncInt64VectorCallback - * @param func (function): No description available. - * - * @return int64[]: No description available. - * - * @callback FuncInt64Vector - * @brief No description provided. - * - * - * @return (callback): int64[]: No description available. - */ - inline plg::vector CallFuncInt64VectorCallback(FuncInt64Vector func) { - using CallFuncInt64VectorCallbackFn = plg::vector (*)(FuncInt64Vector); - static CallFuncInt64VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt64VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt8VectorCallback - * @param func (function): No description available. - * - * @return uint8[]: No description available. - * - * @callback FuncUInt8Vector - * @brief No description provided. - * - * - * @return (callback): uint8[]: No description available. - */ - inline plg::vector CallFuncUInt8VectorCallback(FuncUInt8Vector func) { - using CallFuncUInt8VectorCallbackFn = plg::vector (*)(FuncUInt8Vector); - static CallFuncUInt8VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt8VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt16VectorCallback - * @param func (function): No description available. - * - * @return uint16[]: No description available. - * - * @callback FuncUInt16Vector - * @brief No description provided. - * - * - * @return (callback): uint16[]: No description available. - */ - inline plg::vector CallFuncUInt16VectorCallback(FuncUInt16Vector func) { - using CallFuncUInt16VectorCallbackFn = plg::vector (*)(FuncUInt16Vector); - static CallFuncUInt16VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt16VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt32VectorCallback - * @param func (function): No description available. - * - * @return uint32[]: No description available. - * - * @callback FuncUInt32Vector - * @brief No description provided. - * - * - * @return (callback): uint32[]: No description available. - */ - inline plg::vector CallFuncUInt32VectorCallback(FuncUInt32Vector func) { - using CallFuncUInt32VectorCallbackFn = plg::vector (*)(FuncUInt32Vector); - static CallFuncUInt32VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt32VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncUInt64VectorCallback - * @param func (function): No description available. - * - * @return uint64[]: No description available. - * - * @callback FuncUInt64Vector - * @brief No description provided. - * - * - * @return (callback): uint64[]: No description available. - */ - inline plg::vector CallFuncUInt64VectorCallback(FuncUInt64Vector func) { - using CallFuncUInt64VectorCallbackFn = plg::vector (*)(FuncUInt64Vector); - static CallFuncUInt64VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt64VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncPtrVectorCallback - * @param func (function): No description available. - * - * @return ptr64[]: No description available. - * - * @callback FuncPtrVector - * @brief No description provided. - * - * - * @return (callback): ptr64[]: No description available. - */ - inline plg::vector CallFuncPtrVectorCallback(FuncPtrVector func) { - using CallFuncPtrVectorCallbackFn = plg::vector (*)(FuncPtrVector); - static CallFuncPtrVectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncPtrVectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncFloatVectorCallback - * @param func (function): No description available. - * - * @return float[]: No description available. - * - * @callback FuncFloatVector - * @brief No description provided. - * - * - * @return (callback): float[]: No description available. - */ - inline plg::vector CallFuncFloatVectorCallback(FuncFloatVector func) { - using CallFuncFloatVectorCallbackFn = plg::vector (*)(FuncFloatVector); - static CallFuncFloatVectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncFloatVectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncDoubleVectorCallback - * @param func (function): No description available. - * - * @return double[]: No description available. - * - * @callback FuncDoubleVector - * @brief No description provided. - * - * - * @return (callback): double[]: No description available. - */ - inline plg::vector CallFuncDoubleVectorCallback(FuncDoubleVector func) { - using CallFuncDoubleVectorCallbackFn = plg::vector (*)(FuncDoubleVector); - static CallFuncDoubleVectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncDoubleVectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncStringVectorCallback - * @param func (function): No description available. - * - * @return string[]: No description available. - * - * @callback FuncStringVector - * @brief No description provided. - * - * - * @return (callback): string[]: No description available. - */ - inline plg::vector CallFuncStringVectorCallback(FuncStringVector func) { - using CallFuncStringVectorCallbackFn = plg::vector (*)(FuncStringVector); - static CallFuncStringVectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncStringVectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncAnyVectorCallback - * @param func (function): No description available. - * - * @return any[]: No description available. - * - * @callback FuncAnyVector - * @brief No description provided. - * - * - * @return (callback): any[]: No description available. - */ - inline plg::vector CallFuncAnyVectorCallback(FuncAnyVector func) { - using CallFuncAnyVectorCallbackFn = plg::vector (*)(FuncAnyVector); - static CallFuncAnyVectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncAnyVectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec2VectorCallback - * @param func (function): No description available. - * - * @return vec2[]: No description available. - * - * @callback FuncVec2Vector - * @brief No description provided. - * - * - * @return (callback): vec2[]: No description available. - */ - inline plg::vector CallFuncVec2VectorCallback(FuncVec2Vector func) { - using CallFuncVec2VectorCallbackFn = plg::vector (*)(FuncVec2Vector); - static CallFuncVec2VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec2VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec3VectorCallback - * @param func (function): No description available. - * - * @return vec3[]: No description available. - * - * @callback FuncVec3Vector - * @brief No description provided. - * - * - * @return (callback): vec3[]: No description available. - */ - inline plg::vector CallFuncVec3VectorCallback(FuncVec3Vector func) { - using CallFuncVec3VectorCallbackFn = plg::vector (*)(FuncVec3Vector); - static CallFuncVec3VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec3VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec4VectorCallback - * @param func (function): No description available. - * - * @return vec4[]: No description available. - * - * @callback FuncVec4Vector - * @brief No description provided. - * - * - * @return (callback): vec4[]: No description available. - */ - inline plg::vector CallFuncVec4VectorCallback(FuncVec4Vector func) { - using CallFuncVec4VectorCallbackFn = plg::vector (*)(FuncVec4Vector); - static CallFuncVec4VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec4VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncMat4x4VectorCallback - * @param func (function): No description available. - * - * @return mat4x4[]: No description available. - * - * @callback FuncMat4x4Vector - * @brief No description provided. - * - * - * @return (callback): mat4x4[]: No description available. - */ - inline plg::vector CallFuncMat4x4VectorCallback(FuncMat4x4Vector func) { - using CallFuncMat4x4VectorCallbackFn = plg::vector (*)(FuncMat4x4Vector); - static CallFuncMat4x4VectorCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncMat4x4VectorCallback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec2Callback - * @param func (function): No description available. - * - * @return vec2: No description available. - * - * @callback FuncVec2 - * @brief No description provided. - * - * - * @return (callback): vec2: No description available. - */ - inline plg::vec2 CallFuncVec2Callback(FuncVec2 func) { - using CallFuncVec2CallbackFn = plg::vec2 (*)(FuncVec2); - static CallFuncVec2CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec2Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec3Callback - * @param func (function): No description available. - * - * @return vec3: No description available. - * - * @callback FuncVec3 - * @brief No description provided. - * - * - * @return (callback): vec3: No description available. - */ - inline plg::vec3 CallFuncVec3Callback(FuncVec3 func) { - using CallFuncVec3CallbackFn = plg::vec3 (*)(FuncVec3); - static CallFuncVec3CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec3Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncVec4Callback - * @param func (function): No description available. - * - * @return vec4: No description available. - * - * @callback FuncVec4 - * @brief No description provided. - * - * - * @return (callback): vec4: No description available. - */ - inline plg::vec4 CallFuncVec4Callback(FuncVec4 func) { - using CallFuncVec4CallbackFn = plg::vec4 (*)(FuncVec4); - static CallFuncVec4CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec4Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncMat4x4Callback - * @param func (function): No description available. - * - * @return mat4x4: No description available. - * - * @callback FuncMat4x4 - * @brief No description provided. - * - * - * @return (callback): mat4x4: No description available. - */ - inline plg::mat4x4 CallFuncMat4x4Callback(FuncMat4x4 func) { - using CallFuncMat4x4CallbackFn = plg::mat4x4 (*)(FuncMat4x4); - static CallFuncMat4x4CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncMat4x4Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc1Callback - * @param func (function): No description available. - * - * @return int32: No description available. - * - * @callback Func1 - * @brief No description provided. - * - * @param a (vec3): No description available. - * - * @return (callback): int32: No description available. - */ - inline int32_t CallFunc1Callback(Func1 func) { - using CallFunc1CallbackFn = int32_t (*)(Func1); - static CallFunc1CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc1Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc2Callback - * @param func (function): No description available. - * - * @return char8: No description available. - * - * @callback Func2 - * @brief No description provided. - * - * @param a (float): No description available. - * @param b (int64): No description available. - * - * @return (callback): char8: No description available. - */ - inline char CallFunc2Callback(Func2 func) { - using CallFunc2CallbackFn = char (*)(Func2); - static CallFunc2CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc2Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc3Callback - * @param func (function): No description available. - * - * @callback Func3 - * @brief No description provided. - * - * @param a (ptr64): No description available. - * @param b (vec4): No description available. - * @param c (string): No description available. - * - * @return (callback): void: No description available. - */ - inline void CallFunc3Callback(Func3 func) { - using CallFunc3CallbackFn = void (*)(Func3); - static CallFunc3CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc3Callback", reinterpret_cast(&__func)); - __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc4Callback - * @param func (function): No description available. - * - * @return vec4: No description available. - * - * @callback Func4 - * @brief No description provided. - * - * @param a (bool): No description available. - * @param b (int32): No description available. - * @param c (char16): No description available. - * @param d (mat4x4): No description available. - * - * @return (callback): vec4: No description available. - */ - inline plg::vec4 CallFunc4Callback(Func4 func) { - using CallFunc4CallbackFn = plg::vec4 (*)(Func4); - static CallFunc4CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc4Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc5Callback - * @param func (function): No description available. - * - * @return bool: No description available. - * - * @callback Func5 - * @brief No description provided. - * - * @param a (int8): No description available. - * @param b (vec2): No description available. - * @param c (ptr64): No description available. - * @param d (double): No description available. - * @param e (uint64[]): No description available. - * - * @return (callback): bool: No description available. - */ - inline bool CallFunc5Callback(Func5 func) { - using CallFunc5CallbackFn = bool (*)(Func5); - static CallFunc5CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc5Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc6Callback - * @param func (function): No description available. - * - * @return int64: No description available. - * - * @callback Func6 - * @brief No description provided. - * - * @param a (string): No description available. - * @param b (float): No description available. - * @param c (float[]): No description available. - * @param d (int16): No description available. - * @param e (uint8[]): No description available. - * @param f (ptr64): No description available. - * - * @return (callback): int64: No description available. - */ - inline int64_t CallFunc6Callback(Func6 func) { - using CallFunc6CallbackFn = int64_t (*)(Func6); - static CallFunc6CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc6Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc7Callback - * @param func (function): No description available. - * - * @return double: No description available. - * - * @callback Func7 - * @brief No description provided. - * - * @param vecC (char8[]): No description available. - * @param u16 (uint16): No description available. - * @param ch16 (char16): No description available. - * @param vecU32 (uint32[]): No description available. - * @param vec4 (vec4): No description available. - * @param b (bool): No description available. - * @param u64 (uint64): No description available. - * - * @return (callback): double: No description available. - */ - inline double CallFunc7Callback(Func7 func) { - using CallFunc7CallbackFn = double (*)(Func7); - static CallFunc7CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc7Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc8Callback - * @param func (function): No description available. - * - * @return mat4x4: No description available. - * - * @callback Func8 - * @brief No description provided. - * - * @param vec3 (vec3): No description available. - * @param vecU32 (uint32[]): No description available. - * @param i16 (int16): No description available. - * @param b (bool): No description available. - * @param vec4 (vec4): No description available. - * @param vecC16 (char16[]): No description available. - * @param ch16 (char16): No description available. - * @param i32 (int32): No description available. - * - * @return (callback): mat4x4: No description available. - */ - inline plg::mat4x4 CallFunc8Callback(Func8 func) { - using CallFunc8CallbackFn = plg::mat4x4 (*)(Func8); - static CallFunc8CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc8Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc9Callback - * @param func (function): No description available. - * - * @callback Func9 - * @brief No description provided. - * - * @param f (float): No description available. - * @param vec2 (vec2): No description available. - * @param vecI8 (int8[]): No description available. - * @param u64 (uint64): No description available. - * @param b (bool): No description available. - * @param str (string): No description available. - * @param vec4 (vec4): No description available. - * @param i16 (int16): No description available. - * @param ptr (ptr64): No description available. - * - * @return (callback): void: No description available. - */ - inline void CallFunc9Callback(Func9 func) { - using CallFunc9CallbackFn = void (*)(Func9); - static CallFunc9CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc9Callback", reinterpret_cast(&__func)); - __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc10Callback - * @param func (function): No description available. - * - * @return uint32: No description available. - * - * @callback Func10 - * @brief No description provided. - * - * @param vec4 (vec4): No description available. - * @param mat (mat4x4): No description available. - * @param vecU32 (uint32[]): No description available. - * @param u64 (uint64): No description available. - * @param vecC (char8[]): No description available. - * @param i32 (int32): No description available. - * @param b (bool): No description available. - * @param vec2 (vec2): No description available. - * @param i64 (int64): No description available. - * @param d (double): No description available. - * - * @return (callback): uint32: No description available. - */ - inline uint32_t CallFunc10Callback(Func10 func) { - using CallFunc10CallbackFn = uint32_t (*)(Func10); - static CallFunc10CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc10Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc11Callback - * @param func (function): No description available. - * - * @return ptr64: No description available. - * - * @callback Func11 - * @brief No description provided. - * - * @param vecB (bool[]): No description available. - * @param ch16 (char16): No description available. - * @param u8 (uint8): No description available. - * @param d (double): No description available. - * @param vec3 (vec3): No description available. - * @param vecI8 (int8[]): No description available. - * @param i64 (int64): No description available. - * @param u16 (uint16): No description available. - * @param f (float): No description available. - * @param vec2 (vec2): No description available. - * @param u32 (uint32): No description available. - * - * @return (callback): ptr64: No description available. - */ - inline void* CallFunc11Callback(Func11 func) { - using CallFunc11CallbackFn = void* (*)(Func11); - static CallFunc11CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc11Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc12Callback - * @param func (function): No description available. - * - * @return bool: No description available. - * - * @callback Func12 - * @brief No description provided. - * - * @param ptr (ptr64): No description available. - * @param vecD (double[]): No description available. - * @param u32 (uint32): No description available. - * @param d (double): No description available. - * @param b (bool): No description available. - * @param i32 (int32): No description available. - * @param i8 (int8): No description available. - * @param u64 (uint64): No description available. - * @param f (float): No description available. - * @param vecPtr (ptr64[]): No description available. - * @param i64 (int64): No description available. - * @param ch (char8): No description available. - * - * @return (callback): bool: No description available. - */ - inline bool CallFunc12Callback(Func12 func) { - using CallFunc12CallbackFn = bool (*)(Func12); - static CallFunc12CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc12Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc13Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func13 - * @brief No description provided. - * - * @param i64 (int64): No description available. - * @param vecC (char8[]): No description available. - * @param d (uint16): No description available. - * @param f (float): No description available. - * @param b (bool[]): No description available. - * @param vec4 (vec4): No description available. - * @param str (string): No description available. - * @param int32 (int32): No description available. - * @param vec3 (vec3): No description available. - * @param ptr (ptr64): No description available. - * @param vec2 (vec2): No description available. - * @param arr (uint8[]): No description available. - * @param i16 (int16): No description available. - * - * @return (callback): string: No description available. - */ - inline plg::string CallFunc13Callback(Func13 func) { - using CallFunc13CallbackFn = plg::string (*)(Func13); - static CallFunc13CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc13Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc14Callback - * @param func (function): No description available. - * - * @return string[]: No description available. - * - * @callback Func14 - * @brief No description provided. - * - * @param vecC (char8[]): No description available. - * @param vecU32 (uint32[]): No description available. - * @param mat (mat4x4): No description available. - * @param b (bool): No description available. - * @param ch16 (char16): No description available. - * @param i32 (int32): No description available. - * @param vecF (float[]): No description available. - * @param u16 (uint16): No description available. - * @param vecU8 (uint8[]): No description available. - * @param i8 (int8): No description available. - * @param vec3 (vec3): No description available. - * @param vec4 (vec4): No description available. - * @param d (double): No description available. - * @param ptr (ptr64): No description available. - * - * @return (callback): string[]: No description available. - */ - inline plg::vector CallFunc14Callback(Func14 func) { - using CallFunc14CallbackFn = plg::vector (*)(Func14); - static CallFunc14CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc14Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc15Callback - * @param func (function): No description available. - * - * @return int16: No description available. - * - * @callback Func15 - * @brief No description provided. - * - * @param vecI16 (int16[]): No description available. - * @param mat (mat4x4): No description available. - * @param vec4 (vec4): No description available. - * @param ptr (ptr64): No description available. - * @param u64 (uint64): No description available. - * @param vecU32 (uint32[]): No description available. - * @param b (bool): No description available. - * @param f (float): No description available. - * @param vecC16 (char16[]): No description available. - * @param u8 (uint8): No description available. - * @param i32 (int32): No description available. - * @param vec2 (vec2): No description available. - * @param u16 (uint16): No description available. - * @param d (double): No description available. - * @param vecU8 (uint8[]): No description available. - * - * @return (callback): int16: No description available. - */ - inline int16_t CallFunc15Callback(Func15 func) { - using CallFunc15CallbackFn = int16_t (*)(Func15); - static CallFunc15CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc15Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc16Callback - * @param func (function): No description available. - * - * @return ptr64: No description available. - * - * @callback Func16 - * @brief No description provided. - * - * @param vecB (bool[]): No description available. - * @param i16 (int16): No description available. - * @param vecI8 (int8[]): No description available. - * @param vec4 (vec4): No description available. - * @param mat (mat4x4): No description available. - * @param vec2 (vec2): No description available. - * @param vecU64 (uint64[]): No description available. - * @param vecC (char8[]): No description available. - * @param str (string): No description available. - * @param i64 (int64): No description available. - * @param vecU32 (uint32[]): No description available. - * @param vec3 (vec3): No description available. - * @param f (float): No description available. - * @param d (double): No description available. - * @param i8 (int8): No description available. - * @param u16 (uint16): No description available. - * - * @return (callback): ptr64: No description available. - */ - inline void* CallFunc16Callback(Func16 func) { - using CallFunc16CallbackFn = void* (*)(Func16); - static CallFunc16CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc16Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc17Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func17 - * @brief No description provided. - * - * @param i32 (int32): No description available. - * - * @return (callback): void: No description available. - */ - inline plg::string CallFunc17Callback(Func17 func) { - using CallFunc17CallbackFn = plg::string (*)(Func17); - static CallFunc17CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc17Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc18Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func18 - * @brief No description provided. - * - * @param i8 (int8): No description available. - * @param i16 (int16): No description available. - * - * @return (callback): vec2: No description available. - */ - inline plg::string CallFunc18Callback(Func18 func) { - using CallFunc18CallbackFn = plg::string (*)(Func18); - static CallFunc18CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc18Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc19Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func19 - * @brief No description provided. - * - * @param u32 (uint32): No description available. - * @param vec3 (vec3): No description available. - * @param vecU32 (uint32[]): No description available. - * - * @return (callback): void: No description available. - */ - inline plg::string CallFunc19Callback(Func19 func) { - using CallFunc19CallbackFn = plg::string (*)(Func19); - static CallFunc19CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc19Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc20Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func20 - * @brief No description provided. - * - * @param ch16 (char16): No description available. - * @param vec4 (vec4): No description available. - * @param vecU64 (uint64[]): No description available. - * @param ch (char8): No description available. - * - * @return (callback): int32: No description available. - */ - inline plg::string CallFunc20Callback(Func20 func) { - using CallFunc20CallbackFn = plg::string (*)(Func20); - static CallFunc20CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc20Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc21Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func21 - * @brief No description provided. - * - * @param mat (mat4x4): No description available. - * @param vecI32 (int32[]): No description available. - * @param vec2 (vec2): No description available. - * @param b (bool): No description available. - * @param extraParam (double): No description available. - * - * @return (callback): float: No description available. - */ - inline plg::string CallFunc21Callback(Func21 func) { - using CallFunc21CallbackFn = plg::string (*)(Func21); - static CallFunc21CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc21Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc22Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func22 - * @brief No description provided. - * - * @param ptr64Ref (ptr64): No description available. - * @param uint32Ref (uint32): No description available. - * @param vectorDoubleRef (double[]): No description available. - * @param int16Ref (int16): No description available. - * @param plgStringRef (string): No description available. - * @param plgVector4Ref (vec4): No description available. - * - * @return (callback): uint64: No description available. - */ - inline plg::string CallFunc22Callback(Func22 func) { - using CallFunc22CallbackFn = plg::string (*)(Func22); - static CallFunc22CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc22Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc23Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func23 - * @brief No description provided. - * - * @param uint64Ref (uint64): No description available. - * @param plgVector2Ref (vec2): No description available. - * @param vectorInt16Ref (int16[]): No description available. - * @param char16Ref (char16): No description available. - * @param floatRef (float): No description available. - * @param int8Ref (int8): No description available. - * @param vectorUInt8Ref (uint8[]): No description available. - * - * @return (callback): void: No description available. - */ - inline plg::string CallFunc23Callback(Func23 func) { - using CallFunc23CallbackFn = plg::string (*)(Func23); - static CallFunc23CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc23Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc24Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func24 - * @brief No description provided. - * - * @param vectorCharRef (char8[]): No description available. - * @param int64Ref (int64): No description available. - * @param vectorUInt8Ref (uint8[]): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param uint64Ref (uint64): No description available. - * @param vectorptr64Ref (ptr64[]): No description available. - * @param doubleRef (double): No description available. - * @param vectorptr64Ref2 (ptr64[]): No description available. - * - * @return (callback): mat4x4: No description available. - */ - inline plg::string CallFunc24Callback(Func24 func) { - using CallFunc24CallbackFn = plg::string (*)(Func24); - static CallFunc24CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc24Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc25Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func25 - * @brief No description provided. - * - * @param int32Ref (int32): No description available. - * @param vectorptr64Ref (ptr64[]): No description available. - * @param boolRef (bool): No description available. - * @param uint8Ref (uint8): No description available. - * @param plgStringRef (string): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param int64Ref (int64): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param uint16Ref (uint16): No description available. - * - * @return (callback): double: No description available. - */ - inline plg::string CallFunc25Callback(Func25 func) { - using CallFunc25CallbackFn = plg::string (*)(Func25); - static CallFunc25CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc25Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc26Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func26 - * @brief No description provided. - * - * @param char16Ref (char16): No description available. - * @param plgVector2Ref (vec2): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param vectorFloatRef (float[]): No description available. - * @param int16Ref (int16): No description available. - * @param uint64Ref (uint64): No description available. - * @param uint32Ref (uint32): No description available. - * @param vectorUInt16Ref (uint16[]): No description available. - * @param ptr64Ref (ptr64): No description available. - * @param boolRef (bool): No description available. - * - * @return (callback): char8: No description available. - */ - inline plg::string CallFunc26Callback(Func26 func) { - using CallFunc26CallbackFn = plg::string (*)(Func26); - static CallFunc26CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc26Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc27Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func27 - * @brief No description provided. - * - * @param floatRef (float): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param ptr64Ref (ptr64): No description available. - * @param plgVector2Ref (vec2): No description available. - * @param vectorInt16Ref (int16[]): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param boolRef (bool): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param int8Ref (int8): No description available. - * @param int32Ref (int32): No description available. - * @param vectorUInt8Ref (uint8[]): No description available. - * - * @return (callback): uint8: No description available. - */ - inline plg::string CallFunc27Callback(Func27 func) { - using CallFunc27CallbackFn = plg::string (*)(Func27); - static CallFunc27CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc27Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc28Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func28 - * @brief No description provided. - * - * @param ptr64Ref (ptr64): No description available. - * @param uint16Ref (uint16): No description available. - * @param vectorUInt32Ref (uint32[]): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param floatRef (float): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param plgStringRef (string): No description available. - * @param vectorUInt64Ref (uint64[]): No description available. - * @param int64Ref (int64): No description available. - * @param boolRef (bool): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param vectorFloatRef (float[]): No description available. - * - * @return (callback): string: No description available. - */ - inline plg::string CallFunc28Callback(Func28 func) { - using CallFunc28CallbackFn = plg::string (*)(Func28); - static CallFunc28CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc28Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc29Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func29 - * @brief No description provided. - * - * @param plgVector4Ref (vec4): No description available. - * @param int32Ref (int32): No description available. - * @param vectorInt8Ref (int8[]): No description available. - * @param doubleRef (double): No description available. - * @param boolRef (bool): No description available. - * @param int8Ref (int8): No description available. - * @param vectorUInt16Ref (uint16[]): No description available. - * @param floatRef (float): No description available. - * @param plgStringRef (string): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param uint64Ref (uint64): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param vectorInt64Ref (int64[]): No description available. - * - * @return (callback): string[]: No description available. - */ - inline plg::string CallFunc29Callback(Func29 func) { - using CallFunc29CallbackFn = plg::string (*)(Func29); - static CallFunc29CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc29Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc30Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func30 - * @brief No description provided. - * - * @param ptr64Ref (ptr64): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param int64Ref (int64): No description available. - * @param vectorUInt32Ref (uint32[]): No description available. - * @param boolRef (bool): No description available. - * @param plgStringRef (string): No description available. - * @param plgVector3Ref (vec3): No description available. - * @param vectorUInt8Ref (uint8[]): No description available. - * @param floatRef (float): No description available. - * @param plgVector2Ref (vec2): No description available. - * @param plgMatrix4x4Ref (mat4x4): No description available. - * @param int8Ref (int8): No description available. - * @param vectorFloatRef (float[]): No description available. - * @param doubleRef (double): No description available. - * - * @return (callback): int32: No description available. - */ - inline plg::string CallFunc30Callback(Func30 func) { - using CallFunc30CallbackFn = plg::string (*)(Func30); - static CallFunc30CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc30Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc31Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func31 - * @brief No description provided. - * - * @param charRef (char8): No description available. - * @param uint32Ref (uint32): No description available. - * @param vectorUInt64Ref (uint64[]): No description available. - * @param plgVector4Ref (vec4): No description available. - * @param plgStringRef (string): No description available. - * @param boolRef (bool): No description available. - * @param int64Ref (int64): No description available. - * @param vec2Ref (vec2): No description available. - * @param int8Ref (int8): No description available. - * @param uint16Ref (uint16): No description available. - * @param vectorInt16Ref (int16[]): No description available. - * @param mat4x4Ref (mat4x4): No description available. - * @param vec3Ref (vec3): No description available. - * @param floatRef (float): No description available. - * @param vectorDoubleRef (double[]): No description available. - * - * @return (callback): vec3: No description available. - */ - inline plg::string CallFunc31Callback(Func31 func) { - using CallFunc31CallbackFn = plg::string (*)(Func31); - static CallFunc31CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc31Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc32Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func32 - * @brief No description provided. - * - * @param p1 (int32): No description available. - * @param p2 (uint16): No description available. - * @param p3 (int8[]): No description available. - * @param p4 (vec4): No description available. - * @param p5 (ptr64): No description available. - * @param p6 (uint32[]): No description available. - * @param p7 (mat4x4): No description available. - * @param p8 (uint64): No description available. - * @param p9 (string): No description available. - * @param p10 (int64): No description available. - * @param p11 (vec2): No description available. - * @param p12 (int8[]): No description available. - * @param p13 (bool): No description available. - * @param p14 (vec3): No description available. - * @param p15 (uint8): No description available. - * @param p16 (char16[]): No description available. - * - * @return (callback): double: No description available. - */ - inline plg::string CallFunc32Callback(Func32 func) { - using CallFunc32CallbackFn = plg::string (*)(Func32); - static CallFunc32CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc32Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFunc33Callback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback Func33 - * @brief No description provided. - * - * @param variant (any): No description available. - * - * @return (callback): void: No description available. - */ - inline plg::string CallFunc33Callback(Func33 func) { - using CallFunc33CallbackFn = plg::string (*)(Func33); - static CallFunc33CallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc33Callback", reinterpret_cast(&__func)); - return __func(func); - } - - /** - * @brief No description provided. - * - * @function CallFuncEnumCallback - * @param func (function): No description available. - * - * @return string: No description available. - * - * @callback FuncEnum - * @brief No description provided. - * - * @param p1 (int32): No description available. - * @param p2 (int32[]): No description available. - * - * @return (callback): int32[]: No description available. - */ - inline plg::string CallFuncEnumCallback(FuncEnum func) { - using CallFuncEnumCallbackFn = plg::string (*)(FuncEnum); - static CallFuncEnumCallbackFn __func = nullptr; - if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncEnumCallback", reinterpret_cast(&__func)); - return __func(func); - } - + enum class Example : int32_t { + First = 1, + Second = 2, + Third = 3, + Forth = 4, + }; + + using NoParamReturnFunctionCallbackFunc = int32_t (*)(); + using FuncVoid = void (*)(); + using FuncBool = bool (*)(); + using FuncChar8 = char (*)(); + using FuncChar16 = char16_t (*)(); + using FuncInt8 = int8_t (*)(); + using FuncInt16 = int16_t (*)(); + using FuncInt32 = int32_t (*)(); + using FuncInt64 = int64_t (*)(); + using FuncUInt8 = uint8_t (*)(); + using FuncUInt16 = uint16_t (*)(); + using FuncUInt32 = uint32_t (*)(); + using FuncUInt64 = uint64_t (*)(); + using FuncPtr = void* (*)(); + using FuncFloat = float (*)(); + using FuncDouble = double (*)(); + using FuncString = plg::string (*)(); + using FuncAny = plg::any (*)(); + using FuncFunction = void* (*)(); + using FuncBoolVector = plg::vector (*)(); + using FuncChar8Vector = plg::vector (*)(); + using FuncChar16Vector = plg::vector (*)(); + using FuncInt8Vector = plg::vector (*)(); + using FuncInt16Vector = plg::vector (*)(); + using FuncInt32Vector = plg::vector (*)(); + using FuncInt64Vector = plg::vector (*)(); + using FuncUInt8Vector = plg::vector (*)(); + using FuncUInt16Vector = plg::vector (*)(); + using FuncUInt32Vector = plg::vector (*)(); + using FuncUInt64Vector = plg::vector (*)(); + using FuncPtrVector = plg::vector (*)(); + using FuncFloatVector = plg::vector (*)(); + using FuncDoubleVector = plg::vector (*)(); + using FuncStringVector = plg::vector (*)(); + using FuncAnyVector = plg::vector (*)(); + using FuncVec2Vector = plg::vector (*)(); + using FuncVec3Vector = plg::vector (*)(); + using FuncVec4Vector = plg::vector (*)(); + using FuncMat4x4Vector = plg::vector (*)(); + using FuncVec2 = plg::vec2 (*)(); + using FuncVec3 = plg::vec3 (*)(); + using FuncVec4 = plg::vec4 (*)(); + using FuncMat4x4 = plg::mat4x4 (*)(); + using Func1 = int32_t (*)(const plg::vec3 &); + using Func2 = char (*)(float, int64_t); + using Func3 = void (*)(void *, const plg::vec4 &, const plg::string &); + using Func4 = plg::vec4 (*)(bool, int32_t, char16_t, const plg::mat4x4 &); + using Func5 = bool (*)(int8_t, const plg::vec2 &, void *, double, const plg::vector &); + using Func6 = int64_t (*)(const plg::string &, float, const plg::vector &, int16_t, + const plg::vector &, void *); + using Func7 = double (*)(const plg::vector &, uint16_t, char16_t, const plg::vector &, + const plg::vec4 &, bool, uint64_t); + using Func8 = plg::mat4x4 (*)(const plg::vec3 &, const plg::vector &, int16_t, bool, const plg::vec4 &, + const plg::vector &, char16_t, int32_t); + using Func9 = void (*)(float, const plg::vec2 &, const plg::vector &, uint64_t, bool, const plg::string &, + const plg::vec4 &, int16_t, void *); + using Func10 = uint32_t (*)(const plg::vec4 &, const plg::mat4x4 &, const plg::vector &, uint64_t, + const plg::vector &, int32_t, bool, const plg::vec2 &, int64_t, double); + using Func11 = void* (*)(const plg::vector &, char16_t, uint8_t, double, const plg::vec3 &, + const plg::vector &, int64_t, uint16_t, float, const plg::vec2 &, uint32_t); + using Func12 = bool (*)(void *, const plg::vector &, uint32_t, double, bool, int32_t, int8_t, uint64_t, + float, const plg::vector &, int64_t, char); + using Func13 = plg::string (*)(int64_t, const plg::vector &, uint16_t, float, const plg::vector &, + const plg::vec4 &, const plg::string &, int32_t, const plg::vec3 &, void *, + const plg::vec2 &, const plg::vector &, int16_t); + using Func14 = plg::vector (*)(const plg::vector &, const plg::vector &, + const plg::mat4x4 &, bool, char16_t, int32_t, + const plg::vector &, uint16_t, const plg::vector &, + int8_t, const plg::vec3 &, const plg::vec4 &, double, void *); + using Func15 = int16_t (*)(const plg::vector &, const plg::mat4x4 &, const plg::vec4 &, void *, uint64_t, + const plg::vector &, bool, float, const plg::vector &, uint8_t, + int32_t, const plg::vec2 &, uint16_t, double, const plg::vector &); + using Func16 = void* (*)(const plg::vector &, int16_t, const plg::vector &, const plg::vec4 &, + const plg::mat4x4 &, const plg::vec2 &, const plg::vector &, + const plg::vector &, const plg::string &, int64_t, const plg::vector &, + const plg::vec3 &, float, double, int8_t, uint16_t); + using Func17 = void (*)(int32_t &); + using Func18 = plg::vec2 (*)(int8_t &, int16_t &); + using Func19 = void (*)(uint32_t &, plg::vec3 &, plg::vector &); + using Func20 = int32_t (*)(char16_t &, plg::vec4 &, plg::vector &, char &); + using Func21 = float (*)(plg::mat4x4 &, plg::vector &, plg::vec2 &, bool &, double &); + using Func22 = uint64_t (*)(void *&, uint32_t &, plg::vector &, int16_t &, plg::string &, plg::vec4 &); + using Func23 = void (*)(uint64_t &, plg::vec2 &, plg::vector &, char16_t &, float &, int8_t &, + plg::vector &); + using Func24 = plg::mat4x4 (*)(plg::vector &, int64_t &, plg::vector &, plg::vec4 &, uint64_t &, + plg::vector &, double &, plg::vector &); + using Func25 = double (*)(int32_t &, plg::vector &, bool &, uint8_t &, plg::string &, plg::vec3 &, + int64_t &, plg::vec4 &, uint16_t &); + using Func26 = char (*)(char16_t &, plg::vec2 &, plg::mat4x4 &, plg::vector &, int16_t &, uint64_t &, + uint32_t &, plg::vector &, void *&, bool &); + using Func27 = uint8_t (*)(float &, plg::vec3 &, void *&, plg::vec2 &, plg::vector &, plg::mat4x4 &, + bool &, plg::vec4 &, int8_t &, int32_t &, plg::vector &); + using Func28 = plg::string (*)(void *&, uint16_t &, plg::vector &, plg::mat4x4 &, float &, plg::vec4 &, + plg::string &, plg::vector &, int64_t &, bool &, plg::vec3 &, + plg::vector &); + using Func29 = plg::vector (*)(plg::vec4 &, int32_t &, plg::vector &, double &, bool &, + int8_t &, plg::vector &, float &, plg::string &, + plg::mat4x4 &, uint64_t &, plg::vec3 &, plg::vector &); + using Func30 = int32_t (*)(void *&, plg::vec4 &, int64_t &, plg::vector &, bool &, plg::string &, + plg::vec3 &, plg::vector &, float &, plg::vec2 &, plg::mat4x4 &, int8_t &, + plg::vector &, double &); + using Func31 = plg::vec3 (*)(char &, uint32_t &, plg::vector &, plg::vec4 &, plg::string &, bool &, + int64_t &, plg::vec2 &, int8_t &, uint16_t &, plg::vector &, plg::mat4x4 &, + plg::vec3 &, float &, plg::vector &); + using Func32 = double (*)(int32_t &, uint16_t &, plg::vector &, plg::vec4 &, void *&, + plg::vector &, plg::mat4x4 &, uint64_t &, plg::string &, int64_t &, plg::vec2 &, + plg::vector &, bool &, plg::vec3 &, uint8_t &, plg::vector &); + using Func33 = void (*)(plg::any &); + using FuncEnum = plg::vector (*)(Example, plg::vector &); + + /** + * @brief No description provided. + * + * @function ReverseReturn + * @param returnString (string): No description available. + */ + inline void ReverseReturn(const plg::string &returnString) { + using ReverseReturnFn = void (*)(const plg::string &); + static ReverseReturnFn __func = nullptr; + if (__func == nullptr) + plg::GetMethodPtr2("cross_call_master.ReverseReturn", reinterpret_cast(&__func)); + __func(returnString); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnVoidCallback + */ + inline void NoParamReturnVoidCallback() { + using NoParamReturnVoidCallbackFn = void (*)(); + static NoParamReturnVoidCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnVoidCallback", + reinterpret_cast(&__func)); + __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnBoolCallback + * + * @return bool: No description available. + */ + inline bool NoParamReturnBoolCallback() { + using NoParamReturnBoolCallbackFn = bool (*)(); + static NoParamReturnBoolCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnBoolCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnChar8Callback + * + * @return char8: No description available. + */ + inline char NoParamReturnChar8Callback() { + using NoParamReturnChar8CallbackFn = char (*)(); + static NoParamReturnChar8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnChar8Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnChar16Callback + * + * @return char16: No description available. + */ + inline char16_t NoParamReturnChar16Callback() { + using NoParamReturnChar16CallbackFn = char16_t (*)(); + static NoParamReturnChar16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnChar16Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnInt8Callback + * + * @return int8: No description available. + */ + inline int8_t NoParamReturnInt8Callback() { + using NoParamReturnInt8CallbackFn = int8_t (*)(); + static NoParamReturnInt8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnInt8Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnInt16Callback + * + * @return int16: No description available. + */ + inline int16_t NoParamReturnInt16Callback() { + using NoParamReturnInt16CallbackFn = int16_t (*)(); + static NoParamReturnInt16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnInt16Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnInt32Callback + * + * @return int32: No description available. + */ + inline int32_t NoParamReturnInt32Callback() { + using NoParamReturnInt32CallbackFn = int32_t (*)(); + static NoParamReturnInt32CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnInt32Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnInt64Callback + * + * @return int64: No description available. + */ + inline int64_t NoParamReturnInt64Callback() { + using NoParamReturnInt64CallbackFn = int64_t (*)(); + static NoParamReturnInt64CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnInt64Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnUInt8Callback + * + * @return uint8: No description available. + */ + inline uint8_t NoParamReturnUInt8Callback() { + using NoParamReturnUInt8CallbackFn = uint8_t (*)(); + static NoParamReturnUInt8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnUInt8Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnUInt16Callback + * + * @return uint16: No description available. + */ + inline uint16_t NoParamReturnUInt16Callback() { + using NoParamReturnUInt16CallbackFn = uint16_t (*)(); + static NoParamReturnUInt16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnUInt16Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnUInt32Callback + * + * @return uint32: No description available. + */ + inline uint32_t NoParamReturnUInt32Callback() { + using NoParamReturnUInt32CallbackFn = uint32_t (*)(); + static NoParamReturnUInt32CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnUInt32Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnUInt64Callback + * + * @return uint64: No description available. + */ + inline uint64_t NoParamReturnUInt64Callback() { + using NoParamReturnUInt64CallbackFn = uint64_t (*)(); + static NoParamReturnUInt64CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnUInt64Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnPointerCallback + * + * @return ptr64: No description available. + */ + inline void *NoParamReturnPointerCallback() { + using NoParamReturnPointerCallbackFn = void* (*)(); + static NoParamReturnPointerCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnPointerCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnFloatCallback + * + * @return float: No description available. + */ + inline float NoParamReturnFloatCallback() { + using NoParamReturnFloatCallbackFn = float (*)(); + static NoParamReturnFloatCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnFloatCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnDoubleCallback + * + * @return double: No description available. + */ + inline double NoParamReturnDoubleCallback() { + using NoParamReturnDoubleCallbackFn = double (*)(); + static NoParamReturnDoubleCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnDoubleCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnFunctionCallback + * + * @return function: No description available. + */ + inline NoParamReturnFunctionCallbackFunc NoParamReturnFunctionCallback() { + using NoParamReturnFunctionCallbackFn = NoParamReturnFunctionCallbackFunc (*)(); + static NoParamReturnFunctionCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnFunctionCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnStringCallback + * + * @return string: No description available. + */ + inline plg::string NoParamReturnStringCallback() { + using NoParamReturnStringCallbackFn = plg::string (*)(); + static NoParamReturnStringCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnStringCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnAnyCallback + * + * @return any: No description available. + */ + inline plg::any NoParamReturnAnyCallback() { + using NoParamReturnAnyCallbackFn = plg::any (*)(); + static NoParamReturnAnyCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnAnyCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayBoolCallback + * + * @return bool[]: No description available. + */ + inline plg::vector NoParamReturnArrayBoolCallback() { + using NoParamReturnArrayBoolCallbackFn = plg::vector (*)(); + static NoParamReturnArrayBoolCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayBoolCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayChar8Callback + * + * @return char8[]: No description available. + */ + inline plg::vector NoParamReturnArrayChar8Callback() { + using NoParamReturnArrayChar8CallbackFn = plg::vector (*)(); + static NoParamReturnArrayChar8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayChar8Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayChar16Callback + * + * @return char16[]: No description available. + */ + inline plg::vector NoParamReturnArrayChar16Callback() { + using NoParamReturnArrayChar16CallbackFn = plg::vector (*)(); + static NoParamReturnArrayChar16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayChar16Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayInt8Callback + * + * @return int8[]: No description available. + */ + inline plg::vector NoParamReturnArrayInt8Callback() { + using NoParamReturnArrayInt8CallbackFn = plg::vector (*)(); + static NoParamReturnArrayInt8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayInt8Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayInt16Callback + * + * @return int16[]: No description available. + */ + inline plg::vector NoParamReturnArrayInt16Callback() { + using NoParamReturnArrayInt16CallbackFn = plg::vector (*)(); + static NoParamReturnArrayInt16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayInt16Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayInt32Callback + * + * @return int32[]: No description available. + */ + inline plg::vector NoParamReturnArrayInt32Callback() { + using NoParamReturnArrayInt32CallbackFn = plg::vector (*)(); + static NoParamReturnArrayInt32CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayInt32Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayInt64Callback + * + * @return int64[]: No description available. + */ + inline plg::vector NoParamReturnArrayInt64Callback() { + using NoParamReturnArrayInt64CallbackFn = plg::vector (*)(); + static NoParamReturnArrayInt64CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayInt64Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayUInt8Callback + * + * @return uint8[]: No description available. + */ + inline plg::vector NoParamReturnArrayUInt8Callback() { + using NoParamReturnArrayUInt8CallbackFn = plg::vector (*)(); + static NoParamReturnArrayUInt8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayUInt8Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayUInt16Callback + * + * @return uint16[]: No description available. + */ + inline plg::vector NoParamReturnArrayUInt16Callback() { + using NoParamReturnArrayUInt16CallbackFn = plg::vector (*)(); + static NoParamReturnArrayUInt16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayUInt16Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayUInt32Callback + * + * @return uint32[]: No description available. + */ + inline plg::vector NoParamReturnArrayUInt32Callback() { + using NoParamReturnArrayUInt32CallbackFn = plg::vector (*)(); + static NoParamReturnArrayUInt32CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayUInt32Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayUInt64Callback + * + * @return uint64[]: No description available. + */ + inline plg::vector NoParamReturnArrayUInt64Callback() { + using NoParamReturnArrayUInt64CallbackFn = plg::vector (*)(); + static NoParamReturnArrayUInt64CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayUInt64Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayPointerCallback + * + * @return ptr64[]: No description available. + */ + inline plg::vector NoParamReturnArrayPointerCallback() { + using NoParamReturnArrayPointerCallbackFn = plg::vector (*)(); + static NoParamReturnArrayPointerCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayPointerCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayFloatCallback + * + * @return float[]: No description available. + */ + inline plg::vector NoParamReturnArrayFloatCallback() { + using NoParamReturnArrayFloatCallbackFn = plg::vector (*)(); + static NoParamReturnArrayFloatCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayFloatCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayDoubleCallback + * + * @return double[]: No description available. + */ + inline plg::vector NoParamReturnArrayDoubleCallback() { + using NoParamReturnArrayDoubleCallbackFn = plg::vector (*)(); + static NoParamReturnArrayDoubleCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayDoubleCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayStringCallback + * + * @return string[]: No description available. + */ + inline plg::vector NoParamReturnArrayStringCallback() { + using NoParamReturnArrayStringCallbackFn = plg::vector (*)(); + static NoParamReturnArrayStringCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayStringCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayAnyCallback + * + * @return any[]: No description available. + */ + inline plg::vector NoParamReturnArrayAnyCallback() { + using NoParamReturnArrayAnyCallbackFn = plg::vector (*)(); + static NoParamReturnArrayAnyCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayAnyCallback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayVector2Callback + * + * @return vec2[]: No description available. + */ + inline plg::vector NoParamReturnArrayVector2Callback() { + using NoParamReturnArrayVector2CallbackFn = plg::vector (*)(); + static NoParamReturnArrayVector2CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayVector2Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayVector3Callback + * + * @return vec3[]: No description available. + */ + inline plg::vector NoParamReturnArrayVector3Callback() { + using NoParamReturnArrayVector3CallbackFn = plg::vector (*)(); + static NoParamReturnArrayVector3CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayVector3Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayVector4Callback + * + * @return vec4[]: No description available. + */ + inline plg::vector NoParamReturnArrayVector4Callback() { + using NoParamReturnArrayVector4CallbackFn = plg::vector (*)(); + static NoParamReturnArrayVector4CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayVector4Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnArrayMatrix4x4Callback + * + * @return mat4x4[]: No description available. + */ + inline plg::vector NoParamReturnArrayMatrix4x4Callback() { + using NoParamReturnArrayMatrix4x4CallbackFn = plg::vector (*)(); + static NoParamReturnArrayMatrix4x4CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnArrayMatrix4x4Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnVector2Callback + * + * @return vec2: No description available. + */ + inline plg::vec2 NoParamReturnVector2Callback() { + using NoParamReturnVector2CallbackFn = plg::vec2 (*)(); + static NoParamReturnVector2CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnVector2Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnVector3Callback + * + * @return vec3: No description available. + */ + inline plg::vec3 NoParamReturnVector3Callback() { + using NoParamReturnVector3CallbackFn = plg::vec3 (*)(); + static NoParamReturnVector3CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnVector3Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnVector4Callback + * + * @return vec4: No description available. + */ + inline plg::vec4 NoParamReturnVector4Callback() { + using NoParamReturnVector4CallbackFn = plg::vec4 (*)(); + static NoParamReturnVector4CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnVector4Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function NoParamReturnMatrix4x4Callback + * + * @return mat4x4: No description available. + */ + inline plg::mat4x4 NoParamReturnMatrix4x4Callback() { + using NoParamReturnMatrix4x4CallbackFn = plg::mat4x4 (*)(); + static NoParamReturnMatrix4x4CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.NoParamReturnMatrix4x4Callback", + reinterpret_cast(&__func)); + return __func(); + } + + /** + * @brief No description provided. + * + * @function Param1Callback + * @param a (int32): No description available. + */ + inline void Param1Callback(int32_t a) { + using Param1CallbackFn = void (*)(int32_t); + static Param1CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param1Callback", + reinterpret_cast(&__func)); + __func(a); + } + + /** + * @brief No description provided. + * + * @function Param2Callback + * @param a (int32): No description available. + * @param b (float): No description available. + */ + inline void Param2Callback(int32_t a, float b) { + using Param2CallbackFn = void (*)(int32_t, float); + static Param2CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param2Callback", + reinterpret_cast(&__func)); + __func(a, b); + } + + /** + * @brief No description provided. + * + * @function Param3Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + */ + inline void Param3Callback(int32_t a, float b, double c) { + using Param3CallbackFn = void (*)(int32_t, float, double); + static Param3CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param3Callback", + reinterpret_cast(&__func)); + __func(a, b, c); + } + + /** + * @brief No description provided. + * + * @function Param4Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + */ + inline void Param4Callback(int32_t a, float b, double c, const plg::vec4 &d) { + using Param4CallbackFn = void (*)(int32_t, float, double, const plg::vec4 &); + static Param4CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param4Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d); + } + + /** + * @brief No description provided. + * + * @function Param5Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + */ + inline void Param5Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e) { + using Param5CallbackFn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &); + static Param5CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param5Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e); + } + + /** + * @brief No description provided. + * + * @function Param6Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + */ + inline void Param6Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, + char f) { + using Param6CallbackFn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, + char); + static Param6CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param6Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f); + } + + /** + * @brief No description provided. + * + * @function Param7Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + */ + inline void Param7Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g) { + using Param7CallbackFn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, char, + const plg::string &); + static Param7CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param7Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g); + } + + /** + * @brief No description provided. + * + * @function Param8Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + */ + inline void Param8Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h) { + using Param8CallbackFn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, char, + const plg::string &, char16_t); + static Param8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param8Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h); + } + + /** + * @brief No description provided. + * + * @function Param9Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + * @param k (int16): No description available. + */ + inline void Param9Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h, int16_t k) { + using Param9CallbackFn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, char, + const plg::string &, char16_t, int16_t); + static Param9CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param9Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h, k); + } + + /** + * @brief No description provided. + * + * @function Param10Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + * @param k (int16): No description available. + * @param l (ptr64): No description available. + */ + inline void Param10Callback(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h, int16_t k, void *l) { + using Param10CallbackFn = void (*)(int32_t, float, double, const plg::vec4 &, const plg::vector &, + char, const plg::string &, char16_t, int16_t, void *); + static Param10CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.Param10Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h, k, l); + } + + /** + * @brief No description provided. + * + * @function ParamRef1Callback + * @param a (int32): No description available. + */ + inline void ParamRef1Callback(int32_t &a) { + using ParamRef1CallbackFn = void (*)(int32_t &); + static ParamRef1CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef1Callback", + reinterpret_cast(&__func)); + __func(a); + } + + /** + * @brief No description provided. + * + * @function ParamRef2Callback + * @param a (int32): No description available. + * @param b (float): No description available. + */ + inline void ParamRef2Callback(int32_t &a, float &b) { + using ParamRef2CallbackFn = void (*)(int32_t &, float &); + static ParamRef2CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef2Callback", + reinterpret_cast(&__func)); + __func(a, b); + } + + /** + * @brief No description provided. + * + * @function ParamRef3Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + */ + inline void ParamRef3Callback(int32_t &a, float &b, double &c) { + using ParamRef3CallbackFn = void (*)(int32_t &, float &, double &); + static ParamRef3CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef3Callback", + reinterpret_cast(&__func)); + __func(a, b, c); + } + + /** + * @brief No description provided. + * + * @function ParamRef4Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + */ + inline void ParamRef4Callback(int32_t &a, float &b, double &c, plg::vec4 &d) { + using ParamRef4CallbackFn = void (*)(int32_t &, float &, double &, plg::vec4 &); + static ParamRef4CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef4Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d); + } + + /** + * @brief No description provided. + * + * @function ParamRef5Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + */ + inline void ParamRef5Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e) { + using ParamRef5CallbackFn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &); + static ParamRef5CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef5Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e); + } + + /** + * @brief No description provided. + * + * @function ParamRef6Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + */ + inline void ParamRef6Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f) { + using ParamRef6CallbackFn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &); + static ParamRef6CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef6Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f); + } + + /** + * @brief No description provided. + * + * @function ParamRef7Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + */ + inline void ParamRef7Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g) { + using ParamRef7CallbackFn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &, + plg::string &); + static ParamRef7CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef7Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g); + } + + /** + * @brief No description provided. + * + * @function ParamRef8Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + */ + inline void ParamRef8Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h) { + using ParamRef8CallbackFn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &, + plg::string &, char16_t &); + static ParamRef8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef8Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h); + } + + /** + * @brief No description provided. + * + * @function ParamRef9Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + * @param k (int16): No description available. + */ + inline void ParamRef9Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h, int16_t &k) { + using ParamRef9CallbackFn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &, + plg::string &, char16_t &, int16_t &); + static ParamRef9CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef9Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h, k); + } + + /** + * @brief No description provided. + * + * @function ParamRef10Callback + * @param a (int32): No description available. + * @param b (float): No description available. + * @param c (double): No description available. + * @param d (vec4): No description available. + * @param e (int64[]): No description available. + * @param f (char8): No description available. + * @param g (string): No description available. + * @param h (char16): No description available. + * @param k (int16): No description available. + * @param l (ptr64): No description available. + */ + inline void ParamRef10Callback(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h, int16_t &k, void *&l) { + using ParamRef10CallbackFn = void (*)(int32_t &, float &, double &, plg::vec4 &, plg::vector &, char &, + plg::string &, char16_t &, int16_t &, void *&); + static ParamRef10CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRef10Callback", + reinterpret_cast(&__func)); + __func(a, b, c, d, e, f, g, h, k, l); + } + + /** + * @brief No description provided. + * + * @function ParamRefVectorsCallback + * @param p1 (bool[]): No description available. + * @param p2 (char8[]): No description available. + * @param p3 (char16[]): No description available. + * @param p4 (int8[]): No description available. + * @param p5 (int16[]): No description available. + * @param p6 (int32[]): No description available. + * @param p7 (int64[]): No description available. + * @param p8 (uint8[]): No description available. + * @param p9 (uint16[]): No description available. + * @param p10 (uint32[]): No description available. + * @param p11 (uint64[]): No description available. + * @param p12 (ptr64[]): No description available. + * @param p13 (float[]): No description available. + * @param p14 (double[]): No description available. + * @param p15 (string[]): No description available. + */ + inline void ParamRefVectorsCallback(plg::vector &p1, plg::vector &p2, plg::vector &p3, + plg::vector &p4, plg::vector &p5, plg::vector &p6, + plg::vector &p7, plg::vector &p8, plg::vector &p9, + plg::vector &p10, plg::vector &p11, + plg::vector &p12, plg::vector &p13, plg::vector &p14, + plg::vector &p15) { + using ParamRefVectorsCallbackFn = void (*)(plg::vector &, plg::vector &, plg::vector &, + plg::vector &, plg::vector &, + plg::vector &, plg::vector &, + plg::vector &, plg::vector &, + plg::vector &, plg::vector &, + plg::vector &, plg::vector &, plg::vector &, + plg::vector &); + static ParamRefVectorsCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamRefVectorsCallback", + reinterpret_cast(&__func)); + __func(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); + } + + /** + * @brief No description provided. + * + * @function ParamAllPrimitivesCallback + * @param p1 (bool): No description available. + * @param p2 (char8): No description available. + * @param p3 (char16): No description available. + * @param p4 (int8): No description available. + * @param p5 (int16): No description available. + * @param p6 (int32): No description available. + * @param p7 (int64): No description available. + * @param p8 (uint8): No description available. + * @param p9 (uint16): No description available. + * @param p10 (uint32): No description available. + * @param p11 (uint64): No description available. + * @param p12 (ptr64): No description available. + * @param p13 (float): No description available. + * @param p14 (double): No description available. + * + * @return int64: No description available. + */ + inline int64_t ParamAllPrimitivesCallback(bool p1, char p2, char16_t p3, int8_t p4, int16_t p5, int32_t p6, + int64_t p7, uint8_t p8, uint16_t p9, uint32_t p10, uint64_t p11, + void *p12, float p13, double p14) { + using ParamAllPrimitivesCallbackFn = int64_t (*)(bool, char, char16_t, int8_t, int16_t, int32_t, int64_t, + uint8_t, uint16_t, uint32_t, uint64_t, void *, float, double); + static ParamAllPrimitivesCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamAllPrimitivesCallback", + reinterpret_cast(&__func)); + return __func(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); + } + + /** + * @brief No description provided. + * + * @function ParamEnumCallback + * @param p1 (int32): No description available. + * @param p2 (int32[]): No description available. + * + * @return int32: No description available. + */ + inline int32_t ParamEnumCallback(Example p1, const plg::vector &p2) { + using ParamEnumCallbackFn = int32_t (*)(Example, const plg::vector &); + static ParamEnumCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamEnumCallback", + reinterpret_cast(&__func)); + return __func(p1, p2); + } + + /** + * @brief No description provided. + * + * @function ParamEnumRefCallback + * @param p1 (int32): No description available. + * @param p2 (int32[]): No description available. + * + * @return int32: No description available. + */ + inline int32_t ParamEnumRefCallback(Example &p1, plg::vector &p2) { + using ParamEnumRefCallbackFn = int32_t (*)(Example &, plg::vector &); + static ParamEnumRefCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamEnumRefCallback", + reinterpret_cast(&__func)); + return __func(p1, p2); + } + + /** + * @brief No description provided. + * + * @function ParamVariantCallback + * @param p1 (any): No description available. + * @param p2 (any[]): No description available. + */ + inline void ParamVariantCallback(const plg::any &p1, const plg::vector &p2) { + using ParamVariantCallbackFn = void (*)(const plg::any &, const plg::vector &); + static ParamVariantCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamVariantCallback", + reinterpret_cast(&__func)); + __func(p1, p2); + } + + /** + * @brief No description provided. + * + * @function ParamVariantRefCallback + * @param p1 (any): No description available. + * @param p2 (any[]): No description available. + */ + inline void ParamVariantRefCallback(plg::any &p1, plg::vector &p2) { + using ParamVariantRefCallbackFn = void (*)(plg::any &, plg::vector &); + static ParamVariantRefCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.ParamVariantRefCallback", + reinterpret_cast(&__func)); + __func(p1, p2); + } + + /** + * @brief No description provided. + * + * @function CallFuncVoidCallback + * @param func (function): No description available. + * + * @callback FuncVoid + * @brief No description provided. + * + * + * @return (callback): void: No description available. + */ + inline void CallFuncVoidCallback(FuncVoid func) { + using CallFuncVoidCallbackFn = void (*)(FuncVoid); + static CallFuncVoidCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVoidCallback", + reinterpret_cast(&__func)); + __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncBoolCallback + * @param func (function): No description available. + * + * @return bool: No description available. + * + * @callback FuncBool + * @brief No description provided. + * + * + * @return (callback): bool: No description available. + */ + inline bool CallFuncBoolCallback(FuncBool func) { + using CallFuncBoolCallbackFn = bool (*)(FuncBool); + static CallFuncBoolCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncBoolCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncChar8Callback + * @param func (function): No description available. + * + * @return char8: No description available. + * + * @callback FuncChar8 + * @brief No description provided. + * + * + * @return (callback): char8: No description available. + */ + inline char CallFuncChar8Callback(FuncChar8 func) { + using CallFuncChar8CallbackFn = char (*)(FuncChar8); + static CallFuncChar8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncChar8Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncChar16Callback + * @param func (function): No description available. + * + * @return char16: No description available. + * + * @callback FuncChar16 + * @brief No description provided. + * + * + * @return (callback): char16: No description available. + */ + inline char16_t CallFuncChar16Callback(FuncChar16 func) { + using CallFuncChar16CallbackFn = char16_t (*)(FuncChar16); + static CallFuncChar16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncChar16Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt8Callback + * @param func (function): No description available. + * + * @return int8: No description available. + * + * @callback FuncInt8 + * @brief No description provided. + * + * + * @return (callback): int8: No description available. + */ + inline int8_t CallFuncInt8Callback(FuncInt8 func) { + using CallFuncInt8CallbackFn = int8_t (*)(FuncInt8); + static CallFuncInt8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt8Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt16Callback + * @param func (function): No description available. + * + * @return int16: No description available. + * + * @callback FuncInt16 + * @brief No description provided. + * + * + * @return (callback): int16: No description available. + */ + inline int16_t CallFuncInt16Callback(FuncInt16 func) { + using CallFuncInt16CallbackFn = int16_t (*)(FuncInt16); + static CallFuncInt16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt16Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt32Callback + * @param func (function): No description available. + * + * @return int32: No description available. + * + * @callback FuncInt32 + * @brief No description provided. + * + * + * @return (callback): int32: No description available. + */ + inline int32_t CallFuncInt32Callback(FuncInt32 func) { + using CallFuncInt32CallbackFn = int32_t (*)(FuncInt32); + static CallFuncInt32CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt32Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt64Callback + * @param func (function): No description available. + * + * @return int64: No description available. + * + * @callback FuncInt64 + * @brief No description provided. + * + * + * @return (callback): int64: No description available. + */ + inline int64_t CallFuncInt64Callback(FuncInt64 func) { + using CallFuncInt64CallbackFn = int64_t (*)(FuncInt64); + static CallFuncInt64CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt64Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt8Callback + * @param func (function): No description available. + * + * @return uint8: No description available. + * + * @callback FuncUInt8 + * @brief No description provided. + * + * + * @return (callback): uint8: No description available. + */ + inline uint8_t CallFuncUInt8Callback(FuncUInt8 func) { + using CallFuncUInt8CallbackFn = uint8_t (*)(FuncUInt8); + static CallFuncUInt8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt8Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt16Callback + * @param func (function): No description available. + * + * @return uint16: No description available. + * + * @callback FuncUInt16 + * @brief No description provided. + * + * + * @return (callback): uint16: No description available. + */ + inline uint16_t CallFuncUInt16Callback(FuncUInt16 func) { + using CallFuncUInt16CallbackFn = uint16_t (*)(FuncUInt16); + static CallFuncUInt16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt16Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt32Callback + * @param func (function): No description available. + * + * @return uint32: No description available. + * + * @callback FuncUInt32 + * @brief No description provided. + * + * + * @return (callback): uint32: No description available. + */ + inline uint32_t CallFuncUInt32Callback(FuncUInt32 func) { + using CallFuncUInt32CallbackFn = uint32_t (*)(FuncUInt32); + static CallFuncUInt32CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt32Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt64Callback + * @param func (function): No description available. + * + * @return uint64: No description available. + * + * @callback FuncUInt64 + * @brief No description provided. + * + * + * @return (callback): uint64: No description available. + */ + inline uint64_t CallFuncUInt64Callback(FuncUInt64 func) { + using CallFuncUInt64CallbackFn = uint64_t (*)(FuncUInt64); + static CallFuncUInt64CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt64Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncPtrCallback + * @param func (function): No description available. + * + * @return ptr64: No description available. + * + * @callback FuncPtr + * @brief No description provided. + * + * + * @return (callback): ptr64: No description available. + */ + inline void *CallFuncPtrCallback(FuncPtr func) { + using CallFuncPtrCallbackFn = void* (*)(FuncPtr); + static CallFuncPtrCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncPtrCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncFloatCallback + * @param func (function): No description available. + * + * @return float: No description available. + * + * @callback FuncFloat + * @brief No description provided. + * + * + * @return (callback): float: No description available. + */ + inline float CallFuncFloatCallback(FuncFloat func) { + using CallFuncFloatCallbackFn = float (*)(FuncFloat); + static CallFuncFloatCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncFloatCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncDoubleCallback + * @param func (function): No description available. + * + * @return double: No description available. + * + * @callback FuncDouble + * @brief No description provided. + * + * + * @return (callback): double: No description available. + */ + inline double CallFuncDoubleCallback(FuncDouble func) { + using CallFuncDoubleCallbackFn = double (*)(FuncDouble); + static CallFuncDoubleCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncDoubleCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncStringCallback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback FuncString + * @brief No description provided. + * + * + * @return (callback): string: No description available. + */ + inline plg::string CallFuncStringCallback(FuncString func) { + using CallFuncStringCallbackFn = plg::string (*)(FuncString); + static CallFuncStringCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncStringCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncAnyCallback + * @param func (function): No description available. + * + * @return any: No description available. + * + * @callback FuncAny + * @brief No description provided. + * + * + * @return (callback): any: No description available. + */ + inline plg::any CallFuncAnyCallback(FuncAny func) { + using CallFuncAnyCallbackFn = plg::any (*)(FuncAny); + static CallFuncAnyCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncAnyCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncFunctionCallback + * @param func (function): No description available. + * + * @return ptr64: No description available. + * + * @callback FuncFunction + * @brief No description provided. + * + * + * @return (callback): function: No description available. + */ + inline void *CallFuncFunctionCallback(FuncFunction func) { + using CallFuncFunctionCallbackFn = void* (*)(FuncFunction); + static CallFuncFunctionCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncFunctionCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncBoolVectorCallback + * @param func (function): No description available. + * + * @return bool[]: No description available. + * + * @callback FuncBoolVector + * @brief No description provided. + * + * + * @return (callback): bool[]: No description available. + */ + inline plg::vector CallFuncBoolVectorCallback(FuncBoolVector func) { + using CallFuncBoolVectorCallbackFn = plg::vector (*)(FuncBoolVector); + static CallFuncBoolVectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncBoolVectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncChar8VectorCallback + * @param func (function): No description available. + * + * @return char8[]: No description available. + * + * @callback FuncChar8Vector + * @brief No description provided. + * + * + * @return (callback): char8[]: No description available. + */ + inline plg::vector CallFuncChar8VectorCallback(FuncChar8Vector func) { + using CallFuncChar8VectorCallbackFn = plg::vector (*)(FuncChar8Vector); + static CallFuncChar8VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncChar8VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncChar16VectorCallback + * @param func (function): No description available. + * + * @return char16[]: No description available. + * + * @callback FuncChar16Vector + * @brief No description provided. + * + * + * @return (callback): char16[]: No description available. + */ + inline plg::vector CallFuncChar16VectorCallback(FuncChar16Vector func) { + using CallFuncChar16VectorCallbackFn = plg::vector (*)(FuncChar16Vector); + static CallFuncChar16VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncChar16VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt8VectorCallback + * @param func (function): No description available. + * + * @return int8[]: No description available. + * + * @callback FuncInt8Vector + * @brief No description provided. + * + * + * @return (callback): int8[]: No description available. + */ + inline plg::vector CallFuncInt8VectorCallback(FuncInt8Vector func) { + using CallFuncInt8VectorCallbackFn = plg::vector (*)(FuncInt8Vector); + static CallFuncInt8VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt8VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt16VectorCallback + * @param func (function): No description available. + * + * @return int16[]: No description available. + * + * @callback FuncInt16Vector + * @brief No description provided. + * + * + * @return (callback): int16[]: No description available. + */ + inline plg::vector CallFuncInt16VectorCallback(FuncInt16Vector func) { + using CallFuncInt16VectorCallbackFn = plg::vector (*)(FuncInt16Vector); + static CallFuncInt16VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt16VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt32VectorCallback + * @param func (function): No description available. + * + * @return int32[]: No description available. + * + * @callback FuncInt32Vector + * @brief No description provided. + * + * + * @return (callback): int32[]: No description available. + */ + inline plg::vector CallFuncInt32VectorCallback(FuncInt32Vector func) { + using CallFuncInt32VectorCallbackFn = plg::vector (*)(FuncInt32Vector); + static CallFuncInt32VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt32VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncInt64VectorCallback + * @param func (function): No description available. + * + * @return int64[]: No description available. + * + * @callback FuncInt64Vector + * @brief No description provided. + * + * + * @return (callback): int64[]: No description available. + */ + inline plg::vector CallFuncInt64VectorCallback(FuncInt64Vector func) { + using CallFuncInt64VectorCallbackFn = plg::vector (*)(FuncInt64Vector); + static CallFuncInt64VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncInt64VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt8VectorCallback + * @param func (function): No description available. + * + * @return uint8[]: No description available. + * + * @callback FuncUInt8Vector + * @brief No description provided. + * + * + * @return (callback): uint8[]: No description available. + */ + inline plg::vector CallFuncUInt8VectorCallback(FuncUInt8Vector func) { + using CallFuncUInt8VectorCallbackFn = plg::vector (*)(FuncUInt8Vector); + static CallFuncUInt8VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt8VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt16VectorCallback + * @param func (function): No description available. + * + * @return uint16[]: No description available. + * + * @callback FuncUInt16Vector + * @brief No description provided. + * + * + * @return (callback): uint16[]: No description available. + */ + inline plg::vector CallFuncUInt16VectorCallback(FuncUInt16Vector func) { + using CallFuncUInt16VectorCallbackFn = plg::vector (*)(FuncUInt16Vector); + static CallFuncUInt16VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt16VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt32VectorCallback + * @param func (function): No description available. + * + * @return uint32[]: No description available. + * + * @callback FuncUInt32Vector + * @brief No description provided. + * + * + * @return (callback): uint32[]: No description available. + */ + inline plg::vector CallFuncUInt32VectorCallback(FuncUInt32Vector func) { + using CallFuncUInt32VectorCallbackFn = plg::vector (*)(FuncUInt32Vector); + static CallFuncUInt32VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt32VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncUInt64VectorCallback + * @param func (function): No description available. + * + * @return uint64[]: No description available. + * + * @callback FuncUInt64Vector + * @brief No description provided. + * + * + * @return (callback): uint64[]: No description available. + */ + inline plg::vector CallFuncUInt64VectorCallback(FuncUInt64Vector func) { + using CallFuncUInt64VectorCallbackFn = plg::vector (*)(FuncUInt64Vector); + static CallFuncUInt64VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncUInt64VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncPtrVectorCallback + * @param func (function): No description available. + * + * @return ptr64[]: No description available. + * + * @callback FuncPtrVector + * @brief No description provided. + * + * + * @return (callback): ptr64[]: No description available. + */ + inline plg::vector CallFuncPtrVectorCallback(FuncPtrVector func) { + using CallFuncPtrVectorCallbackFn = plg::vector (*)(FuncPtrVector); + static CallFuncPtrVectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncPtrVectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncFloatVectorCallback + * @param func (function): No description available. + * + * @return float[]: No description available. + * + * @callback FuncFloatVector + * @brief No description provided. + * + * + * @return (callback): float[]: No description available. + */ + inline plg::vector CallFuncFloatVectorCallback(FuncFloatVector func) { + using CallFuncFloatVectorCallbackFn = plg::vector (*)(FuncFloatVector); + static CallFuncFloatVectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncFloatVectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncDoubleVectorCallback + * @param func (function): No description available. + * + * @return double[]: No description available. + * + * @callback FuncDoubleVector + * @brief No description provided. + * + * + * @return (callback): double[]: No description available. + */ + inline plg::vector CallFuncDoubleVectorCallback(FuncDoubleVector func) { + using CallFuncDoubleVectorCallbackFn = plg::vector (*)(FuncDoubleVector); + static CallFuncDoubleVectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncDoubleVectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncStringVectorCallback + * @param func (function): No description available. + * + * @return string[]: No description available. + * + * @callback FuncStringVector + * @brief No description provided. + * + * + * @return (callback): string[]: No description available. + */ + inline plg::vector CallFuncStringVectorCallback(FuncStringVector func) { + using CallFuncStringVectorCallbackFn = plg::vector (*)(FuncStringVector); + static CallFuncStringVectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncStringVectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncAnyVectorCallback + * @param func (function): No description available. + * + * @return any[]: No description available. + * + * @callback FuncAnyVector + * @brief No description provided. + * + * + * @return (callback): any[]: No description available. + */ + inline plg::vector CallFuncAnyVectorCallback(FuncAnyVector func) { + using CallFuncAnyVectorCallbackFn = plg::vector (*)(FuncAnyVector); + static CallFuncAnyVectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncAnyVectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec2VectorCallback + * @param func (function): No description available. + * + * @return vec2[]: No description available. + * + * @callback FuncVec2Vector + * @brief No description provided. + * + * + * @return (callback): vec2[]: No description available. + */ + inline plg::vector CallFuncVec2VectorCallback(FuncVec2Vector func) { + using CallFuncVec2VectorCallbackFn = plg::vector (*)(FuncVec2Vector); + static CallFuncVec2VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec2VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec3VectorCallback + * @param func (function): No description available. + * + * @return vec3[]: No description available. + * + * @callback FuncVec3Vector + * @brief No description provided. + * + * + * @return (callback): vec3[]: No description available. + */ + inline plg::vector CallFuncVec3VectorCallback(FuncVec3Vector func) { + using CallFuncVec3VectorCallbackFn = plg::vector (*)(FuncVec3Vector); + static CallFuncVec3VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec3VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec4VectorCallback + * @param func (function): No description available. + * + * @return vec4[]: No description available. + * + * @callback FuncVec4Vector + * @brief No description provided. + * + * + * @return (callback): vec4[]: No description available. + */ + inline plg::vector CallFuncVec4VectorCallback(FuncVec4Vector func) { + using CallFuncVec4VectorCallbackFn = plg::vector (*)(FuncVec4Vector); + static CallFuncVec4VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec4VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncMat4x4VectorCallback + * @param func (function): No description available. + * + * @return mat4x4[]: No description available. + * + * @callback FuncMat4x4Vector + * @brief No description provided. + * + * + * @return (callback): mat4x4[]: No description available. + */ + inline plg::vector CallFuncMat4x4VectorCallback(FuncMat4x4Vector func) { + using CallFuncMat4x4VectorCallbackFn = plg::vector (*)(FuncMat4x4Vector); + static CallFuncMat4x4VectorCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncMat4x4VectorCallback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec2Callback + * @param func (function): No description available. + * + * @return vec2: No description available. + * + * @callback FuncVec2 + * @brief No description provided. + * + * + * @return (callback): vec2: No description available. + */ + inline plg::vec2 CallFuncVec2Callback(FuncVec2 func) { + using CallFuncVec2CallbackFn = plg::vec2 (*)(FuncVec2); + static CallFuncVec2CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec2Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec3Callback + * @param func (function): No description available. + * + * @return vec3: No description available. + * + * @callback FuncVec3 + * @brief No description provided. + * + * + * @return (callback): vec3: No description available. + */ + inline plg::vec3 CallFuncVec3Callback(FuncVec3 func) { + using CallFuncVec3CallbackFn = plg::vec3 (*)(FuncVec3); + static CallFuncVec3CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec3Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncVec4Callback + * @param func (function): No description available. + * + * @return vec4: No description available. + * + * @callback FuncVec4 + * @brief No description provided. + * + * + * @return (callback): vec4: No description available. + */ + inline plg::vec4 CallFuncVec4Callback(FuncVec4 func) { + using CallFuncVec4CallbackFn = plg::vec4 (*)(FuncVec4); + static CallFuncVec4CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncVec4Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncMat4x4Callback + * @param func (function): No description available. + * + * @return mat4x4: No description available. + * + * @callback FuncMat4x4 + * @brief No description provided. + * + * + * @return (callback): mat4x4: No description available. + */ + inline plg::mat4x4 CallFuncMat4x4Callback(FuncMat4x4 func) { + using CallFuncMat4x4CallbackFn = plg::mat4x4 (*)(FuncMat4x4); + static CallFuncMat4x4CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncMat4x4Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc1Callback + * @param func (function): No description available. + * + * @return int32: No description available. + * + * @callback Func1 + * @brief No description provided. + * + * @param a (vec3): No description available. + * + * @return (callback): int32: No description available. + */ + inline int32_t CallFunc1Callback(Func1 func) { + using CallFunc1CallbackFn = int32_t (*)(Func1); + static CallFunc1CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc1Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc2Callback + * @param func (function): No description available. + * + * @return char8: No description available. + * + * @callback Func2 + * @brief No description provided. + * + * @param a (float): No description available. + * @param b (int64): No description available. + * + * @return (callback): char8: No description available. + */ + inline char CallFunc2Callback(Func2 func) { + using CallFunc2CallbackFn = char (*)(Func2); + static CallFunc2CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc2Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc3Callback + * @param func (function): No description available. + * + * @callback Func3 + * @brief No description provided. + * + * @param a (ptr64): No description available. + * @param b (vec4): No description available. + * @param c (string): No description available. + * + * @return (callback): void: No description available. + */ + inline void CallFunc3Callback(Func3 func) { + using CallFunc3CallbackFn = void (*)(Func3); + static CallFunc3CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc3Callback", + reinterpret_cast(&__func)); + __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc4Callback + * @param func (function): No description available. + * + * @return vec4: No description available. + * + * @callback Func4 + * @brief No description provided. + * + * @param a (bool): No description available. + * @param b (int32): No description available. + * @param c (char16): No description available. + * @param d (mat4x4): No description available. + * + * @return (callback): vec4: No description available. + */ + inline plg::vec4 CallFunc4Callback(Func4 func) { + using CallFunc4CallbackFn = plg::vec4 (*)(Func4); + static CallFunc4CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc4Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc5Callback + * @param func (function): No description available. + * + * @return bool: No description available. + * + * @callback Func5 + * @brief No description provided. + * + * @param a (int8): No description available. + * @param b (vec2): No description available. + * @param c (ptr64): No description available. + * @param d (double): No description available. + * @param e (uint64[]): No description available. + * + * @return (callback): bool: No description available. + */ + inline bool CallFunc5Callback(Func5 func) { + using CallFunc5CallbackFn = bool (*)(Func5); + static CallFunc5CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc5Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc6Callback + * @param func (function): No description available. + * + * @return int64: No description available. + * + * @callback Func6 + * @brief No description provided. + * + * @param a (string): No description available. + * @param b (float): No description available. + * @param c (float[]): No description available. + * @param d (int16): No description available. + * @param e (uint8[]): No description available. + * @param f (ptr64): No description available. + * + * @return (callback): int64: No description available. + */ + inline int64_t CallFunc6Callback(Func6 func) { + using CallFunc6CallbackFn = int64_t (*)(Func6); + static CallFunc6CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc6Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc7Callback + * @param func (function): No description available. + * + * @return double: No description available. + * + * @callback Func7 + * @brief No description provided. + * + * @param vecC (char8[]): No description available. + * @param u16 (uint16): No description available. + * @param ch16 (char16): No description available. + * @param vecU32 (uint32[]): No description available. + * @param vec4 (vec4): No description available. + * @param b (bool): No description available. + * @param u64 (uint64): No description available. + * + * @return (callback): double: No description available. + */ + inline double CallFunc7Callback(Func7 func) { + using CallFunc7CallbackFn = double (*)(Func7); + static CallFunc7CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc7Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc8Callback + * @param func (function): No description available. + * + * @return mat4x4: No description available. + * + * @callback Func8 + * @brief No description provided. + * + * @param vec3 (vec3): No description available. + * @param vecU32 (uint32[]): No description available. + * @param i16 (int16): No description available. + * @param b (bool): No description available. + * @param vec4 (vec4): No description available. + * @param vecC16 (char16[]): No description available. + * @param ch16 (char16): No description available. + * @param i32 (int32): No description available. + * + * @return (callback): mat4x4: No description available. + */ + inline plg::mat4x4 CallFunc8Callback(Func8 func) { + using CallFunc8CallbackFn = plg::mat4x4 (*)(Func8); + static CallFunc8CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc8Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc9Callback + * @param func (function): No description available. + * + * @callback Func9 + * @brief No description provided. + * + * @param f (float): No description available. + * @param vec2 (vec2): No description available. + * @param vecI8 (int8[]): No description available. + * @param u64 (uint64): No description available. + * @param b (bool): No description available. + * @param str (string): No description available. + * @param vec4 (vec4): No description available. + * @param i16 (int16): No description available. + * @param ptr (ptr64): No description available. + * + * @return (callback): void: No description available. + */ + inline void CallFunc9Callback(Func9 func) { + using CallFunc9CallbackFn = void (*)(Func9); + static CallFunc9CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc9Callback", + reinterpret_cast(&__func)); + __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc10Callback + * @param func (function): No description available. + * + * @return uint32: No description available. + * + * @callback Func10 + * @brief No description provided. + * + * @param vec4 (vec4): No description available. + * @param mat (mat4x4): No description available. + * @param vecU32 (uint32[]): No description available. + * @param u64 (uint64): No description available. + * @param vecC (char8[]): No description available. + * @param i32 (int32): No description available. + * @param b (bool): No description available. + * @param vec2 (vec2): No description available. + * @param i64 (int64): No description available. + * @param d (double): No description available. + * + * @return (callback): uint32: No description available. + */ + inline uint32_t CallFunc10Callback(Func10 func) { + using CallFunc10CallbackFn = uint32_t (*)(Func10); + static CallFunc10CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc10Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc11Callback + * @param func (function): No description available. + * + * @return ptr64: No description available. + * + * @callback Func11 + * @brief No description provided. + * + * @param vecB (bool[]): No description available. + * @param ch16 (char16): No description available. + * @param u8 (uint8): No description available. + * @param d (double): No description available. + * @param vec3 (vec3): No description available. + * @param vecI8 (int8[]): No description available. + * @param i64 (int64): No description available. + * @param u16 (uint16): No description available. + * @param f (float): No description available. + * @param vec2 (vec2): No description available. + * @param u32 (uint32): No description available. + * + * @return (callback): ptr64: No description available. + */ + inline void *CallFunc11Callback(Func11 func) { + using CallFunc11CallbackFn = void* (*)(Func11); + static CallFunc11CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc11Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc12Callback + * @param func (function): No description available. + * + * @return bool: No description available. + * + * @callback Func12 + * @brief No description provided. + * + * @param ptr (ptr64): No description available. + * @param vecD (double[]): No description available. + * @param u32 (uint32): No description available. + * @param d (double): No description available. + * @param b (bool): No description available. + * @param i32 (int32): No description available. + * @param i8 (int8): No description available. + * @param u64 (uint64): No description available. + * @param f (float): No description available. + * @param vecPtr (ptr64[]): No description available. + * @param i64 (int64): No description available. + * @param ch (char8): No description available. + * + * @return (callback): bool: No description available. + */ + inline bool CallFunc12Callback(Func12 func) { + using CallFunc12CallbackFn = bool (*)(Func12); + static CallFunc12CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc12Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc13Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func13 + * @brief No description provided. + * + * @param i64 (int64): No description available. + * @param vecC (char8[]): No description available. + * @param d (uint16): No description available. + * @param f (float): No description available. + * @param b (bool[]): No description available. + * @param vec4 (vec4): No description available. + * @param str (string): No description available. + * @param int32 (int32): No description available. + * @param vec3 (vec3): No description available. + * @param ptr (ptr64): No description available. + * @param vec2 (vec2): No description available. + * @param arr (uint8[]): No description available. + * @param i16 (int16): No description available. + * + * @return (callback): string: No description available. + */ + inline plg::string CallFunc13Callback(Func13 func) { + using CallFunc13CallbackFn = plg::string (*)(Func13); + static CallFunc13CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc13Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc14Callback + * @param func (function): No description available. + * + * @return string[]: No description available. + * + * @callback Func14 + * @brief No description provided. + * + * @param vecC (char8[]): No description available. + * @param vecU32 (uint32[]): No description available. + * @param mat (mat4x4): No description available. + * @param b (bool): No description available. + * @param ch16 (char16): No description available. + * @param i32 (int32): No description available. + * @param vecF (float[]): No description available. + * @param u16 (uint16): No description available. + * @param vecU8 (uint8[]): No description available. + * @param i8 (int8): No description available. + * @param vec3 (vec3): No description available. + * @param vec4 (vec4): No description available. + * @param d (double): No description available. + * @param ptr (ptr64): No description available. + * + * @return (callback): string[]: No description available. + */ + inline plg::vector CallFunc14Callback(Func14 func) { + using CallFunc14CallbackFn = plg::vector (*)(Func14); + static CallFunc14CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc14Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc15Callback + * @param func (function): No description available. + * + * @return int16: No description available. + * + * @callback Func15 + * @brief No description provided. + * + * @param vecI16 (int16[]): No description available. + * @param mat (mat4x4): No description available. + * @param vec4 (vec4): No description available. + * @param ptr (ptr64): No description available. + * @param u64 (uint64): No description available. + * @param vecU32 (uint32[]): No description available. + * @param b (bool): No description available. + * @param f (float): No description available. + * @param vecC16 (char16[]): No description available. + * @param u8 (uint8): No description available. + * @param i32 (int32): No description available. + * @param vec2 (vec2): No description available. + * @param u16 (uint16): No description available. + * @param d (double): No description available. + * @param vecU8 (uint8[]): No description available. + * + * @return (callback): int16: No description available. + */ + inline int16_t CallFunc15Callback(Func15 func) { + using CallFunc15CallbackFn = int16_t (*)(Func15); + static CallFunc15CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc15Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc16Callback + * @param func (function): No description available. + * + * @return ptr64: No description available. + * + * @callback Func16 + * @brief No description provided. + * + * @param vecB (bool[]): No description available. + * @param i16 (int16): No description available. + * @param vecI8 (int8[]): No description available. + * @param vec4 (vec4): No description available. + * @param mat (mat4x4): No description available. + * @param vec2 (vec2): No description available. + * @param vecU64 (uint64[]): No description available. + * @param vecC (char8[]): No description available. + * @param str (string): No description available. + * @param i64 (int64): No description available. + * @param vecU32 (uint32[]): No description available. + * @param vec3 (vec3): No description available. + * @param f (float): No description available. + * @param d (double): No description available. + * @param i8 (int8): No description available. + * @param u16 (uint16): No description available. + * + * @return (callback): ptr64: No description available. + */ + inline void *CallFunc16Callback(Func16 func) { + using CallFunc16CallbackFn = void* (*)(Func16); + static CallFunc16CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc16Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc17Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func17 + * @brief No description provided. + * + * @param i32 (int32): No description available. + * + * @return (callback): void: No description available. + */ + inline plg::string CallFunc17Callback(Func17 func) { + using CallFunc17CallbackFn = plg::string (*)(Func17); + static CallFunc17CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc17Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc18Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func18 + * @brief No description provided. + * + * @param i8 (int8): No description available. + * @param i16 (int16): No description available. + * + * @return (callback): vec2: No description available. + */ + inline plg::string CallFunc18Callback(Func18 func) { + using CallFunc18CallbackFn = plg::string (*)(Func18); + static CallFunc18CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc18Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc19Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func19 + * @brief No description provided. + * + * @param u32 (uint32): No description available. + * @param vec3 (vec3): No description available. + * @param vecU32 (uint32[]): No description available. + * + * @return (callback): void: No description available. + */ + inline plg::string CallFunc19Callback(Func19 func) { + using CallFunc19CallbackFn = plg::string (*)(Func19); + static CallFunc19CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc19Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc20Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func20 + * @brief No description provided. + * + * @param ch16 (char16): No description available. + * @param vec4 (vec4): No description available. + * @param vecU64 (uint64[]): No description available. + * @param ch (char8): No description available. + * + * @return (callback): int32: No description available. + */ + inline plg::string CallFunc20Callback(Func20 func) { + using CallFunc20CallbackFn = plg::string (*)(Func20); + static CallFunc20CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc20Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc21Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func21 + * @brief No description provided. + * + * @param mat (mat4x4): No description available. + * @param vecI32 (int32[]): No description available. + * @param vec2 (vec2): No description available. + * @param b (bool): No description available. + * @param extraParam (double): No description available. + * + * @return (callback): float: No description available. + */ + inline plg::string CallFunc21Callback(Func21 func) { + using CallFunc21CallbackFn = plg::string (*)(Func21); + static CallFunc21CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc21Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc22Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func22 + * @brief No description provided. + * + * @param ptr64Ref (ptr64): No description available. + * @param uint32Ref (uint32): No description available. + * @param vectorDoubleRef (double[]): No description available. + * @param int16Ref (int16): No description available. + * @param plgStringRef (string): No description available. + * @param plgVector4Ref (vec4): No description available. + * + * @return (callback): uint64: No description available. + */ + inline plg::string CallFunc22Callback(Func22 func) { + using CallFunc22CallbackFn = plg::string (*)(Func22); + static CallFunc22CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc22Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc23Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func23 + * @brief No description provided. + * + * @param uint64Ref (uint64): No description available. + * @param plgVector2Ref (vec2): No description available. + * @param vectorInt16Ref (int16[]): No description available. + * @param char16Ref (char16): No description available. + * @param floatRef (float): No description available. + * @param int8Ref (int8): No description available. + * @param vectorUInt8Ref (uint8[]): No description available. + * + * @return (callback): void: No description available. + */ + inline plg::string CallFunc23Callback(Func23 func) { + using CallFunc23CallbackFn = plg::string (*)(Func23); + static CallFunc23CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc23Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc24Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func24 + * @brief No description provided. + * + * @param vectorCharRef (char8[]): No description available. + * @param int64Ref (int64): No description available. + * @param vectorUInt8Ref (uint8[]): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param uint64Ref (uint64): No description available. + * @param vectorptr64Ref (ptr64[]): No description available. + * @param doubleRef (double): No description available. + * @param vectorptr64Ref2 (ptr64[]): No description available. + * + * @return (callback): mat4x4: No description available. + */ + inline plg::string CallFunc24Callback(Func24 func) { + using CallFunc24CallbackFn = plg::string (*)(Func24); + static CallFunc24CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc24Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc25Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func25 + * @brief No description provided. + * + * @param int32Ref (int32): No description available. + * @param vectorptr64Ref (ptr64[]): No description available. + * @param boolRef (bool): No description available. + * @param uint8Ref (uint8): No description available. + * @param plgStringRef (string): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param int64Ref (int64): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param uint16Ref (uint16): No description available. + * + * @return (callback): double: No description available. + */ + inline plg::string CallFunc25Callback(Func25 func) { + using CallFunc25CallbackFn = plg::string (*)(Func25); + static CallFunc25CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc25Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc26Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func26 + * @brief No description provided. + * + * @param char16Ref (char16): No description available. + * @param plgVector2Ref (vec2): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param vectorFloatRef (float[]): No description available. + * @param int16Ref (int16): No description available. + * @param uint64Ref (uint64): No description available. + * @param uint32Ref (uint32): No description available. + * @param vectorUInt16Ref (uint16[]): No description available. + * @param ptr64Ref (ptr64): No description available. + * @param boolRef (bool): No description available. + * + * @return (callback): char8: No description available. + */ + inline plg::string CallFunc26Callback(Func26 func) { + using CallFunc26CallbackFn = plg::string (*)(Func26); + static CallFunc26CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc26Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc27Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func27 + * @brief No description provided. + * + * @param floatRef (float): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param ptr64Ref (ptr64): No description available. + * @param plgVector2Ref (vec2): No description available. + * @param vectorInt16Ref (int16[]): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param boolRef (bool): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param int8Ref (int8): No description available. + * @param int32Ref (int32): No description available. + * @param vectorUInt8Ref (uint8[]): No description available. + * + * @return (callback): uint8: No description available. + */ + inline plg::string CallFunc27Callback(Func27 func) { + using CallFunc27CallbackFn = plg::string (*)(Func27); + static CallFunc27CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc27Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc28Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func28 + * @brief No description provided. + * + * @param ptr64Ref (ptr64): No description available. + * @param uint16Ref (uint16): No description available. + * @param vectorUInt32Ref (uint32[]): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param floatRef (float): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param plgStringRef (string): No description available. + * @param vectorUInt64Ref (uint64[]): No description available. + * @param int64Ref (int64): No description available. + * @param boolRef (bool): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param vectorFloatRef (float[]): No description available. + * + * @return (callback): string: No description available. + */ + inline plg::string CallFunc28Callback(Func28 func) { + using CallFunc28CallbackFn = plg::string (*)(Func28); + static CallFunc28CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc28Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc29Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func29 + * @brief No description provided. + * + * @param plgVector4Ref (vec4): No description available. + * @param int32Ref (int32): No description available. + * @param vectorInt8Ref (int8[]): No description available. + * @param doubleRef (double): No description available. + * @param boolRef (bool): No description available. + * @param int8Ref (int8): No description available. + * @param vectorUInt16Ref (uint16[]): No description available. + * @param floatRef (float): No description available. + * @param plgStringRef (string): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param uint64Ref (uint64): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param vectorInt64Ref (int64[]): No description available. + * + * @return (callback): string[]: No description available. + */ + inline plg::string CallFunc29Callback(Func29 func) { + using CallFunc29CallbackFn = plg::string (*)(Func29); + static CallFunc29CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc29Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc30Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func30 + * @brief No description provided. + * + * @param ptr64Ref (ptr64): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param int64Ref (int64): No description available. + * @param vectorUInt32Ref (uint32[]): No description available. + * @param boolRef (bool): No description available. + * @param plgStringRef (string): No description available. + * @param plgVector3Ref (vec3): No description available. + * @param vectorUInt8Ref (uint8[]): No description available. + * @param floatRef (float): No description available. + * @param plgVector2Ref (vec2): No description available. + * @param plgMatrix4x4Ref (mat4x4): No description available. + * @param int8Ref (int8): No description available. + * @param vectorFloatRef (float[]): No description available. + * @param doubleRef (double): No description available. + * + * @return (callback): int32: No description available. + */ + inline plg::string CallFunc30Callback(Func30 func) { + using CallFunc30CallbackFn = plg::string (*)(Func30); + static CallFunc30CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc30Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc31Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func31 + * @brief No description provided. + * + * @param charRef (char8): No description available. + * @param uint32Ref (uint32): No description available. + * @param vectorUInt64Ref (uint64[]): No description available. + * @param plgVector4Ref (vec4): No description available. + * @param plgStringRef (string): No description available. + * @param boolRef (bool): No description available. + * @param int64Ref (int64): No description available. + * @param vec2Ref (vec2): No description available. + * @param int8Ref (int8): No description available. + * @param uint16Ref (uint16): No description available. + * @param vectorInt16Ref (int16[]): No description available. + * @param mat4x4Ref (mat4x4): No description available. + * @param vec3Ref (vec3): No description available. + * @param floatRef (float): No description available. + * @param vectorDoubleRef (double[]): No description available. + * + * @return (callback): vec3: No description available. + */ + inline plg::string CallFunc31Callback(Func31 func) { + using CallFunc31CallbackFn = plg::string (*)(Func31); + static CallFunc31CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc31Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc32Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func32 + * @brief No description provided. + * + * @param p1 (int32): No description available. + * @param p2 (uint16): No description available. + * @param p3 (int8[]): No description available. + * @param p4 (vec4): No description available. + * @param p5 (ptr64): No description available. + * @param p6 (uint32[]): No description available. + * @param p7 (mat4x4): No description available. + * @param p8 (uint64): No description available. + * @param p9 (string): No description available. + * @param p10 (int64): No description available. + * @param p11 (vec2): No description available. + * @param p12 (int8[]): No description available. + * @param p13 (bool): No description available. + * @param p14 (vec3): No description available. + * @param p15 (uint8): No description available. + * @param p16 (char16[]): No description available. + * + * @return (callback): double: No description available. + */ + inline plg::string CallFunc32Callback(Func32 func) { + using CallFunc32CallbackFn = plg::string (*)(Func32); + static CallFunc32CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc32Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFunc33Callback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback Func33 + * @brief No description provided. + * + * @param variant (any): No description available. + * + * @return (callback): void: No description available. + */ + inline plg::string CallFunc33Callback(Func33 func) { + using CallFunc33CallbackFn = plg::string (*)(Func33); + static CallFunc33CallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFunc33Callback", + reinterpret_cast(&__func)); + return __func(func); + } + + /** + * @brief No description provided. + * + * @function CallFuncEnumCallback + * @param func (function): No description available. + * + * @return string: No description available. + * + * @callback FuncEnum + * @brief No description provided. + * + * @param p1 (int32): No description available. + * @param p2 (int32[]): No description available. + * + * @return (callback): int32[]: No description available. + */ + inline plg::string CallFuncEnumCallback(FuncEnum func) { + using CallFuncEnumCallbackFn = plg::string (*)(FuncEnum); + static CallFuncEnumCallbackFn __func = nullptr; + if (__func == nullptr) plg::GetMethodPtr2("cross_call_master.CallFuncEnumCallback", + reinterpret_cast(&__func)); + return __func(func); + } } // namespace cross_call_master diff --git a/test/cross_call_worker/plugin.cpp b/test/cross_call_worker/plugin.cpp index 8bd4317..e78151b 100644 --- a/test/cross_call_worker/plugin.cpp +++ b/test/cross_call_worker/plugin.cpp @@ -15,7 +15,7 @@ PLUGIFY_WARN_PUSH() #if defined(__clang__) -PLUGIFY_WARN_IGNORE("-Wreturn-type-c-linkage") +PLUGIFY_WARN_IGNORE ("-Wreturn-type-c-linkage") #elif defined(_MSC_VER) PLUGIFY_WARN_IGNORE(4190) #endif @@ -25,6 +25,7 @@ using Example = cross_call_master::Example; // format support #ifdef FMT_HEADER_ONLY namespace fmt { + #else namespace std { #endif @@ -35,7 +36,7 @@ namespace std { } template - auto format(const Example& e, FormatContext &ctx) const { + auto format(const Example &e, FormatContext &ctx) const { return std::format_to(ctx.out(), "{}", static_cast(e)); } }; @@ -53,79 +54,79 @@ PLUGIN_API void NoParamReturnVoid() { extern "C" PLUGIN_API bool NoParamReturnBool() { - return true; + return true; } extern "C" PLUGIN_API char NoParamReturnChar8() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API char16_t NoParamReturnChar16() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API int8_t NoParamReturnInt8() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API int16_t NoParamReturnInt16() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API int32_t NoParamReturnInt32() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API int64_t NoParamReturnInt64() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API uint8_t NoParamReturnUInt8() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API uint16_t NoParamReturnUInt16() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API uint32_t NoParamReturnUInt32() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API uint64_t NoParamReturnUInt64() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" -PLUGIN_API void* NoParamReturnPointer() { - return reinterpret_cast(0x1); +PLUGIN_API void *NoParamReturnPointer() { + return reinterpret_cast(0x1); } extern "C" PLUGIN_API float NoParamReturnFloat() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } extern "C" PLUGIN_API double NoParamReturnDouble() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } using NoParamReturnFunctionFunc = void (*)(); extern "C" PLUGIN_API NoParamReturnFunctionFunc NoParamReturnFunction() { - return nullptr; + return nullptr; } extern "C" @@ -140,82 +141,88 @@ PLUGIN_API plg::any NoParamReturnAny() { extern "C" PLUGIN_API plg::vector NoParamReturnArrayBool() { - return {true, false}; + return {true, false}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayChar8() { - return {'a', 'b', 'c', 'd'}; + return {'a', 'b', 'c', 'd'}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayChar16() { - return {u'a', u'b', u'c', u'd'}; + return {u'a', u'b', u'c', u'd'}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayInt8() { - return {-3, -2, -1, 0, 1}; + return {-3, -2, -1, 0, 1}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayInt16() { - return {-4, -3, -2, -1, 0, 1}; + return {-4, -3, -2, -1, 0, 1}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayInt32() { - return {-5, -4, -3, -2, -1, 0, 1}; + return {-5, -4, -3, -2, -1, 0, 1}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayInt64() { - return {-6, -5, -4, -3, -2, -1, 0, 1}; + return {-6, -5, -4, -3, -2, -1, 0, 1}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayUInt8() { - return {0, 1, 2, 3, 4, 5, 6, 7, 8}; + return {0, 1, 2, 3, 4, 5, 6, 7, 8}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayUInt16() { - return {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + return {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayUInt32() { - return {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + return {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayUInt64() { - return {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + return {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; } extern "C" -PLUGIN_API plg::vector NoParamReturnArrayPointer() { - return {reinterpret_cast(0), reinterpret_cast(1), reinterpret_cast(2), reinterpret_cast(3)}; +PLUGIN_API plg::vector NoParamReturnArrayPointer() { + return { + reinterpret_cast(0), reinterpret_cast(1), reinterpret_cast(2), + reinterpret_cast(3) + }; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayFloat() { - return {-12.34f, 0.0f, 12.34f}; + return {-12.34f, 0.0f, 12.34f}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayDouble() { - return {-12.345, 0.0, 12.345}; + return {-12.345, 0.0, 12.345}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayString() { - return {"1st string", "2nd string", "3rd element string (Should be big enough to avoid small string optimization)"}; + return {"1st string", "2nd string", "3rd element string (Should be big enough to avoid small string optimization)"}; } extern "C" PLUGIN_API plg::vector NoParamReturnArrayAny() { - return {1.0, 2.0f, "3rd element string (Should be big enough to avoid small string optimization)", plg::vector{"lolek", "and", "bolek"}, 1}; + return { + 1.0, 2.0f, "3rd element string (Should be big enough to avoid small string optimization)", + plg::vector{"lolek", "and", "bolek"}, 1 + }; } extern "C" @@ -258,243 +265,265 @@ PLUGIN_API plg::vector NoParamReturnArrayMatrix4x4() { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f // Identity matrix + 0.0f, 0.0f, 0.0f, 1.0f // Identity matrix }, { 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, - 14.0f, 15.0f, 16.0f, 17.0f // Example random matrix + 14.0f, 15.0f, 16.0f, 17.0f // Example random matrix }, { -1.0f, -2.0f, -3.0f, -4.0f, -5.0f, -6.0f, -7.0f, -8.0f, -9.0f, -10.0f, -11.0f, -12.0f, - -13.0f, -14.0f, -15.0f, -16.0f // Negative matrix + -13.0f, -14.0f, -15.0f, -16.0f // Negative matrix } }; } extern "C" PLUGIN_API plg::vec2 NoParamReturnVector2() { - return {1.f, 2.f}; + return {1.f, 2.f}; } extern "C" PLUGIN_API plg::vec3 NoParamReturnVector3() { - return {1.f, 2.f, 3.f}; + return {1.f, 2.f, 3.f}; } extern "C" PLUGIN_API plg::vec4 NoParamReturnVector4() { - return {1.f, 2.f, 3.f, 4.f}; + return {1.f, 2.f, 3.f, 4.f}; } extern "C" PLUGIN_API plg::mat4x4 NoParamReturnMatrix4x4() { - return {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f, 16.f}; + return {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f, 16.f}; } extern "C" PLUGIN_API void Param1(int32_t a) { - const auto buffer = std::format("{}", a); + const auto buffer = std::format("{}", a); } extern "C" PLUGIN_API void Param2(int32_t a, float b) { - const auto buffer = std::format("{}{:.2f}", a, b); + const auto buffer = std::format("{}{:.2f}", a, b); } extern "C" PLUGIN_API void Param3(int32_t a, float b, double c) { - const auto buffer = std::format("{}{:.2f}{:.2f}", a, b, c); + const auto buffer = std::format("{}{:.2f}{:.2f}", a, b, c); } extern "C" -PLUGIN_API void Param4(int32_t a, float b, double c, const plg::vec4& d) { - const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}", a, b, c, d.x, d.w); +PLUGIN_API void Param4(int32_t a, float b, double c, const plg::vec4 &d) { + const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}", a, b, c, d.x, d.w); } extern "C" -PLUGIN_API void Param5(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e) { - const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}", a, b, c, d.x, d.w, e.size(), e.size() == 3 ? e[2] : int64_t{0}); +PLUGIN_API void Param5(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e) { + const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}", a, b, c, d.x, d.w, e.size(), + e.size() == 3 ? e[2] : int64_t{0}); } extern "C" -PLUGIN_API void Param6(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f) { - const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}", a, b, c, d.x, d.w, e.size(), e.size() == 3 ? e[2] : int64_t{0}, static_cast(f)); +PLUGIN_API void Param6(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f) { + const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}", a, b, c, d.x, d.w, e.size(), + e.size() == 3 ? e[2] : int64_t{0}, static_cast(f)); } extern "C" -PLUGIN_API void Param7(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g) { - const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}{}", a, b, c, d.x, d.w, e.size(), e.size() == 3 ? e[2] : int64_t{0}, static_cast(f), g); +PLUGIN_API void Param7(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g) { + const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}{}", a, b, c, d.x, d.w, e.size(), + e.size() == 3 ? e[2] : int64_t{0}, static_cast(f), g); } extern "C" -PLUGIN_API void Param8(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h) { - const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}{}{}", a, b, c, d.x, d.w, e.size(), e.size() == 3 ? e[2] : int64_t{0}, static_cast(f), g, static_cast(h)); +PLUGIN_API void Param8(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h) { + const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}{}{}", a, b, c, d.x, d.w, e.size(), + e.size() == 3 ? e[2] : int64_t{0}, static_cast(f), g, + static_cast(h)); } extern "C" -PLUGIN_API void Param9(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h, int16_t k) { - const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}{}{}{}", a, b, c, d.x, d.w, e.size(), e.size() == 3 ? e[2] : int64_t{0}, static_cast(f), g, static_cast(h), k); +PLUGIN_API void Param9(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h, int16_t k) { + const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}{}{}{}", a, b, c, d.x, d.w, e.size(), + e.size() == 3 ? e[2] : int64_t{0}, static_cast(f), g, + static_cast(h), k); } extern "C" -PLUGIN_API void Param10(int32_t a, float b, double c, const plg::vec4& d, const plg::vector& e, char f, const plg::string& g, char16_t h, int16_t k, void* l) { - const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}{}{}{}{}", a, b, c, d.x, d.w, e.size(), e.size() == 3 ? e[2] : int64_t{0}, static_cast(f), g, static_cast(h), k, l); +PLUGIN_API void Param10(int32_t a, float b, double c, const plg::vec4 &d, const plg::vector &e, char f, + const plg::string &g, char16_t h, int16_t k, void *l) { + const auto buffer = std::format("{}{:.2f}{:.2f}{:.1f}{:.1f}{}{}{}{}{}{}{}", a, b, c, d.x, d.w, e.size(), + e.size() == 3 ? e[2] : int64_t{0}, static_cast(f), g, + static_cast(h), k, l); } extern "C" -PLUGIN_API void ParamRef1(int32_t& a) { - a = 42; +PLUGIN_API void ParamRef1(int32_t &a) { + a = 42; } extern "C" -PLUGIN_API void ParamRef2(int32_t& a, float& b) { - a = 10; - b = 3.14f; +PLUGIN_API void ParamRef2(int32_t &a, float &b) { + a = 10; + b = 3.14f; } extern "C" -PLUGIN_API void ParamRef3(int32_t& a, float& b, double& c) { - a = -20; - b = 2.718f; - c = 3.14159; +PLUGIN_API void ParamRef3(int32_t &a, float &b, double &c) { + a = -20; + b = 2.718f; + c = 3.14159; } extern "C" -PLUGIN_API void ParamRef4(int32_t& a, float& b, double& c, plg::vec4& d) { - a = 100; - b = -5.55f; - c = 1.618; - d = {1.0f, 2.0f, 3.0f, 4.0f}; +PLUGIN_API void ParamRef4(int32_t &a, float &b, double &c, plg::vec4 &d) { + a = 100; + b = -5.55f; + c = 1.618; + d = {1.0f, 2.0f, 3.0f, 4.0f}; } extern "C" -PLUGIN_API void ParamRef5(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e) { - a = 500; - b = -10.5f; - c = 2.71828; - d = {-1.0f, -2.0f, -3.0f, -4.0f}; - e = {-6, -5, -4, -3, -2, -1, 0, 1}; +PLUGIN_API void ParamRef5(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e) { + a = 500; + b = -10.5f; + c = 2.71828; + d = {-1.0f, -2.0f, -3.0f, -4.0f}; + e = {-6, -5, -4, -3, -2, -1, 0, 1}; } extern "C" -PLUGIN_API void ParamRef6(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f) { - a = 750; - b = 20.0f; - c = 1.23456; - d = {10.0f, 20.0f, 30.0f, 40.0f}; - e = {-6, -5, -4}; - f = 'Z'; +PLUGIN_API void ParamRef6(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f) { + a = 750; + b = 20.0f; + c = 1.23456; + d = {10.0f, 20.0f, 30.0f, 40.0f}; + e = {-6, -5, -4}; + f = 'Z'; } extern "C" -PLUGIN_API void ParamRef7(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g) { - a = -1000; - b = 3.0f; - c = -1.0; - d = {100.0f, 200.0f, 300.0f, 400.0f}; - e = {-6, -5, -4, -3}; - f = 'Y'; - g = "Hello, World!"; +PLUGIN_API void ParamRef7(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g) { + a = -1000; + b = 3.0f; + c = -1.0; + d = {100.0f, 200.0f, 300.0f, 400.0f}; + e = {-6, -5, -4, -3}; + f = 'Y'; + g = "Hello, World!"; } extern "C" -PLUGIN_API void ParamRef8(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h) { - a = 999; - b = -7.5f; - c = 0.123456; - d = {-100.0f, -200.0f, -300.0f, -400.0f}; - e = {-6, -5, -4, -3, -2, -1}; - f = 'X'; - g = "Goodbye, World!"; - h = 'A'; +PLUGIN_API void ParamRef8(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h) { + a = 999; + b = -7.5f; + c = 0.123456; + d = {-100.0f, -200.0f, -300.0f, -400.0f}; + e = {-6, -5, -4, -3, -2, -1}; + f = 'X'; + g = "Goodbye, World!"; + h = 'A'; } extern "C" -PLUGIN_API void ParamRef9(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h, int16_t& k) { - a = -1234; - b = 123.45f; - c = -678.9; - d = {987.65f, 432.1f, 123.456f, 789.123f}; - e = {-6, -5, -4, -3, -2, -1, 0, 1, 5, 9}; - f = 'W'; - g = "Testing, 1 2 3"; - h = 'B'; - k = 42; +PLUGIN_API void ParamRef9(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h, int16_t &k) { + a = -1234; + b = 123.45f; + c = -678.9; + d = {987.65f, 432.1f, 123.456f, 789.123f}; + e = {-6, -5, -4, -3, -2, -1, 0, 1, 5, 9}; + f = 'W'; + g = "Testing, 1 2 3"; + h = 'B'; + k = 42; } extern "C" -PLUGIN_API void ParamRef10(int32_t& a, float& b, double& c, plg::vec4& d, plg::vector& e, char& f, plg::string& g, char16_t& h, int16_t& k, void*& l) { - a = 987; - b = -0.123f; - c = 456.789; - d = {-123.456f, 0.987f, 654.321f, -789.123f}; - e = {-6, -5, -4, -3, -2, -1, 0, 1, 5, 9, 4, -7}; - f = 'V'; - g = "Another string"; - h = 'C'; - k = -444; - l = reinterpret_cast(0x12345678); +PLUGIN_API void ParamRef10(int32_t &a, float &b, double &c, plg::vec4 &d, plg::vector &e, char &f, + plg::string &g, char16_t &h, int16_t &k, void *&l) { + a = 987; + b = -0.123f; + c = 456.789; + d = {-123.456f, 0.987f, 654.321f, -789.123f}; + e = {-6, -5, -4, -3, -2, -1, 0, 1, 5, 9, 4, -7}; + f = 'V'; + g = "Another string"; + h = 'C'; + k = -444; + l = reinterpret_cast(0x12345678); } extern "C" -PLUGIN_API void ParamRefVectors(plg::vector& p1, plg::vector& p2, plg::vector& p3, plg::vector& p4, plg::vector& p5, - plg::vector& p6, plg::vector& p7, plg::vector& p8, plg::vector& p9, plg::vector& p10, plg::vector& p11, - plg::vector& p12, plg::vector& p13, plg::vector& p14, plg::vector& p15 +PLUGIN_API void ParamRefVectors(plg::vector &p1, plg::vector &p2, plg::vector &p3, + plg::vector &p4, plg::vector &p5, + plg::vector &p6, plg::vector &p7, plg::vector &p8, + plg::vector &p9, plg::vector &p10, plg::vector &p11, + plg::vector &p12, plg::vector &p13, plg::vector &p14, + plg::vector &p15 ) { - p1 = {true}; - p2 = {'a', 'b', 'c'}; - p3 = {'d', 'e', 'f'}; - p4 = {-3, -2, -1, 0, 1, 2, 3}; - p5 = {-4, -3, -2, -1, 0, 1, 2, 3, 4}; - p6 = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; - p7 = {-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6}; - p8 = {0, 1, 2, 3, 4, 5, 6, 7}; - p9 = {0, 1, 2, 3, 4, 5, 6, 7, 8}; - p10 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - p11 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - p12 = {reinterpret_cast(0), reinterpret_cast(1), reinterpret_cast(2)}; - p13 = {-12.34f, 0.0f, 12.34f}; - p14 = {-12.345, 0.0, 12.345}; - p15 = {"1", "12", "123", "1234", "12345", "123456"}; -} - -extern "C" -PLUGIN_API int64_t ParamAllPrimitives(bool p1, char p2, char16_t p3, int8_t p4, int16_t p5, int32_t p6, int64_t p7, uint8_t p8, uint16_t p9, uint32_t p10, - uint64_t p11, void* p12, float p13, double p14 + p1 = {true}; + p2 = {'a', 'b', 'c'}; + p3 = {'d', 'e', 'f'}; + p4 = {-3, -2, -1, 0, 1, 2, 3}; + p5 = {-4, -3, -2, -1, 0, 1, 2, 3, 4}; + p6 = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + p7 = {-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6}; + p8 = {0, 1, 2, 3, 4, 5, 6, 7}; + p9 = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + p10 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + p11 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + p12 = {reinterpret_cast(0), reinterpret_cast(1), reinterpret_cast(2)}; + p13 = {-12.34f, 0.0f, 12.34f}; + p14 = {-12.345, 0.0, 12.345}; + p15 = {"1", "12", "123", "1234", "12345", "123456"}; +} + +extern "C" +PLUGIN_API int64_t ParamAllPrimitives(bool p1, char p2, char16_t p3, int8_t p4, int16_t p5, int32_t p6, int64_t p7, + uint8_t p8, uint16_t p9, uint32_t p10, + uint64_t p11, void *p12, float p13, double p14 ) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}{:.3f}{:.3f}", p1, static_cast(p2), static_cast(p3), p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); - return 56; + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}{:.3f}{:.3f}", p1, static_cast(p2), + static_cast(p3), p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); + return 56; } extern "C" -PLUGIN_API int32_t ParamEnum(Example p1, const plg::vector& p2) { +PLUGIN_API int32_t ParamEnum(Example p1, const plg::vector &p2) { return static_cast(p1) + std::accumulate(p2.begin(), p2.end(), int32_t{0}, - [](int32_t sum, const Example& e) { - return sum + static_cast(e); - }); + [](int32_t sum, const Example &e) { + return sum + static_cast(e); + }); } extern "C" -PLUGIN_API int32_t ParamEnumRef(Example& p1, plg::vector& p2) { +PLUGIN_API int32_t ParamEnumRef(Example &p1, plg::vector &p2) { p1 = Example::Forth; p2 = plg::vector{Example::First, Example::Second, Example::Third}; return static_cast(p1) + std::accumulate(p2.begin(), p2.end(), int32_t{0}, - [](int32_t sum, const Example& e) { - return sum + static_cast(e); - }); + [](int32_t sum, const Example &e) { + return sum + static_cast(e); + }); } extern "C" -PLUGIN_API void ParamVariant(const plg::any& p1, const plg::vector& p2) { +PLUGIN_API void ParamVariant(const plg::any &p1, const plg::vector &p2) { const auto buffer = std::format("{}|{}", p1, p2); } extern "C" -PLUGIN_API void ParamVariantRef(plg::any& p1, plg::vector& p2) { +PLUGIN_API void ParamVariantRef(plg::any &p1, plg::vector &p2) { p1 = 'Z'; p2.resize(5); p2[0] = false; @@ -518,7 +547,7 @@ PLUGIN_API bool CallFuncBool(cross_call_master::FuncBool func) { extern "C" PLUGIN_API char CallFuncChar8(cross_call_master::FuncChar8 func) { - char result = func(); + char result = func(); return result; } @@ -577,8 +606,8 @@ PLUGIN_API uint64_t CallFuncUInt64(cross_call_master::FuncUInt64 func) { } extern "C" -PLUGIN_API void* CallFuncPtr(cross_call_master::FuncPtr func) { - void* result = func(); +PLUGIN_API void *CallFuncPtr(cross_call_master::FuncPtr func) { + void *result = func(); return result; } @@ -595,8 +624,8 @@ PLUGIN_API double CallFuncDouble(cross_call_master::FuncDouble func) { } extern "C" -PLUGIN_API void* CallFuncFunction(cross_call_master::FuncFunction func) { - void* result = func(); +PLUGIN_API void *CallFuncFunction(cross_call_master::FuncFunction func) { + void *result = func(); return result; } @@ -680,8 +709,8 @@ PLUGIN_API plg::vector CallFuncUInt64Vector(cross_call_master::FuncUIn } extern "C" -PLUGIN_API plg::vector CallFuncPtrVector(cross_call_master::FuncPtrVector func) { - plg::vector result = func(); +PLUGIN_API plg::vector CallFuncPtrVector(cross_call_master::FuncPtrVector func) { + plg::vector result = func(); return std::move(result); } @@ -776,7 +805,7 @@ PLUGIN_API char CallFunc2(cross_call_master::Func2 func) { // 3 parameters extern "C" PLUGIN_API void CallFunc3(cross_call_master::Func3 func) { - void* ptr = reinterpret_cast(12345); // Example pointer changed + void *ptr = reinterpret_cast(12345); // Example pointer changed plg::vec4 vec4{7.8f, 8.9f, 9.1f, 10.2f}; // Changed to random values plg::string str = "RandomString"; // Changed string func(ptr, vec4, str); @@ -797,7 +826,7 @@ extern "C" PLUGIN_API bool CallFunc5(cross_call_master::Func5 func) { int8_t i8 = 10; // Changed to random int8_t plg::vec2 vec2{3.4f, 5.6f}; // Changed to random values - void* ptr = reinterpret_cast(67890); // Example pointer changed + void *ptr = reinterpret_cast(67890); // Example pointer changed double d = 1.618; // Changed to random double plg::vector vec64{4, 5, 6}; // Changed to random values return func(i8, vec2, ptr, d, vec64); @@ -811,7 +840,7 @@ PLUGIN_API int64_t CallFunc6(cross_call_master::Func6 func) { plg::vector vecF{4.0f, 5.0f, 6.0f}; // Changed to random values int16_t i16 = 30; // Changed to random int16_t plg::vector vecU8{3, 4, 5}; // Changed to random values - void* ptr = reinterpret_cast(24680); // Example pointer changed + void *ptr = reinterpret_cast(24680); // Example pointer changed return func(str, f, vecF, i16, vecU8, ptr); } @@ -836,7 +865,7 @@ PLUGIN_API plg::mat4x4 CallFunc8(cross_call_master::Func8 func) { int16_t i16 = 30; // Changed to random int16_t bool b = false; // Changed to random bool plg::vec4 vec4{4.5f, 5.6f, 6.7f, 7.8f}; // Changed to random values - plg::vector vecC16{ 'D', 'E' }; // Changed to random chars + plg::vector vecC16{'D', 'E'}; // Changed to random chars char16_t ch16 = L'B'; // Changed to random character int32_t i32 = 50; // Changed to random int32_t return func(vec3, vecU32, i16, b, vec4, vecC16, ch16, i32); @@ -853,7 +882,7 @@ PLUGIN_API void CallFunc9(cross_call_master::Func9 func) { plg::string str = "Random"; // Changed string plg::vec4 vec4{4.5f, 5.6f, 6.7f, 7.8f}; // Changed to random values int16_t i16 = 30; // Changed to random int16_t - void* ptr = reinterpret_cast(13579); // Example pointer changed + void *ptr = reinterpret_cast(13579); // Example pointer changed func(f, vec2, vecI8, u64, b, str, vec4, i16, ptr); } @@ -875,7 +904,7 @@ PLUGIN_API uint32_t CallFunc10(cross_call_master::Func10 func) { // 11 parameters extern "C" -PLUGIN_API void* CallFunc11(cross_call_master::Func11 func) { +PLUGIN_API void *CallFunc11(cross_call_master::Func11 func) { plg::vector vecB{false, true, false}; // Changed to random bools char16_t ch16 = 'C'; // Changed to random character uint8_t u8 = 10; // Changed to random uint8_t @@ -893,7 +922,7 @@ PLUGIN_API void* CallFunc11(cross_call_master::Func11 func) { // 12 parameters extern "C" PLUGIN_API bool CallFunc12(cross_call_master::Func12 func) { - void* ptr = reinterpret_cast(98765); // Example pointer changed + void *ptr = reinterpret_cast(98765); // Example pointer changed plg::vector vecD{4.0, 5.0, 6.0}; // Changed to random values uint32_t u32 = 30; // Changed to random uint32_t double d = 1.41; // Changed to random double @@ -902,7 +931,9 @@ PLUGIN_API bool CallFunc12(cross_call_master::Func12 func) { int8_t i8 = 10; // Changed to random int8_t uint64_t u64 = 300; // Changed to random uint64_t float f = 2.72f; // Changed to random float - plg::vector vecPtr{reinterpret_cast(2), reinterpret_cast(3), reinterpret_cast(4)}; // Changed to random values + plg::vector vecPtr{ + reinterpret_cast(2), reinterpret_cast(3), reinterpret_cast(4) + }; // Changed to random values int64_t i64 = 200; // Changed to random int64_t char ch = 'B'; // Changed to random character return func(ptr, vecD, u32, d, b, i32, i8, u64, f, vecPtr, i64, ch); @@ -920,7 +951,7 @@ PLUGIN_API plg::string CallFunc13(cross_call_master::Func13 func) { plg::string str = "RandomString"; // Changed string int32_t i32 = 30; // Changed to random int32_t plg::vec3 vec3{4.0f, 5.0f, 6.0f}; // Changed to random values - void* ptr = reinterpret_cast(13579); // Example pointer changed + void *ptr = reinterpret_cast(13579); // Example pointer changed plg::vec2 vec2{4.5f, 6.7f}; // Changed to random values plg::vector vecU8{2, 3, 4}; // Changed to random values int16_t i16 = 20; // Changed to random int16_t @@ -944,7 +975,7 @@ PLUGIN_API plg::vector CallFunc14(cross_call_master::Func14 func) { plg::vec3 vec3{4.0f, 5.0f, 6.0f}; // Changed to random values plg::vec4 vec4{5.6f, 7.8f, 9.0f, 10.1f}; // Changed to random values double d = 2.72; // Changed to random double - void* ptr = reinterpret_cast(54321); // Example pointer changed + void *ptr = reinterpret_cast(54321); // Example pointer changed auto ret = func(vecC, vecU32, mat, b, ch16, i32, vecF, u16, vecU8, i8, vec3, vec4, d, ptr); return std::move(ret); } @@ -955,7 +986,7 @@ PLUGIN_API int16_t CallFunc15(cross_call_master::Func15 func) { plg::vector vecI16{4, 5, 6}; // Changed to random values plg::mat4x4 mat; // Assume it's initialized properly plg::vec4 vec4{7.8f, 8.9f, 9.0f, 10.1f}; // Changed to random values - void* ptr = reinterpret_cast(12345); // Example pointer changed + void *ptr = reinterpret_cast(12345); // Example pointer changed uint64_t u64 = 200; // Changed to random uint64_t plg::vector vecU32{5, 6, 7}; // Changed to random values bool b = false; // Changed to random bool @@ -972,7 +1003,7 @@ PLUGIN_API int16_t CallFunc15(cross_call_master::Func15 func) { // 16 parameters extern "C" -PLUGIN_API void* CallFunc16(cross_call_master::Func16 func) { +PLUGIN_API void *CallFunc16(cross_call_master::Func16 func) { plg::vector vecB{true, true, false}; // Changed to random bools int16_t i16 = 20; // Changed to random int16_t plg::vector vecI8{2, 3, 4}; // Changed to random values @@ -1045,7 +1076,7 @@ PLUGIN_API plg::string CallFunc21(cross_call_master::Func21 func) { // 6 parameters extern "C" PLUGIN_API plg::string CallFunc22(cross_call_master::Func22 func) { - void* ptr = reinterpret_cast(1); // Changed from 0 to 1 + void *ptr = reinterpret_cast(1); // Changed from 0 to 1 uint32_t u32 = 20; // Changed from 10 to 20 plg::vector vecD{4.0, 5.0, 6.0}; // Changed vector values int16_t i16 = 15; // Changed from 10 to 15 @@ -1077,9 +1108,14 @@ PLUGIN_API plg::string CallFunc24(cross_call_master::Func24 func) { plg::vector vecU8{3, 4, 5}; // Changed vector values plg::vec4 vec4{5.0f, 6.0f, 7.0f, 8.0f}; // Changed vec4 values uint64_t u64 = 200; // Changed from 100 to 200 - plg::vector vecPtr{reinterpret_cast(3), reinterpret_cast(4), reinterpret_cast(5)}; // Changed vector values + plg::vector vecPtr{ + reinterpret_cast(3), reinterpret_cast(4), reinterpret_cast(5) + }; // Changed vector values double d = 6.28; // Changed from 3.14 to 6.28 - plg::vector vecV2{ reinterpret_cast(4), reinterpret_cast(5), reinterpret_cast(6), reinterpret_cast(7) }; // Changed vector values + plg::vector vecV2{ + reinterpret_cast(4), reinterpret_cast(5), reinterpret_cast(6), + reinterpret_cast(7) + }; // Changed vector values plg::mat4x4 ret = func(vecC, i64, vecU8, vec4, u64, vecPtr, d, vecV2); return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, vecC, i64, vecU8, vec4, u64, vecPtr, d, vecV2); } @@ -1088,7 +1124,9 @@ PLUGIN_API plg::string CallFunc24(cross_call_master::Func24 func) { extern "C" PLUGIN_API plg::string CallFunc25(cross_call_master::Func25 func) { int32_t i32 = 50; // Changed from 20 to 50 - plg::vector vecPtr{reinterpret_cast(3), reinterpret_cast(4), reinterpret_cast(5)}; // Changed vector values + plg::vector vecPtr{ + reinterpret_cast(3), reinterpret_cast(4), reinterpret_cast(5) + }; // Changed vector values bool b = false; // Changed from true to false uint8_t u8 = 10; // Changed from 5 to 10 plg::string str = "Updated Test String"; // Changed string @@ -1097,7 +1135,8 @@ PLUGIN_API plg::string CallFunc25(cross_call_master::Func25 func) { plg::vec4 vec4{5.0f, 6.0f, 7.0f, 8.0f}; // Changed vec4 values uint16_t u16 = 20; // Changed from 10 to 20 double ret = func(i32, vecPtr, b, u8, str, vec3, i64, vec4, u16); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, i32, vecPtr, b ? "true" : "false", u8, str.c_str(), vec3, i64, vec4, u16); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, i32, vecPtr, b ? "true" : "false", u8, str.c_str(), vec3, + i64, vec4, u16); } // 10 parameters @@ -1111,17 +1150,19 @@ PLUGIN_API plg::string CallFunc26(cross_call_master::Func26 func) { uint64_t u64 = 200; // Changed from 100 to 200 uint32_t u32 = 20; // Changed from 10 to 20 plg::vector vecU16{3, 4, 5}; - void* ptr = reinterpret_cast(0xDEADBEAFDEADBEAF); // Example pointer + void *ptr = reinterpret_cast(0xDEADBEAFDEADBEAF); // Example pointer bool b = false; char ret = func(ch16, vec2, mat, vecF, i16, u64, u32, vecU16, ptr, b); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, static_cast(ch16), vec2, mat, vecF, u64, u32, vecU16, ptr, b ? "true" : "false"); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, static_cast(ch16), vec2, mat, vecF, u64, u32, + vecU16, ptr, b ? "true" : "false"); } + // 11 parameters extern "C" PLUGIN_API plg::string CallFunc27(cross_call_master::Func27 func) { float f = 2.56f; // Changed from 1.23f plg::vec3 vec3{4.0f, 5.0f, 6.0f}; // Changed values - void* ptr = nullptr; // Example pointer + void *ptr = nullptr; // Example pointer plg::vec2 vec2{3.0f, 4.0f}; // Changed values plg::vector vecI16{4, 5, 6}; // Changed values plg::mat4x4 mat; // Assume it's initialized properly @@ -1131,13 +1172,14 @@ PLUGIN_API plg::string CallFunc27(cross_call_master::Func27 func) { int32_t i32 = 40; // Changed from 20 to 40 plg::vector vecU8{3, 4, 5}; // Changed values uint8_t ret = func(f, vec3, ptr, vec2, vecI16, mat, b, vec4, i8, i32, vecU8); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, f, vec3, ptr, vec2, vecI16, mat, b, vec4, i8, i32, vecU8); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, f, vec3, ptr, vec2, vecI16, mat, b, vec4, i8, i32, + vecU8); } // 12 parameters extern "C" PLUGIN_API plg::string CallFunc28(cross_call_master::Func28 func) { - void* ptr = reinterpret_cast(1); // Changed from 0 + void *ptr = reinterpret_cast(1); // Changed from 0 uint16_t u16 = 20; // Changed from 10 plg::vector vecU32{4, 5, 6}; // Changed values plg::mat4x4 mat; // Assume initialized properly @@ -1151,7 +1193,8 @@ PLUGIN_API plg::string CallFunc28(cross_call_master::Func28 func) { plg::vector vecF{4.0f, 5.0f, 6.0f}; // Changed values plg::string ret = func(ptr, u16, vecU32, mat, f, vec4, str, vecU64, i64, b, vec3, vecF); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ptr, u16, vecU32, mat, f, vec4, str, vecU64, i64, b, vec3, vecF); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ptr, u16, vecU32, mat, f, vec4, str, vecU64, i64, + b, vec3, vecF); } // 13 parameters @@ -1172,13 +1215,14 @@ PLUGIN_API plg::string CallFunc29(cross_call_master::Func29 func) { plg::vector vecI64{2000, 3000, 4000}; // Changed values plg::vector ret = func(vec4, i32, vecI8, d, b, i8, vecU16, f, str, mat, u64, vec3, vecI64); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, vec4, i32, vecI8, d, b ? "true" : "false", i8, vecU16, f, str, mat, u64, vec3, vecI64); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, vec4, i32, vecI8, d, b ? "true" : "false", i8, + vecU16, f, str, mat, u64, vec3, vecI64); } // 14 parameters extern "C" PLUGIN_API plg::string CallFunc30(cross_call_master::Func30 func) { - void* ptr = reinterpret_cast(1); // Changed from 0 + void *ptr = reinterpret_cast(1); // Changed from 0 plg::vec4 vec4{2.0f, 3.0f, 4.0f, 5.0f}; // Changed values int64_t i64 = 987654321; // Changed from 123456789 plg::vector vecU32{4, 5, 6}; // Changed values @@ -1194,7 +1238,8 @@ PLUGIN_API plg::string CallFunc30(cross_call_master::Func30 func) { double d = 8.90; // Changed from 7.89 int32_t ret = func(ptr, vec4, i64, vecU32, b, str, vec3, vecU8, f, vec2, mat, i8, vecF, d); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ptr, vec4, i64, vecU32, b ? "true" : "false", str, vec3, vecU8, f, vec2, mat, i8, vecF, d); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ptr, vec4, i64, vecU32, + b ? "true" : "false", str, vec3, vecU8, f, vec2, mat, i8, vecF, d); } // 15 parameters @@ -1217,7 +1262,8 @@ PLUGIN_API plg::string CallFunc31(cross_call_master::Func31 func) { plg::vector vecD{4.0, 5.0, 6.0}; // Changed values plg::vec3 ret = func(ch, u32, vecU64, vec4, str, b, i64, vec2, i8, u16, vecI16, mat, vec3, f, vecD); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ch, u32, vecU64, vec4, str, b ? "true" : "false", i64, vec2, i8, u16, vecI16, mat, vec3, f, vecD); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", ret, ch, u32, vecU64, vec4, str, + b ? "true" : "false", i64, vec2, i8, u16, vecI16, mat, vec3, f, vecD); } // 16 parameters @@ -1227,7 +1273,7 @@ PLUGIN_API plg::string CallFunc32(cross_call_master::Func32 func) { uint16_t u16 = 20; // Changed from 10 plg::vector vecI8{4, 5, 6}; // Changed values plg::vec4 vec4{2.0f, 3.0f, 4.0f, 5.0f}; // Changed values - void* ptr = reinterpret_cast(1); // Changed from 0 + void *ptr = reinterpret_cast(1); // Changed from 0 plg::vector vecU32{4, 5, 6}; // Changed values plg::mat4x4 mat; // Assume initialized properly uint64_t u64 = 200; // Changed from 100 @@ -1241,7 +1287,8 @@ PLUGIN_API plg::string CallFunc32(cross_call_master::Func32 func) { plg::vector vecC16{u'D', u'E', u'F'}; // Changed values func(i32, u16, vecI8, vec4, ptr, vecU32, mat, u64, str, i64, vec2, vecI8_2, b, vec3, u8, vecC16); - return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", i32, u16, vecI8, vec4, ptr, vecU32, mat, u64, str, i64, vec2, vecI8_2, b ? "true" : "false", vec3, u8, vecC16); + return std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", i32, u16, vecI8, vec4, ptr, vecU32, mat, u64, + str, i64, vec2, vecI8_2, b ? "true" : "false", vec3, u8, vecC16); } // 1 parameters @@ -1258,12 +1305,15 @@ PLUGIN_API plg::string CallFuncEnum(cross_call_master::FuncEnum func) { cross_call_master::Example p1 = cross_call_master::Example::Forth; plg::vector p2; auto ret = func(p1, p2); - return std::format("{}|{}", ret, p2); + return std::format("{}|{}", ret, p2); } // Mock Functions for the typedefs -void MockVoid() { /*std::cout << "Void function called\n";*/ } +void MockVoid() { + /*std::cout << "Void function called\n";*/ +} + bool MockBool() { return true; } char MockChar8() { return 'A'; } char16_t MockChar16() { return u'Z'; } @@ -1275,10 +1325,10 @@ uint8_t MockUInt8() { return 20; } uint16_t MockUInt16() { return 200; } uint32_t MockUInt32() { return 2000; } uint64_t MockUInt64() { return 20000; } -void* MockPtr() { return nullptr; } +void *MockPtr() { return nullptr; } float MockFloat() { return 3.14f; } double MockDouble() { return 6.28; } -void* MockFunction() { return nullptr; } +void *MockFunction() { return nullptr; } plg::string MockString() { return "Test string"; } plg::any MockAny() { return L'A'; } @@ -1293,675 +1343,848 @@ plg::vector MockUInt8Vector() { return {20, 30}; } plg::vector MockUInt16Vector() { return {200, 300}; } plg::vector MockUInt32Vector() { return {2000, 3000}; } plg::vector MockUInt64Vector() { return {20000, 30000}; } -plg::vector MockPtrVector() { return {nullptr, reinterpret_cast(1) }; } +plg::vector MockPtrVector() { return {nullptr, reinterpret_cast(1)}; } plg::vector MockFloatVector() { return {1.1f, 2.2f}; } plg::vector MockDoubleVector() { return {3.3, 4.4}; } plg::vector MockStringVector() { return {"Hello", "World"}; } plg::vector MockAnyVector() { return {"Hello", 3.14f, 6.28, 1, 0xDEADBEAF}; } + plg::vector MockVec2Vector() { return { - {0.5f, -1.2f}, - {3.4f, 7.8f}, - {-6.7f, 2.3f}, - {8.9f, -4.5f}, - {0.0f, 0.0f} + {0.5f, -1.2f}, + {3.4f, 7.8f}, + {-6.7f, 2.3f}, + {8.9f, -4.5f}, + {0.0f, 0.0f} }; } plg::vector MockVec3Vector() { return { - {2.1f, 3.2f, 4.3f}, - {-5.4f, 6.5f, -7.6f}, - {8.7f, 9.8f, 0.1f}, - {1.2f, -3.3f, 4.4f}, - {-5.5f, 6.6f, -7.7f} + {2.1f, 3.2f, 4.3f}, + {-5.4f, 6.5f, -7.6f}, + {8.7f, 9.8f, 0.1f}, + {1.2f, -3.3f, 4.4f}, + {-5.5f, 6.6f, -7.7f} }; } plg::vector MockVec4Vector() { return { - {0.1f, 1.2f, 2.3f, 3.4f}, - {-4.5f, 5.6f, 6.7f, -7.8f}, - {8.9f, -9.0f, 10.1f, -11.2f}, - {12.3f, 13.4f, 14.5f, 15.6f}, - {-16.7f, 17.8f, 18.9f, -19.0f} + {0.1f, 1.2f, 2.3f, 3.4f}, + {-4.5f, 5.6f, 6.7f, -7.8f}, + {8.9f, -9.0f, 10.1f, -11.2f}, + {12.3f, 13.4f, 14.5f, 15.6f}, + {-16.7f, 17.8f, 18.9f, -19.0f} }; } plg::vector MockMat4x4Vector() { return { - // Identity matrix - { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }, - // Random matrix #1 - { - 0.5f, 1.0f, 1.5f, 2.0f, - 2.5f, 3.0f, 3.5f, 4.0f, - 4.5f, 5.0f, 5.5f, 6.0f, - 6.5f, 7.0f, 7.5f, 8.0f - }, - // Random matrix #2 - { - -1.0f, -2.0f, -3.0f, -4.0f, - -5.0f, -6.0f, -7.0f, -8.0f, - -9.0f, -10.0f, -11.0f, -12.0f, - -13.0f, -14.0f, -15.0f, -16.0f - }, - // Random matrix #3 - { - 1.1f, 2.2f, 3.3f, 4.4f, - 5.5f, 6.6f, 7.7f, 8.8f, - 9.9f, 10.0f, 11.1f, 12.2f, - 13.3f, 14.4f, 15.5f, 16.6f - } + // Identity matrix + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }, + // Random matrix #1 + { + 0.5f, 1.0f, 1.5f, 2.0f, + 2.5f, 3.0f, 3.5f, 4.0f, + 4.5f, 5.0f, 5.5f, 6.0f, + 6.5f, 7.0f, 7.5f, 8.0f + }, + // Random matrix #2 + { + -1.0f, -2.0f, -3.0f, -4.0f, + -5.0f, -6.0f, -7.0f, -8.0f, + -9.0f, -10.0f, -11.0f, -12.0f, + -13.0f, -14.0f, -15.0f, -16.0f + }, + // Random matrix #3 + { + 1.1f, 2.2f, 3.3f, 4.4f, + 5.5f, 6.6f, 7.7f, 8.8f, + 9.9f, 10.0f, 11.1f, 12.2f, + 13.3f, 14.4f, 15.5f, 16.6f + } }; } + plg::vec2 MockVec2() { return {1.0f, 2.0f}; } plg::vec3 MockVec3() { return {1.0f, 2.0f, 3.0f}; } plg::vec4 MockVec4() { return {1.0f, 2.0f, 3.0f, 4.0f}; } -plg::mat4x4 MockMat4x4() { return {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; } + +plg::mat4x4 MockMat4x4() { + return {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; +} // Mock implementations for 1 parameter functions -int32_t MockFunc1(const plg::vec3& v) { +int32_t MockFunc1(const plg::vec3 &v) { const auto buffer = std::format("{}{}{}", v.x, v.y, v.z); - return static_cast(v.x + v.y + v.z); + return static_cast(v.x + v.y + v.z); } // Mock implementations for 2 parameter functions char MockFunc2(float a, int64_t b) { const auto buffer = std::format("{}{}", a, b); - return '&'; + return '&'; } // Mock implementations for 3 parameter functions -void MockFunc3(void* p, const plg::vec4& v, const plg::string& s) { +void MockFunc3(void *p, const plg::vec4 &v, const plg::string &s) { const auto buffer = std::format("{}{}{}{}{}{}", p, v.x, v.y, v.z, v.w, s); } // Mock implementations for 4 parameter functions -plg::vec4 MockFunc4(bool flag, int32_t u, char16_t c, const plg::mat4x4& m) { +plg::vec4 MockFunc4(bool flag, int32_t u, char16_t c, const plg::mat4x4 &m) { const auto buffer = std::format("{}{}{}{}", flag, u, static_cast(c), m.m[3][3]); - return {1.0f, 2.0f, 3.0f, 4.0f}; // Returning a dummy const plg::vec4 + return {1.0f, 2.0f, 3.0f, 4.0f}; // Returning a dummy const plg::vec4 } // Mock implementations for 5 parameter functions -bool MockFunc5(int8_t i, const plg::vec2& v, void* p, double d, const plg::vector& vec) { +bool MockFunc5(int8_t i, const plg::vec2 &v, void *p, double d, const plg::vector &vec) { const auto buffer = std::format("{}{}{}{}{}{}", i, v.x, v.y, p, d, vec.size()); - return true; // Returning dummy bool + return true; // Returning dummy bool } // Mock implementations for 6 parameter functions -int64_t MockFunc6(const plg::string& s, float f, const plg::vector& vec, int16_t i, const plg::vector& uVec, void* p) { +int64_t MockFunc6(const plg::string &s, float f, const plg::vector &vec, int16_t i, + const plg::vector &uVec, void *p) { const auto buffer = std::format("{}{}{}{}{}{}", s, f, vec.size(), i, uVec.size(), p); - return static_cast(f + i); // Returning a dummy int64_t + return static_cast(f + i); // Returning a dummy int64_t } // Mock implementations for 7 parameter functions -double MockFunc7(const plg::vector& vec, uint16_t u, char16_t c, const plg::vector& uVec, const plg::vec4& v, bool flag, uint64_t l) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", vec.size(), u, static_cast(c), uVec.size(), v.x, v.y, v.z, v.w, flag, l); - return 3.14; // Returning dummy double +double MockFunc7(const plg::vector &vec, uint16_t u, char16_t c, const plg::vector &uVec, + const plg::vec4 &v, bool flag, uint64_t l) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", vec.size(), u, static_cast(c), uVec.size(), v.x, + v.y, v.z, v.w, flag, l); + return 3.14; // Returning dummy double } // Mock implementations for 8 parameter functions -plg::mat4x4 MockFunc8(const plg::vec3& v, const plg::vector& uVec, int16_t i, bool flag, const plg::vec4& v4, const plg::vector& cVec, char16_t c, int32_t a) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", v.x, v.y, v.z, uVec.size(), i, flag, v4.w, cVec.size(), static_cast(c), a); +plg::mat4x4 MockFunc8(const plg::vec3 &v, const plg::vector &uVec, int16_t i, bool flag, const plg::vec4 &v4, + const plg::vector &cVec, char16_t c, int32_t a) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", v.x, v.y, v.z, uVec.size(), i, flag, v4.w, cVec.size(), + static_cast(c), a); return {}; // Returning a dummy const plg::mat4x4 } // Mock implementations for 9 parameter functions -void MockFunc9(float f, const plg::vec2& v, const plg::vector& iVec, uint64_t l, bool flag, const plg::string& s, const plg::vec4& v4, int16_t i, void* p) { +void MockFunc9(float f, const plg::vec2 &v, const plg::vector &iVec, uint64_t l, bool flag, + const plg::string &s, const plg::vec4 &v4, int16_t i, void *p) { const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", f, v.x, v.y, iVec.size(), l, flag, s, v4.w, i, p); } // Mock implementations for 10 parameter functions -uint32_t MockFunc10(const plg::vec4& v4, const plg::mat4x4& m, const plg::vector& uVec, uint64_t l, const plg::vector& cVec, int32_t a, bool flag, const plg::vec2& v, int64_t i, double d) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}", v4.x, v4.y, v4.z, v4.w, m.m[3][3], uVec.size(), l, cVec.size(), a, flag, v.x, v.y, i, d); - return 42; // Returning dummy uint32_t +uint32_t MockFunc10(const plg::vec4 &v4, const plg::mat4x4 &m, const plg::vector &uVec, uint64_t l, + const plg::vector &cVec, int32_t a, bool flag, const plg::vec2 &v, int64_t i, double d) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}", v4.x, v4.y, v4.z, v4.w, m.m[3][3], uVec.size(), l, + cVec.size(), a, flag, v.x, v.y, i, d); + return 42; // Returning dummy uint32_t } // Mock implementations for 11 parameter functions -void* MockFunc11(const plg::vector& bVec, char16_t c, uint8_t u, double d, const plg::vec3& v3, const plg::vector& iVec, int64_t i, uint16_t u16, float f, const plg::vec2& v, uint32_t u32) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", bVec.size(), static_cast(c), u, d, v3.x, iVec.size(), i, u16, f, v.x, u32); - return 0; // Returning dummy void* +void *MockFunc11(const plg::vector &bVec, char16_t c, uint8_t u, double d, const plg::vec3 &v3, + const plg::vector &iVec, int64_t i, uint16_t u16, float f, const plg::vec2 &v, uint32_t u32) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", bVec.size(), static_cast(c), u, d, v3.x, + iVec.size(), i, u16, f, v.x, u32); + return 0; // Returning dummy void* } // Mock implementations for 12 parameter functions -bool MockFunc12(void* p, const plg::vector& dVec, uint32_t u, double d, bool flag, int32_t a, int8_t i, uint64_t l, float f, const plg::vector& pVec, int64_t i64, char c) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}", p, dVec.size(), u, d, flag, a, i, l, f, pVec.size(), i64, c); - return false; // Returning dummy bool +bool MockFunc12(void *p, const plg::vector &dVec, uint32_t u, double d, bool flag, int32_t a, int8_t i, + uint64_t l, float f, const plg::vector &pVec, int64_t i64, char c) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}", p, dVec.size(), u, d, flag, a, i, l, f, pVec.size(), + i64, c); + return false; // Returning dummy bool } // Mock implementations for 13 parameter functions -plg::string MockFunc13(int64_t i64, const plg::vector& cVec, uint16_t u16, float f, const plg::vector& bVec, const plg::vec4& v4, const plg::string& s, int32_t a, const plg::vec3& v3, void* p, const plg::vec2& v2, const plg::vector& u8Vec, int16_t i16) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", i64, cVec.size(), u16, f, bVec.size(), v4.z, s, a, v3.x, p, v2.x, u8Vec.size(), i16); - return "Dummy String"; // Returning dummy string +plg::string MockFunc13(int64_t i64, const plg::vector &cVec, uint16_t u16, float f, const plg::vector &bVec, + const plg::vec4 &v4, const plg::string &s, int32_t a, const plg::vec3 &v3, void *p, + const plg::vec2 &v2, const plg::vector &u8Vec, int16_t i16) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", i64, cVec.size(), u16, f, bVec.size(), v4.z, s, a, v3.x, p, + v2.x, u8Vec.size(), i16); + return "Dummy String"; // Returning dummy string } // Mock implementations for 14 parameter functions -plg::vector MockFunc14(const plg::vector& cVec, const plg::vector& uVec, const plg::mat4x4& m, bool flag, char16_t c, int32_t a, const plg::vector& fVec, uint16_t u16, const plg::vector& u8Vec, int8_t i8, const plg::vec3& v3, const plg::vec4& v4, double d, void* p) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}", cVec.size(), uVec.size(), m.m[3][3], flag, static_cast(c), a, fVec.size(), u16, u8Vec.size(), i8, v3.x, v4.x, d, p); - return {"String1", "String2"}; // Returning dummy vector of strings +plg::vector MockFunc14(const plg::vector &cVec, const plg::vector &uVec, + const plg::mat4x4 &m, bool flag, char16_t c, int32_t a, + const plg::vector &fVec, uint16_t u16, const plg::vector &u8Vec, + int8_t i8, const plg::vec3 &v3, const plg::vec4 &v4, double d, void *p) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}", cVec.size(), uVec.size(), m.m[3][3], flag, + static_cast(c), a, fVec.size(), u16, u8Vec.size(), i8, v3.x, v4.x, d, p); + return {"String1", "String2"}; // Returning dummy vector of strings } // Mock implementations for 15 parameter functions -int16_t MockFunc15(const plg::vector& iVec, const plg::mat4x4& m, const plg::vec4& v4, void* p, uint64_t l, const plg::vector& uVec, bool flag, float f, const plg::vector& cVec, uint8_t u, int32_t a, const plg::vec2& v2, uint16_t u16, double d, const plg::vector& u8Vec) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", iVec.size(), m.m[3][3], v4.x, p, l, uVec.size(), flag, f, cVec.size(), u, a, v2.x, u16, d, u8Vec.size()); - return 257; // Returning dummy int16_t +int16_t MockFunc15(const plg::vector &iVec, const plg::mat4x4 &m, const plg::vec4 &v4, void *p, uint64_t l, + const plg::vector &uVec, bool flag, float f, const plg::vector &cVec, uint8_t u, + int32_t a, const plg::vec2 &v2, uint16_t u16, double d, const plg::vector &u8Vec) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}", iVec.size(), m.m[3][3], v4.x, p, l, uVec.size(), flag, f, + cVec.size(), u, a, v2.x, u16, d, u8Vec.size()); + return 257; // Returning dummy int16_t } // Mock implementations for 16 parameter functions -void* MockFunc16(const plg::vector& bVec, int16_t i16, const plg::vector& iVec, const plg::vec4& v4, const plg::mat4x4& m, const plg::vec2& v2, const plg::vector& uVec, const plg::vector& cVec, const plg::string& s, int64_t i64, const plg::vector& u32Vec, const plg::vec3& v3, float f, double d, int8_t i8, uint16_t u16) { - const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", i16, bVec.size(), iVec.size(), v4.x, v4.y, v4.z, v4.w, m.m[3][3], v2.x, uVec.size(), cVec.size(), s, i64, u32Vec.size(), v3.x, f, d, i8, u16); - return 0; // Returning dummy void* +void *MockFunc16(const plg::vector &bVec, int16_t i16, const plg::vector &iVec, const plg::vec4 &v4, + const plg::mat4x4 &m, const plg::vec2 &v2, const plg::vector &uVec, + const plg::vector &cVec, const plg::string &s, int64_t i64, const plg::vector &u32Vec, + const plg::vec3 &v3, float f, double d, int8_t i8, uint16_t u16) { + const auto buffer = std::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", i16, bVec.size(), iVec.size(), v4.x, v4.y, v4.z, + v4.w, m.m[3][3], v2.x, uVec.size(), cVec.size(), s, i64, u32Vec.size(), v3.x, f, d, + i8, u16); + return 0; // Returning dummy void* } // Mock implementations for 17 parameter functions -void MockFunc17(int32_t& ref) { - ref += 10; // Modifying the reference +void MockFunc17(int32_t &ref) { + ref += 10; // Modifying the reference } // Mock implementations for 18 parameter functions -plg::vec2 MockFunc18(int8_t& i8, int16_t& i16) { - i8 = 5; // Setting a value for int8_t reference - i16 = 10; // Setting a value for int16_t reference - return {static_cast(i8), static_cast(i16)}; // Returning dummy plg::vec2 +plg::vec2 MockFunc18(int8_t &i8, int16_t &i16) { + i8 = 5; // Setting a value for int8_t reference + i16 = 10; // Setting a value for int16_t reference + return {static_cast(i8), static_cast(i16)}; // Returning dummy plg::vec2 } // Mock implementations for 19 parameter functions -void MockFunc19(uint32_t& u32, plg::vec3& v3, plg::vector& uVec) { - u32 = 42; // Setting a value for uint32_t reference - v3 = {1.0f, 2.0f, 3.0f}; // Setting a value for plg::vec3 reference - uVec = {1, 2, 3}; // Setting values for plg::vector +void MockFunc19(uint32_t &u32, plg::vec3 &v3, plg::vector &uVec) { + u32 = 42; // Setting a value for uint32_t reference + v3 = {1.0f, 2.0f, 3.0f}; // Setting a value for plg::vec3 reference + uVec = {1, 2, 3}; // Setting values for plg::vector } // Mock implementations for 20 parameter functions -int32_t MockFunc20(char16_t& c, plg::vec4& v4, plg::vector& uVec, char& ch) { - c = u't'; // Setting a value for char16_t reference - v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference - uVec = {100, 200}; // Setting values for plg::vector - ch = 'F'; - return 0; // Returning dummy int32_t +int32_t MockFunc20(char16_t &c, plg::vec4 &v4, plg::vector &uVec, char &ch) { + c = u't'; // Setting a value for char16_t reference + v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference + uVec = {100, 200}; // Setting values for plg::vector + ch = 'F'; + return 0; // Returning dummy int32_t } // Mock implementations for 21 parameter functions -float MockFunc21(plg::mat4x4& m, plg::vector& iVec, plg::vec2& v2, bool& flag, double& d) { - flag = true; // Setting a value for bool reference - d = 3.14; // Setting a value for double reference - v2 = {1.0f, 2.0f}; // Setting a value for plg::vec2 reference +float MockFunc21(plg::mat4x4 &m, plg::vector &iVec, plg::vec2 &v2, bool &flag, double &d) { + flag = true; // Setting a value for bool reference + d = 3.14; // Setting a value for double reference + v2 = {1.0f, 2.0f}; // Setting a value for plg::vec2 reference m = { - 1.3f, 0.6f, 0.8f, 0.5f, // Row 0 - 0.7f, 1.1f, 0.2f, 0.4f, // Row 1 - 0.9f, 0.3f, 1.2f, 0.7f, // Row 2 - 0.2f, 0.8f, 0.5f, 1.0f // Row 3 - };// Setting a value for plg::mat4x4 reference - iVec = {1, 2, 3}; // Setting values for plg::vector - return 0.0f; // Returning dummy float + 1.3f, 0.6f, 0.8f, 0.5f, // Row 0 + 0.7f, 1.1f, 0.2f, 0.4f, // Row 1 + 0.9f, 0.3f, 1.2f, 0.7f, // Row 2 + 0.2f, 0.8f, 0.5f, 1.0f // Row 3 + }; // Setting a value for plg::mat4x4 reference + iVec = {1, 2, 3}; // Setting values for plg::vector + return 0.0f; // Returning dummy float } // Mock implementations for 22 parameter functions -uint64_t MockFunc22(void*& p, uint32_t& u32, plg::vector& dVec, int16_t& i16, plg::string& s, plg::vec4& v4) { - //std::cout << "MockFunc22 called with uint32_t: " << u32 << ", int16_t: " << i16 << "\n"; - p = nullptr; // Setting a value for void* reference - u32 = 99; // Setting a value for uint32_t reference - i16 = 123; // Setting a value for int16_t reference - s = "Hello"; // Setting a value for string reference - v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference - dVec = {1.1, 2.2, 3.3}; // Setting values for plg::vector - return 0; // Returning dummy uint64_t +uint64_t MockFunc22(void *&p, uint32_t &u32, plg::vector &dVec, int16_t &i16, plg::string &s, plg::vec4 &v4) { + //std::cout << "MockFunc22 called with uint32_t: " << u32 << ", int16_t: " << i16 << "\n"; + p = nullptr; // Setting a value for void* reference + u32 = 99; // Setting a value for uint32_t reference + i16 = 123; // Setting a value for int16_t reference + s = "Hello"; // Setting a value for string reference + v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference + dVec = {1.1, 2.2, 3.3}; // Setting values for plg::vector + return 0; // Returning dummy uint64_t } // Mock implementations for 23 parameter functions -void MockFunc23(uint64_t& u64, plg::vec2& v2, plg::vector& iVec, char16_t& c, float& f, int8_t& i8, plg::vector& u8Vec) { - //std::cout << "MockFunc23 called with float: " << f << ", int8_t: " << static_cast(i8) << "\n"; - u64 = 50; // Setting a value for uint64_t reference - f = 1.5f; // Setting a value for float reference - i8 = -1; // Setting a value for int8_t reference - v2 = {3.0f, 4.0f}; // Setting a value for plg::vec2 reference - u8Vec = {1, 2, 3}; // Setting values for plg::vector - c = L'Ⅴ'; - iVec = {1, 2, 3, 4}; +void MockFunc23(uint64_t &u64, plg::vec2 &v2, plg::vector &iVec, char16_t &c, float &f, int8_t &i8, + plg::vector &u8Vec) { + //std::cout << "MockFunc23 called with float: " << f << ", int8_t: " << static_cast(i8) << "\n"; + u64 = 50; // Setting a value for uint64_t reference + f = 1.5f; // Setting a value for float reference + i8 = -1; // Setting a value for int8_t reference + v2 = {3.0f, 4.0f}; // Setting a value for plg::vec2 reference + u8Vec = {1, 2, 3}; // Setting values for plg::vector + c = L'Ⅴ'; + iVec = {1, 2, 3, 4}; } // Mock implementations for 24 parameter functions -plg::mat4x4 MockFunc24(plg::vector& cVec, int64_t& i64, plg::vector& u8Vec, plg::vec4& v4, uint64_t& u64, plg::vector& pVec, double& d, plg::vector& vVec) { - //std::cout << "MockFunc24 called with int64_t: " << i64 << ", double: " << d << "\n"; - i64 = 64; // Setting a value for int64_t reference - d = 2.71; // Setting a value for double reference - v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference - cVec = {'a', 'b', 'c'}; // Setting values for plg::vector - u8Vec = {5, 6, 7}; // Setting values for plg::vector - pVec = {nullptr}; // Setting values for plg::vector - vVec = {reinterpret_cast(1), reinterpret_cast(1), reinterpret_cast(2), reinterpret_cast(2)}; // Setting values for plg::vector - u64 = 0xffffffff; - return {}; // Returning dummy plg::mat4x4 +plg::mat4x4 MockFunc24(plg::vector &cVec, int64_t &i64, plg::vector &u8Vec, plg::vec4 &v4, uint64_t &u64, + plg::vector &pVec, double &d, plg::vector &vVec) { + //std::cout << "MockFunc24 called with int64_t: " << i64 << ", double: " << d << "\n"; + i64 = 64; // Setting a value for int64_t reference + d = 2.71; // Setting a value for double reference + v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference + cVec = {'a', 'b', 'c'}; // Setting values for plg::vector + u8Vec = {5, 6, 7}; // Setting values for plg::vector + pVec = {nullptr}; // Setting values for plg::vector + vVec = { + reinterpret_cast(1), reinterpret_cast(1), reinterpret_cast(2), + reinterpret_cast(2) + }; // Setting values for plg::vector + u64 = 0xffffffff; + return {}; // Returning dummy plg::mat4x4 } // Mock implementations for 25 parameter functions -double MockFunc25(int32_t& i32, plg::vector& pVec, bool& flag, uint8_t& u8, plg::string& s, plg::vec3& v3, int64_t& i64, plg::vec4& v4, uint16_t& u16) { - //std::cout << "MockFunc25 called with bool: " << flag << ", int32_t: " << i32 << "\n"; - flag = false; // Setting a value for bool reference - i32 = 100; // Setting a value for int32_t reference - u8 = 250; // Setting a value for uint8_t reference - v3 = {1.0f, 2.0f, 3.0f}; // Setting a value for plg::vec3 reference - v4 = {4.0f, 5.0f, 6.0f, 7.0f}; // Setting a value for plg::vec4 reference - s = "MockFunc25"; // Setting a value for string reference - pVec = {nullptr}; // Setting values for plg::vector - i64 = 1337; +double MockFunc25(int32_t &i32, plg::vector &pVec, bool &flag, uint8_t &u8, plg::string &s, plg::vec3 &v3, + int64_t &i64, plg::vec4 &v4, uint16_t &u16) { + //std::cout << "MockFunc25 called with bool: " << flag << ", int32_t: " << i32 << "\n"; + flag = false; // Setting a value for bool reference + i32 = 100; // Setting a value for int32_t reference + u8 = 250; // Setting a value for uint8_t reference + v3 = {1.0f, 2.0f, 3.0f}; // Setting a value for plg::vec3 reference + v4 = {4.0f, 5.0f, 6.0f, 7.0f}; // Setting a value for plg::vec4 reference + s = "MockFunc25"; // Setting a value for string reference + pVec = {nullptr}; // Setting values for plg::vector + i64 = 1337; u16 = 64222; - return 0.0; // Returning dummy double + return 0.0; // Returning dummy double } // Mock implementations for 26 parameter functions -char MockFunc26(char16_t& c, plg::vec2& v2, plg::mat4x4& m, plg::vector& fVec, int16_t& i16, uint64_t& u64, uint32_t& u32, plg::vector& u16Vec, void*& p, bool& flag) { - //std::cout << "MockFunc26 called with char16: " << c << ", bool: " << flag << "\n"; - c = u'Z'; // Setting a value for char16_t reference - flag = true; // Setting a value for bool reference - v2 = {2.0f, 3.0f}; // Setting a value for plg::vec2 reference +char MockFunc26(char16_t &c, plg::vec2 &v2, plg::mat4x4 &m, plg::vector &fVec, int16_t &i16, uint64_t &u64, + uint32_t &u32, plg::vector &u16Vec, void *&p, bool &flag) { + //std::cout << "MockFunc26 called with char16: " << c << ", bool: " << flag << "\n"; + c = u'Z'; // Setting a value for char16_t reference + flag = true; // Setting a value for bool reference + v2 = {2.0f, 3.0f}; // Setting a value for plg::vec2 reference m = { - 0.9f, 0.2f, 0.4f, 0.8f, // Row 0 - 0.1f, 1.0f, 0.6f, 0.3f, // Row 1 - 0.7f, 0.5f, 0.2f, 0.9f, // Row 2 - 0.3f, 0.4f, 1.5f, 0.1f // Row 3 + 0.9f, 0.2f, 0.4f, 0.8f, // Row 0 + 0.1f, 1.0f, 0.6f, 0.3f, // Row 1 + 0.7f, 0.5f, 0.2f, 0.9f, // Row 2 + 0.3f, 0.4f, 1.5f, 0.1f // Row 3 }; // Setting a value for plg::mat4x4 reference - fVec = {1.1f, 2.2f}; // Setting values for plg::vector - u64 = 64; // Setting a value for uint64_t reference - u32 = 32; // Setting a value for uint32_t reference - u16Vec = {100, 200}; // Setting values for plg::vector - i16 = 332; - p = reinterpret_cast(0xDEADBEAFDEADBEAF); - return 'A'; // Returning dummy char + fVec = {1.1f, 2.2f}; // Setting values for plg::vector + u64 = 64; // Setting a value for uint64_t reference + u32 = 32; // Setting a value for uint32_t reference + u16Vec = {100, 200}; // Setting values for plg::vector + i16 = 332; + p = reinterpret_cast(0xDEADBEAFDEADBEAF); + return 'A'; // Returning dummy char } // Mock implementations for 27 parameter functions -uint8_t MockFunc27(float& f, plg::vec3& v3, void*& p, plg::vec2& v2, plg::vector& i16Vec, plg::mat4x4& m, bool& flag, plg::vec4& v4, int8_t& i8, int32_t& i32, plg::vector& u8Vec) { - //std::cout << "MockFunc27 called with uint8_t: " << static_cast(u8) << ", bool: " << flag << "\n"; +uint8_t MockFunc27(float &f, plg::vec3 &v3, void *&p, plg::vec2 &v2, plg::vector &i16Vec, plg::mat4x4 &m, + bool &flag, plg::vec4 &v4, int8_t &i8, int32_t &i32, plg::vector &u8Vec) { + //std::cout << "MockFunc27 called with uint8_t: " << static_cast(u8) << ", bool: " << flag << "\n"; f = 1.0; v3 = {-1.0f, -2.0f, -3.0f}; p = reinterpret_cast(0xDEADBEAFDEADBEAF); v2 = {-111.0f, 111.0f}; - i16Vec = { 1, 2, 3, 4 }; + i16Vec = {1, 2, 3, 4}; m = { - 1.0f, 0.5f, 0.3f, 0.7f, // Row 0 - 0.8f, 1.2f, 0.6f, 0.9f, // Row 1 - 1.5f, 1.1f, 0.4f, 0.2f, // Row 2 - 0.3f, 0.9f, 0.7f, 1.0f // Row 3 + 1.0f, 0.5f, 0.3f, 0.7f, // Row 0 + 0.8f, 1.2f, 0.6f, 0.9f, // Row 1 + 1.5f, 1.1f, 0.4f, 0.2f, // Row 2 + 0.3f, 0.9f, 0.7f, 1.0f // Row 3 }; flag = true; v4 = {1.0f, 2.0f, 3.0f, 4.0f}; i8 = 111; i32 = 30; - u8Vec = { 0, 0, 0, 0, 0, 0, 1, 0 }; - return 0; // Returning dummy int + u8Vec = {0, 0, 0, 0, 0, 0, 1, 0}; + return 0; // Returning dummy int } // Mock implementations for 28 parameter functions -plg::string MockFunc28(void*& ptr, uint16_t& u16, plg::vector& u32Vec, plg::mat4x4& m, float& f, plg::vec4& v4, plg::string& str, plg::vector& u64Vec, int64_t& i64, bool& b, plg::vec3& vec3, plg::vector& fVec) { - //std::cout << "MockFunc28 called with float: " << f << "\n"; +plg::string MockFunc28(void *&ptr, uint16_t &u16, plg::vector &u32Vec, plg::mat4x4 &m, float &f, + plg::vec4 &v4, plg::string &str, plg::vector &u64Vec, int64_t &i64, bool &b, + plg::vec3 &vec3, plg::vector &fVec) { + //std::cout << "MockFunc28 called with float: " << f << "\n"; ptr = nullptr; u16 = 65500; - u32Vec = { 1, 2, 3, 4, 5, 7 }; + u32Vec = {1, 2, 3, 4, 5, 7}; m = { - 1.4f, 0.7f, 0.2f, 0.5f, // Row 0 - 0.3f, 1.1f, 0.6f, 0.8f, // Row 1 - 0.9f, 0.4f, 1.3f, 0.1f, // Row 2 - 0.6f, 0.2f, 0.7f, 1.0f // Row 3 + 1.4f, 0.7f, 0.2f, 0.5f, // Row 0 + 0.3f, 1.1f, 0.6f, 0.8f, // Row 1 + 0.9f, 0.4f, 1.3f, 0.1f, // Row 2 + 0.6f, 0.2f, 0.7f, 1.0f // Row 3 }; f = 5.5f; // Setting a value for float reference - v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference + v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference u64Vec = {1, 2}; // Setting values for plg::vector i64 = 834748377834; b = true, - vec3 = {10, 20, 30}; // Setting values for plg::vector - str = "MockFunc28"; // Setting a value for string reference - fVec = {1.0f, -1000.0f, 2000.0f }; - return str; // Returning dummy string + vec3 = {10, 20, 30}; // Setting values for plg::vector + str = "MockFunc28"; // Setting a value for string reference + fVec = {1.0f, -1000.0f, 2000.0f}; + return str; // Returning dummy string } // Mock implementations for 29 parameter functions -plg::vector MockFunc29(plg::vec4& v4, int32_t& i32, plg::vector& iVec, double& d, bool& flag, int8_t& i8, plg::vector& u16Vec, float& f, plg::string& s, plg::mat4x4& m, uint64_t& u64, plg::vec3& v3, plg::vector& i64Vec) { - //std::cout << "MockFunc29 called with int32_t: " << i32 << ", bool: " << flag << "\n"; - i32 = 30; // Setting a value for int32_t reference - flag = true; // Setting a value for bool reference - v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference - d = 3.14; // Setting a value for double reference - i8 = 8; // Setting a value for int8_t reference - u16Vec = {100, 200}; // Setting values for plg::vector - f = 1.5f; // Setting a value for float reference - s = "MockFunc29"; // Setting a value for string reference +plg::vector MockFunc29(plg::vec4 &v4, int32_t &i32, plg::vector &iVec, double &d, bool &flag, + int8_t &i8, plg::vector &u16Vec, float &f, plg::string &s, plg::mat4x4 &m, + uint64_t &u64, plg::vec3 &v3, plg::vector &i64Vec) { + //std::cout << "MockFunc29 called with int32_t: " << i32 << ", bool: " << flag << "\n"; + i32 = 30; // Setting a value for int32_t reference + flag = true; // Setting a value for bool reference + v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference + d = 3.14; // Setting a value for double reference + i8 = 8; // Setting a value for int8_t reference + u16Vec = {100, 200}; // Setting values for plg::vector + f = 1.5f; // Setting a value for float reference + s = "MockFunc29"; // Setting a value for string reference m = { - 0.4f, 1.0f, 0.6f, 0.3f, // Row 0 - 1.2f, 0.8f, 0.5f, 0.9f, // Row 1 - 0.7f, 0.3f, 1.4f, 0.6f, // Row 2 - 0.1f, 0.9f, 0.8f, 1.3f // Row 3 + 0.4f, 1.0f, 0.6f, 0.3f, // Row 0 + 1.2f, 0.8f, 0.5f, 0.9f, // Row 1 + 0.7f, 0.3f, 1.4f, 0.6f, // Row 2 + 0.1f, 0.9f, 0.8f, 1.3f // Row 3 }; // Setting a value for plg::mat4x4 reference - u64 = 64; // Setting a value for uint64_t reference - v3 = {1.0f, 2.0f, 3.0f}; // Setting a value for plg::vec3 reference - i64Vec = {1, 2, 3}; // Setting values for plg::vector - iVec = {127, 126, 125}; - return {"Example", "MockFunc29"}; // Returning dummy vector of strings + u64 = 64; // Setting a value for uint64_t reference + v3 = {1.0f, 2.0f, 3.0f}; // Setting a value for plg::vec3 reference + i64Vec = {1, 2, 3}; // Setting values for plg::vector + iVec = {127, 126, 125}; + return {"Example", "MockFunc29"}; // Returning dummy vector of strings } // Mock implementations for 30 parameter functions -int32_t MockFunc30(void*& p, plg::vec4& v4, int64_t& i64, plg::vector& uVec, bool& flag, plg::string& s, plg::vec3& v3, plg::vector& u8Vec, float& f, plg::vec2& v2, plg::mat4x4& m, int8_t& i8, plg::vector& vVec, double& d) { - //std::cout << "MockFunc30 called with int64_t: " << i64 << ", bool: " << flag << "\n"; - flag = false; // Setting a value for bool reference - f = 1.1f; // Setting a value for float reference - i64 = 1000; // Setting a value for int64_t reference - v2 = {3.0f, 4.0f}; // Setting a value for plg::vec2 reference - v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference - s = "MockFunc30"; // Setting a value for string reference - p = nullptr; // Setting a value for void* reference - uVec = {100, 200}; // Setting values for plg::vector +int32_t MockFunc30(void *&p, plg::vec4 &v4, int64_t &i64, plg::vector &uVec, bool &flag, plg::string &s, + plg::vec3 &v3, plg::vector &u8Vec, float &f, plg::vec2 &v2, plg::mat4x4 &m, int8_t &i8, + plg::vector &vVec, double &d) { + //std::cout << "MockFunc30 called with int64_t: " << i64 << ", bool: " << flag << "\n"; + flag = false; // Setting a value for bool reference + f = 1.1f; // Setting a value for float reference + i64 = 1000; // Setting a value for int64_t reference + v2 = {3.0f, 4.0f}; // Setting a value for plg::vec2 reference + v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference + s = "MockFunc30"; // Setting a value for string reference + p = nullptr; // Setting a value for void* reference + uVec = {100, 200}; // Setting values for plg::vector m = { - 0.5f, 0.3f, 1.0f, 0.7f, // Row 0 - 1.1f, 0.9f, 0.6f, 0.4f, // Row 1 - 0.2f, 0.8f, 1.5f, 0.3f, // Row 2 - 0.7f, 0.4f, 0.9f, 1.0f // Row 3 + 0.5f, 0.3f, 1.0f, 0.7f, // Row 0 + 1.1f, 0.9f, 0.6f, 0.4f, // Row 1 + 0.2f, 0.8f, 1.5f, 0.3f, // Row 2 + 0.7f, 0.4f, 0.9f, 1.0f // Row 3 }; // Setting a value for plg::mat4x4 reference - i8 = 8; // Setting a value for int8_t reference - vVec = {1.0f, 1.0f, 2.0f, 2.0f}; // Setting values for plg::vector - d = 2.718; // Setting a value for double reference - v3 = { 1, 2, 3 }; - u8Vec = { 255, 0, 255, 200, 100, 200 }; - return 42; // Returning dummy int32_t + i8 = 8; // Setting a value for int8_t reference + vVec = {1.0f, 1.0f, 2.0f, 2.0f}; // Setting values for plg::vector + d = 2.718; // Setting a value for double reference + v3 = {1, 2, 3}; + u8Vec = {255, 0, 255, 200, 100, 200}; + return 42; // Returning dummy int32_t } // Mock implementations for 31 parameter functions -plg::vec3 MockFunc31(char& c, uint32_t& u32, plg::vector& uVec, plg::vec4& v4, plg::string& s, bool& flag, int64_t& i64, plg::vec2& v2, int8_t& i8, uint16_t& u16, plg::vector& iVec, plg::mat4x4& m, plg::vec3& v3, float& f, plg::vector& v4Vec) { - //std::cout << "MockFunc31 called with uint32_t: " << u32 << ", bool: " << flag << "\n"; - u32 = 12345; // Setting a value for uint32_t reference - flag = true; // Setting a value for bool reference - v3 = {1.0f, 2.0f, 3.0f}; // Setting a value for plg::vec3 reference - c = 'C'; // Setting a value for char reference - v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference - s = "MockFunc31"; // Setting a value for string reference - i64 = 123456789; // Setting a value for int64_t reference - v2 = {5.0f, 6.0f}; // Setting a value for plg::vec2 reference - i8 = 7; // Setting a value for int8_t reference - u16 = 255; // Setting a value for uint16_t reference - iVec = {1, 2}; // Setting values for plg::vector +plg::vec3 MockFunc31(char &c, uint32_t &u32, plg::vector &uVec, plg::vec4 &v4, plg::string &s, bool &flag, + int64_t &i64, plg::vec2 &v2, int8_t &i8, uint16_t &u16, plg::vector &iVec, plg::mat4x4 &m, + plg::vec3 &v3, float &f, plg::vector &v4Vec) { + //std::cout << "MockFunc31 called with uint32_t: " << u32 << ", bool: " << flag << "\n"; + u32 = 12345; // Setting a value for uint32_t reference + flag = true; // Setting a value for bool reference + v3 = {1.0f, 2.0f, 3.0f}; // Setting a value for plg::vec3 reference + c = 'C'; // Setting a value for char reference + v4 = {1.0f, 2.0f, 3.0f, 4.0f}; // Setting a value for plg::vec4 reference + s = "MockFunc31"; // Setting a value for string reference + i64 = 123456789; // Setting a value for int64_t reference + v2 = {5.0f, 6.0f}; // Setting a value for plg::vec2 reference + i8 = 7; // Setting a value for int8_t reference + u16 = 255; // Setting a value for uint16_t reference + iVec = {1, 2}; // Setting values for plg::vector m = { - 0.8f, 0.5f, 1.2f, 0.3f, // Row 0 - 1.0f, 0.7f, 0.4f, 0.6f, // Row 1 - 0.9f, 0.2f, 0.5f, 1.4f, // Row 2 - 0.6f, 0.8f, 1.1f, 0.7f // Row 3 + 0.8f, 0.5f, 1.2f, 0.3f, // Row 0 + 1.0f, 0.7f, 0.4f, 0.6f, // Row 1 + 0.9f, 0.2f, 0.5f, 1.4f, // Row 2 + 0.6f, 0.8f, 1.1f, 0.7f // Row 3 }; // Setting a value for plg::mat4x4 reference - v4Vec = {1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0}; // Setting values for plg::vector - uVec = { 1, 2, 3, 4, 5 }; - f = -1.0f; - return {1.0f, 1.5f, 3.0f}; // Returning dummy plg::vec3 + v4Vec = {1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0}; // Setting values for plg::vector + uVec = {1, 2, 3, 4, 5}; + f = -1.0f; + return {1.0f, 1.5f, 3.0f}; // Returning dummy plg::vec3 } // Mock implementations for 32 parameter functions -double MockFunc32(int32_t& i32, uint16_t& u16, plg::vector& iVec, plg::vec4& v4, void*& p, plg::vector& uVec, plg::mat4x4& m, uint64_t& u64, plg::string& s, int64_t& i64, plg::vec2& v2, plg::vector& u8Vec, bool& flag, plg::vec3& v3, uint8_t& u8, plg::vector& cVec) { - //std::cout << "MockFunc32 called with int32_t: " << i32 << ", uint16_t: " << u16 << "\n"; - i32 = 42; // Setting a value for int32_t reference - u16 = 255; // Setting a value for uint16_t reference - flag = false; // Setting a value for bool reference - v2 = {2.5f, 3.5f}; // Setting a value for plg::vec2 reference - u8Vec = { 1, 2, 3, 4, 5, 9 }; - v4 = {4.0f, 5.0f, 6.0f, 7.0f}; // Setting a value for plg::vec4 reference - s = "MockFunc32"; // Setting a value for string reference - p = nullptr; // Setting a value for void* reference +double MockFunc32(int32_t &i32, uint16_t &u16, plg::vector &iVec, plg::vec4 &v4, void *&p, + plg::vector &uVec, plg::mat4x4 &m, uint64_t &u64, plg::string &s, int64_t &i64, + plg::vec2 &v2, plg::vector &u8Vec, bool &flag, plg::vec3 &v3, uint8_t &u8, + plg::vector &cVec) { + //std::cout << "MockFunc32 called with int32_t: " << i32 << ", uint16_t: " << u16 << "\n"; + i32 = 42; // Setting a value for int32_t reference + u16 = 255; // Setting a value for uint16_t reference + flag = false; // Setting a value for bool reference + v2 = {2.5f, 3.5f}; // Setting a value for plg::vec2 reference + u8Vec = {1, 2, 3, 4, 5, 9}; + v4 = {4.0f, 5.0f, 6.0f, 7.0f}; // Setting a value for plg::vec4 reference + s = "MockFunc32"; // Setting a value for string reference + p = nullptr; // Setting a value for void* reference m = { - 1.0f, 0.4f, 0.3f, 0.9f, // Row 0 - 0.7f, 1.2f, 0.5f, 0.8f, // Row 1 - 0.2f, 0.6f, 1.1f, 0.4f, // Row 2 - 0.9f, 0.3f, 0.8f, 1.5f // Row 3 + 1.0f, 0.4f, 0.3f, 0.9f, // Row 0 + 0.7f, 1.2f, 0.5f, 0.8f, // Row 1 + 0.2f, 0.6f, 1.1f, 0.4f, // Row 2 + 0.9f, 0.3f, 0.8f, 1.5f // Row 3 }; // Setting a value for plg::mat4x4 reference - u64 = 123456789; // Setting a value for uint64_t reference - uVec = {100, 200}; // Setting values for plg::vector - i64 = 1000; // Setting a value for int64_t reference - v3 = {0.0f, 0.0f, 0.0f}; // Setting a value for plg::vec3 reference - u8 = 8; // Setting a value for uint8_t reference - cVec = {u'a', u'b', u'c'}; // Setting values for plg::vector - iVec = { 0, 1 }; - return 1.0; // Returning dummy double + u64 = 123456789; // Setting a value for uint64_t reference + uVec = {100, 200}; // Setting values for plg::vector + i64 = 1000; // Setting a value for int64_t reference + v3 = {0.0f, 0.0f, 0.0f}; // Setting a value for plg::vec3 reference + u8 = 8; // Setting a value for uint8_t reference + cVec = {u'a', u'b', u'c'}; // Setting values for plg::vector + iVec = {0, 1}; + return 1.0; // Returning dummy double } // Mock implementations for 1 parameter functions -void MockFunc33(plg::any& variant) { +void MockFunc33(plg::any &variant) { variant = "MockFunc33"; } // Mock implementations for enum parameters functions -plg::vector MockFuncEnum(cross_call_master::Example p1, plg::vector& p2) { - p2 = { cross_call_master::Example::First, cross_call_master::Example::Second, cross_call_master::Example::Third }; +plg::vector MockFuncEnum(cross_call_master::Example p1, + plg::vector &p2) { + p2 = {cross_call_master::Example::First, cross_call_master::Example::Second, cross_call_master::Example::Third}; return {p1, cross_call_master::Example::Forth}; } extern "C" -PLUGIN_API void ReverseCall(const plg::string& test) { - static std::unordered_map tests { - {"NoParamReturnVoid", []() { +PLUGIN_API void ReverseCall(const plg::string &test) { + static std::unordered_map tests{ + { + "NoParamReturnVoid", []() { cross_call_master::NoParamReturnVoidCallback(); - }}, - {"NoParamReturnBool", []() { + } + }, + { + "NoParamReturnBool", []() { const auto result = cross_call_master::NoParamReturnBoolCallback(); - cross_call_master::ReverseReturn(result == true ? "true" : (result == false ? "false" : "")); - }}, - {"NoParamReturnChar8", []() { + cross_call_master::ReverseReturn(result == true + ? "true" + : (result == false ? "false" : "")); + } + }, + { + "NoParamReturnChar8", []() { const auto result = cross_call_master::NoParamReturnChar8Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnChar16", []() { + } + }, + { + "NoParamReturnChar16", []() { const auto result = cross_call_master::NoParamReturnChar16Callback(); cross_call_master::ReverseReturn(std::format("{}", static_cast(result))); - }}, - {"NoParamReturnInt8", []() { + } + }, + { + "NoParamReturnInt8", []() { const auto result = cross_call_master::NoParamReturnInt8Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnInt16", []() { + } + }, + { + "NoParamReturnInt16", []() { const auto result = cross_call_master::NoParamReturnInt16Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnInt32", []() { + } + }, + { + "NoParamReturnInt32", []() { const auto result = cross_call_master::NoParamReturnInt32Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnInt64", []() { + } + }, + { + "NoParamReturnInt64", []() { const auto result = cross_call_master::NoParamReturnInt64Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnUInt8", []() { + } + }, + { + "NoParamReturnUInt8", []() { const auto result = cross_call_master::NoParamReturnUInt8Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnUInt16", []() { + } + }, + { + "NoParamReturnUInt16", []() { const auto result = cross_call_master::NoParamReturnUInt16Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnUInt32", []() { + } + }, + { + "NoParamReturnUInt32", []() { const auto result = cross_call_master::NoParamReturnUInt32Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnUInt64", []() { + } + }, + { + "NoParamReturnUInt64", []() { const auto result = cross_call_master::NoParamReturnUInt64Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnPointer", []() { + } + }, + { + "NoParamReturnPointer", []() { const auto result = cross_call_master::NoParamReturnPointerCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnFloat", []() { + } + }, + { + "NoParamReturnFloat", []() { const auto result = cross_call_master::NoParamReturnFloatCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnDouble", []() { + } + }, + { + "NoParamReturnDouble", []() { const auto result = cross_call_master::NoParamReturnDoubleCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnFunction", []() { + } + }, + { + "NoParamReturnFunction", []() { const auto result = cross_call_master::NoParamReturnFunctionCallback(); cross_call_master::ReverseReturn(result ? std::format("{}", result()) : ""); - }}, - {"NoParamReturnString", []() { + } + }, + { + "NoParamReturnString", []() { const auto result = cross_call_master::NoParamReturnStringCallback(); cross_call_master::ReverseReturn(result); - }}, - {"NoParamReturnAny", []() { + } + }, + { + "NoParamReturnAny", []() { const auto result = cross_call_master::NoParamReturnAnyCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayBool", []() { + } + }, + { + "NoParamReturnArrayBool", []() { const auto result = cross_call_master::NoParamReturnArrayBoolCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayChar8", []() { + } + }, + { + "NoParamReturnArrayChar8", []() { const auto result = cross_call_master::NoParamReturnArrayChar8Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayChar16", []() { + } + }, + { + "NoParamReturnArrayChar16", []() { const auto result = cross_call_master::NoParamReturnArrayChar16Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayInt8", []() { + } + }, + { + "NoParamReturnArrayInt8", []() { const auto result = cross_call_master::NoParamReturnArrayInt8Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayInt16", []() { + } + }, + { + "NoParamReturnArrayInt16", []() { const auto result = cross_call_master::NoParamReturnArrayInt16Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayInt32", []() { + } + }, + { + "NoParamReturnArrayInt32", []() { const auto result = cross_call_master::NoParamReturnArrayInt32Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayInt64", []() { + } + }, + { + "NoParamReturnArrayInt64", []() { const auto result = cross_call_master::NoParamReturnArrayInt64Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayUInt8", []() { + } + }, + { + "NoParamReturnArrayUInt8", []() { const auto result = cross_call_master::NoParamReturnArrayUInt8Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayUInt16", []() { + } + }, + { + "NoParamReturnArrayUInt16", []() { const auto result = cross_call_master::NoParamReturnArrayUInt16Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayUInt32", []() { + } + }, + { + "NoParamReturnArrayUInt32", []() { const auto result = cross_call_master::NoParamReturnArrayUInt32Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayUInt64", []() { + } + }, + { + "NoParamReturnArrayUInt64", []() { const auto result = cross_call_master::NoParamReturnArrayUInt64Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayPointer", []() { + } + }, + { + "NoParamReturnArrayPointer", []() { const auto result = cross_call_master::NoParamReturnArrayPointerCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayFloat", []() { + } + }, + { + "NoParamReturnArrayFloat", []() { const auto result = cross_call_master::NoParamReturnArrayFloatCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayDouble", []() { + } + }, + { + "NoParamReturnArrayDouble", []() { const auto result = cross_call_master::NoParamReturnArrayDoubleCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayString", []() { + } + }, + { + "NoParamReturnArrayString", []() { const auto result = cross_call_master::NoParamReturnArrayStringCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayAny", []() { + } + }, + { + "NoParamReturnArrayAny", []() { const auto result = cross_call_master::NoParamReturnArrayAnyCallback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayVector2", []() { + } + }, + { + "NoParamReturnArrayVector2", []() { const auto result = cross_call_master::NoParamReturnArrayVector2Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayVector3", []() { + } + }, + { + "NoParamReturnArrayVector3", []() { const auto result = cross_call_master::NoParamReturnArrayVector3Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayVector4", []() { + } + }, + { + "NoParamReturnArrayVector4", []() { const auto result = cross_call_master::NoParamReturnArrayVector4Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnArrayMatrix4x4", []() { + } + }, + { + "NoParamReturnArrayMatrix4x4", []() { const auto result = cross_call_master::NoParamReturnArrayMatrix4x4Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnVector2", []() { + } + }, + { + "NoParamReturnVector2", []() { const auto result = cross_call_master::NoParamReturnVector2Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnVector3", []() { + } + }, + { + "NoParamReturnVector3", []() { const auto result = cross_call_master::NoParamReturnVector3Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnVector4", []() { + } + }, + { + "NoParamReturnVector4", []() { const auto result = cross_call_master::NoParamReturnVector4Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"NoParamReturnMatrix4x4", []() { + } + }, + { + "NoParamReturnMatrix4x4", []() { const auto result = cross_call_master::NoParamReturnMatrix4x4Callback(); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"Param1", []() { + } + }, + { + "Param1", []() { cross_call_master::Param1Callback(999); - }}, - {"Param2", []() { + } + }, + { + "Param2", []() { cross_call_master::Param2Callback(888, 9.9f); - }}, - {"Param3", []() { + } + }, + { + "Param3", []() { cross_call_master::Param3Callback(777, 8.8f, 9.8765); - }}, - {"Param4", []() { + } + }, + { + "Param4", []() { cross_call_master::Param4Callback(666, 7.7f, 8.7659, {100.1f, 200.2f, 300.3f, 400.4f}); - }}, - {"Param5", []() { + } + }, + { + "Param5", []() { cross_call_master::Param5Callback(555, 6.6f, 7.6598, {-105.1f, -205.2f, -305.3f, -405.4f}, {}); - }}, - {"Param6", []() { - cross_call_master::Param6Callback(444, 5.5f, 6.5987, {110.1f, 210.2f, 310.3f, 410.4f}, {90000, -100, 20000}, 'A'); - }}, - {"Param7", []() { - cross_call_master::Param7Callback(333, 4.4f, 5.9876, {-115.1f, -215.2f, -315.3f, -415.4f}, {800000, 30000, -4000000}, 'B', "red gold"); - }}, - {"Param8", []() { - cross_call_master::Param8Callback(222, 3.3f, 1.2345, {120.1f, 220.2f, 320.3f, 420.4f}, {7000000, 5000000, -600000000}, 'C', "blue ice", u'Z'); - }}, - {"Param9", []() { - cross_call_master::Param9Callback(111, 2.2f, 5.1234, {-125.1f, -225.2f, -325.3f, -425.4f}, {60000000, -700000000, 80000000000}, 'D', "pink metal", u'Y', -100); - }}, - {"Param10", []() { - cross_call_master::Param10Callback(1234, 1.1f, 4.5123, {130.1f, 230.2f, 330.3f, 430.4f}, {500000000, 90000000000, 1000000000000}, 'E', "green wood", u'X', -200, reinterpret_cast(0xabebaLL)); - }}, - {"ParamRef1", []() { + } + }, + { + "Param6", []() { + cross_call_master::Param6Callback(444, 5.5f, 6.5987, {110.1f, 210.2f, 310.3f, 410.4f}, + {90000, -100, 20000}, 'A'); + } + }, + { + "Param7", []() { + cross_call_master::Param7Callback(333, 4.4f, 5.9876, {-115.1f, -215.2f, -315.3f, -415.4f}, + {800000, 30000, -4000000}, 'B', "red gold"); + } + }, + { + "Param8", []() { + cross_call_master::Param8Callback(222, 3.3f, 1.2345, {120.1f, 220.2f, 320.3f, 420.4f}, + {7000000, 5000000, -600000000}, 'C', "blue ice", u'Z'); + } + }, + { + "Param9", []() { + cross_call_master::Param9Callback(111, 2.2f, 5.1234, {-125.1f, -225.2f, -325.3f, -425.4f}, + {60000000, -700000000, 80000000000}, 'D', "pink metal", u'Y', -100); + } + }, + { + "Param10", []() { + cross_call_master::Param10Callback(1234, 1.1f, 4.5123, {130.1f, 230.2f, 330.3f, 430.4f}, + {500000000, 90000000000, 1000000000000}, 'E', "green wood", u'X', + -200, reinterpret_cast(0xabebaLL)); + } + }, + { + "ParamRef1", []() { int32_t a{}; cross_call_master::ParamRef1Callback(a); cross_call_master::ReverseReturn(std::format("{}", a)); - }}, - {"ParamRef2", []() { + } + }, + { + "ParamRef2", []() { int32_t a{}; float b{}; cross_call_master::ParamRef2Callback(a, b); cross_call_master::ReverseReturn(std::format("{}|{}", a, b)); - }}, - {"ParamRef3", []() { + } + }, + { + "ParamRef3", []() { int32_t a{}; float b{}; double c{}; cross_call_master::ParamRef3Callback(a, b, c); cross_call_master::ReverseReturn(std::format("{}|{}|{}", a, b, c)); - }}, - {"ParamRef4", []() { + } + }, + { + "ParamRef4", []() { int32_t a{}; float b{}; double c{}; plg::vec4 d{}; cross_call_master::ParamRef4Callback(a, b, c, d); cross_call_master::ReverseReturn(std::format("{}|{}|{}|{}", a, b, c, d)); - }}, - {"ParamRef5", []() { + } + }, + { + "ParamRef5", []() { int32_t a{}; float b{}; double c{}; @@ -1969,8 +2192,10 @@ PLUGIN_API void ReverseCall(const plg::string& test) { plg::vector e{}; cross_call_master::ParamRef5Callback(a, b, c, d, e); cross_call_master::ReverseReturn(std::format("{}|{}|{}|{}|{}", a, b, c, d, e)); - }}, - {"ParamRef6", []() { + } + }, + { + "ParamRef6", []() { int32_t a{}; float b{}; double c{}; @@ -1980,8 +2205,10 @@ PLUGIN_API void ReverseCall(const plg::string& test) { cross_call_master::ParamRef6Callback(a, b, c, d, e, f); cross_call_master::ReverseReturn(std::format("{}|{}|{}|{}|{}|{}", a, b, c, d, e, static_cast(f))); - }}, - {"ParamRef7", []() { + } + }, + { + "ParamRef7", []() { int32_t a{}; float b{}; double c{}; @@ -1991,9 +2218,11 @@ PLUGIN_API void ReverseCall(const plg::string& test) { plg::string g{}; cross_call_master::ParamRef7Callback(a, b, c, d, e, f, g); cross_call_master::ReverseReturn(std::format("{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, - static_cast(f), g)); - }}, - {"ParamRef8", []() { + static_cast(f), g)); + } + }, + { + "ParamRef8", []() { int32_t a{}; float b{}; double c{}; @@ -2004,9 +2233,11 @@ PLUGIN_API void ReverseCall(const plg::string& test) { char16_t h{}; cross_call_master::ParamRef8Callback(a, b, c, d, e, f, g, h); cross_call_master::ReverseReturn(std::format("{}|{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, - static_cast(f), g, static_cast(h))); - }}, - {"ParamRef9", []() { + static_cast(f), g, static_cast(h))); + } + }, + { + "ParamRef9", []() { int32_t a{}; float b{}; double c{}; @@ -2018,9 +2249,11 @@ PLUGIN_API void ReverseCall(const plg::string& test) { int16_t k{}; cross_call_master::ParamRef9Callback(a, b, c, d, e, f, g, h, k); cross_call_master::ReverseReturn(std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, - static_cast(f), g, static_cast(h), k)); - }}, - {"ParamRef10", []() { + static_cast(f), g, static_cast(h), k)); + } + }, + { + "ParamRef10", []() { int32_t a{}; float b{}; double c{}; @@ -2030,12 +2263,15 @@ PLUGIN_API void ReverseCall(const plg::string& test) { plg::string g{}; char16_t h{}; int16_t k{}; - void* l{}; + void *l{}; cross_call_master::ParamRef10Callback(a, b, c, d, e, f, g, h, k, l); cross_call_master::ReverseReturn(std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", a, b, c, d, e, - static_cast(f), g, static_cast(h), k, l)); - }}, - {"ParamRefArrays", []() { + static_cast(f), g, static_cast(h), k, + l)); + } + }, + { + "ParamRefArrays", []() { plg::vector p1{true}; plg::vector p2{'A'}; plg::vector p3{u'A'}; @@ -2047,342 +2283,515 @@ PLUGIN_API void ReverseCall(const plg::string& test) { plg::vector p9{0}; plg::vector p10{0}; plg::vector p11{0}; - plg::vector p12{nullptr}; + plg::vector p12{nullptr}; plg::vector p13{1.0f}; plg::vector p14{1.0}; plg::vector p15{"Hi"}; - cross_call_master::ParamRefVectorsCallback(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); + cross_call_master::ParamRefVectorsCallback(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, + p15); cross_call_master::ReverseReturn(std::format("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15)); - }}, - {"ParamAllPrimitives", []() { - const auto result = cross_call_master::ParamAllPrimitivesCallback(true, '%', u'☢', -1, -1000, -1000000, -1000000000000LL, 200, 50000, 3000000000LL, 9999999999LL, - reinterpret_cast(0xfedcbaabcdefLL), 0.001f, 987654.456789); + } + }, + { + "ParamAllPrimitives", []() { + const auto result = cross_call_master::ParamAllPrimitivesCallback( + true, '%', u'☢', -1, -1000, -1000000, -1000000000000LL, 200, 50000, 3000000000LL, 9999999999LL, + reinterpret_cast(0xfedcbaabcdefLL), 0.001f, 987654.456789); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"ParamEnum", []() { + } + }, + { + "ParamEnum", []() { cross_call_master::Example p1 = cross_call_master::Example::Forth; - plg::vector p2{cross_call_master::Example::First, cross_call_master::Example::Second, cross_call_master::Example::Third}; + plg::vector p2{ + cross_call_master::Example::First, cross_call_master::Example::Second, + cross_call_master::Example::Third + }; const auto result = cross_call_master::ParamEnumCallback(p1, p2); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"ParamEnumRef", []() { + } + }, + { + "ParamEnumRef", []() { cross_call_master::Example p1 = cross_call_master::Example::First; - plg::vector p2{cross_call_master::Example::First, cross_call_master::Example::First, cross_call_master::Example::Second}; + plg::vector p2{ + cross_call_master::Example::First, cross_call_master::Example::First, + cross_call_master::Example::Second + }; const auto result = cross_call_master::ParamEnumRefCallback(p1, p2); cross_call_master::ReverseReturn(std::format("{}|{}|{}", result, p1, p2)); - }}, - {"ParamVariant", []() { + } + }, + { + "ParamVariant", []() { plg::any p1 = "my custom string with enough chars"; - plg::vector p2{'X', u'☢', -1, -1000, -1000000, -1000000000000LL, 200, 50000, 3000000000LL, 9999999999LL, - reinterpret_cast(0xfedcbaabcdefLL), 0.001f, 987654.456789}; + plg::vector p2{ + 'X', u'☢', -1, -1000, -1000000, -1000000000000LL, 200, 50000, 3000000000LL, 9999999999LL, + reinterpret_cast(0xfedcbaabcdefLL), 0.001f, 987654.456789 + }; cross_call_master::ParamVariantCallback(p1, p2); - }}, - {"ParamVariantRef", []() { + } + }, + { + "ParamVariantRef", []() { plg::any p1 = "my custom string with enough chars"; - plg::vector p2{'X', u'☢', -1, -1000, -1000000, -1000000000000LL, 200, 50000, 3000000000LL, 9999999999LL, - reinterpret_cast(0xfedcbaabcdefLL), 0.001f, 987654.456789}; + plg::vector p2{ + 'X', u'☢', -1, -1000, -1000000, -1000000000000LL, 200, 50000, 3000000000LL, 9999999999LL, + reinterpret_cast(0xfedcbaabcdefLL), 0.001f, 987654.456789 + }; cross_call_master::ParamVariantRefCallback(p1, p2); cross_call_master::ReverseReturn(std::format("{}|{}", p1, p2)); - }}, - {"CallFuncVoid", []() { + } + }, + { + "CallFuncVoid", []() { cross_call_master::CallFuncVoidCallback(&MockVoid); - }}, - {"CallFuncBool", []() { + } + }, + { + "CallFuncBool", []() { const auto result = cross_call_master::CallFuncBoolCallback(&MockBool); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncChar8", []() { + } + }, + { + "CallFuncChar8", []() { const auto result = cross_call_master::CallFuncChar8Callback(&MockChar8); cross_call_master::ReverseReturn(std::format("{}", static_cast(result))); - }}, - {"CallFuncChar16", []() { + } + }, + { + "CallFuncChar16", []() { const auto result = cross_call_master::CallFuncChar16Callback(&MockChar16); cross_call_master::ReverseReturn(std::format("{}", static_cast(result))); - }}, - {"CallFuncInt8", []() { + } + }, + { + "CallFuncInt8", []() { const auto result = cross_call_master::CallFuncInt8Callback(&MockInt8); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncInt16", []() { + } + }, + { + "CallFuncInt16", []() { const auto result = cross_call_master::CallFuncInt16Callback(&MockInt16); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncInt32", []() { + } + }, + { + "CallFuncInt32", []() { const auto result = cross_call_master::CallFuncInt32Callback(&MockInt32); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncInt64", []() { + } + }, + { + "CallFuncInt64", []() { const auto result = cross_call_master::CallFuncInt64Callback(&MockInt64); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncUInt8", []() { + } + }, + { + "CallFuncUInt8", []() { const auto result = cross_call_master::CallFuncUInt8Callback(&MockUInt8); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncUInt16", []() { + } + }, + { + "CallFuncUInt16", []() { const auto result = cross_call_master::CallFuncUInt16Callback(&MockUInt16); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncUInt32", []() { + } + }, + { + "CallFuncUInt32", []() { const auto result = cross_call_master::CallFuncUInt32Callback(&MockUInt32); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncUInt64", []() { + } + }, + { + "CallFuncUInt64", []() { const auto result = cross_call_master::CallFuncUInt64Callback(&MockUInt64); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncPtr", []() { + } + }, + { + "CallFuncPtr", []() { const auto result = cross_call_master::CallFuncPtrCallback(&MockPtr); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncFloat", []() { + } + }, + { + "CallFuncFloat", []() { const auto result = cross_call_master::CallFuncFloatCallback(&MockFloat); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncDouble", []() { + } + }, + { + "CallFuncDouble", []() { const auto result = cross_call_master::CallFuncDoubleCallback(&MockDouble); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncString", []() { + } + }, + { + "CallFuncString", []() { const auto result = cross_call_master::CallFuncStringCallback(&MockString); cross_call_master::ReverseReturn(result); - }}, - {"CallFuncAny", []() { + } + }, + { + "CallFuncAny", []() { auto result = cross_call_master::CallFuncAnyCallback(&MockAny); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncBoolVector", []() { + } + }, + { + "CallFuncBoolVector", []() { const auto result = cross_call_master::CallFuncBoolVectorCallback(&MockBoolVector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncChar8Vector", []() { + } + }, + { + "CallFuncChar8Vector", []() { const auto result = cross_call_master::CallFuncChar8VectorCallback(&MockChar8Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncChar16Vector", []() { + } + }, + { + "CallFuncChar16Vector", []() { const auto result = cross_call_master::CallFuncChar16VectorCallback(&MockChar16Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncInt8Vector", []() { + } + }, + { + "CallFuncInt8Vector", []() { const auto result = cross_call_master::CallFuncInt8VectorCallback(&MockInt8Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncInt16Vector", []() { + } + }, + { + "CallFuncInt16Vector", []() { const auto result = cross_call_master::CallFuncInt16VectorCallback(&MockInt16Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncInt32Vector", []() { + } + }, + { + "CallFuncInt32Vector", []() { const auto result = cross_call_master::CallFuncInt32VectorCallback(&MockInt32Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncInt64Vector", []() { + } + }, + { + "CallFuncInt64Vector", []() { const auto result = cross_call_master::CallFuncInt64VectorCallback(&MockInt64Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncUInt8Vector", []() { + } + }, + { + "CallFuncUInt8Vector", []() { const auto result = cross_call_master::CallFuncUInt8VectorCallback(&MockUInt8Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncUInt16Vector", []() { + } + }, + { + "CallFuncUInt16Vector", []() { const auto result = cross_call_master::CallFuncUInt16VectorCallback(&MockUInt16Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncUInt32Vector", []() { + } + }, + { + "CallFuncUInt32Vector", []() { const auto result = cross_call_master::CallFuncUInt32VectorCallback(&MockUInt32Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncUInt64Vector", []() { + } + }, + { + "CallFuncUInt64Vector", []() { const auto result = cross_call_master::CallFuncUInt64VectorCallback(&MockUInt64Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncPtrVector", []() { + } + }, + { + "CallFuncPtrVector", []() { const auto result = cross_call_master::CallFuncPtrVectorCallback(&MockPtrVector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncFloatVector", []() { + } + }, + { + "CallFuncFloatVector", []() { const auto result = cross_call_master::CallFuncFloatVectorCallback(&MockFloatVector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncDoubleVector", []() { + } + }, + { + "CallFuncDoubleVector", []() { const auto result = cross_call_master::CallFuncDoubleVectorCallback(&MockDoubleVector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncStringVector", []() { + } + }, + { + "CallFuncStringVector", []() { const auto result = cross_call_master::CallFuncStringVectorCallback(&MockStringVector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncAnyVector", []() { + } + }, + { + "CallFuncAnyVector", []() { const auto result = cross_call_master::CallFuncAnyVectorCallback(&MockAnyVector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncVec2Vector", []() { + } + }, + { + "CallFuncVec2Vector", []() { const auto result = cross_call_master::CallFuncVec2VectorCallback(&MockVec2Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncVec3Vector", []() { + } + }, + { + "CallFuncVec3Vector", []() { const auto result = cross_call_master::CallFuncVec3VectorCallback(&MockVec3Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncVec4Vector", []() { + } + }, + { + "CallFuncVec4Vector", []() { const auto result = cross_call_master::CallFuncVec4VectorCallback(&MockVec4Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncMat4x4Vector", []() { + } + }, + { + "CallFuncMat4x4Vector", []() { const auto result = cross_call_master::CallFuncMat4x4VectorCallback(&MockMat4x4Vector); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncVec2", []() { + } + }, + { + "CallFuncVec2", []() { const auto result = cross_call_master::CallFuncVec2Callback(&MockVec2); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncVec3", []() { + } + }, + { + "CallFuncVec3", []() { const auto result = cross_call_master::CallFuncVec3Callback(&MockVec3); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncVec4", []() { + } + }, + { + "CallFuncVec4", []() { const auto result = cross_call_master::CallFuncVec4Callback(&MockVec4); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFuncMat4x4", []() { + } + }, + { + "CallFuncMat4x4", []() { const auto result = cross_call_master::CallFuncMat4x4Callback(&MockMat4x4); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc1", []() { + } + }, + { + "CallFunc1", []() { const auto result = cross_call_master::CallFunc1Callback(&MockFunc1); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc2", []() { + } + }, + { + "CallFunc2", []() { const auto result = cross_call_master::CallFunc2Callback(&MockFunc2); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc3", []() { + } + }, + { + "CallFunc3", []() { cross_call_master::CallFunc3Callback(&MockFunc3); - }}, - {"CallFunc4", []() { + } + }, + { + "CallFunc4", []() { const auto result = cross_call_master::CallFunc4Callback(&MockFunc4); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc5", []() { + } + }, + { + "CallFunc5", []() { const auto result = cross_call_master::CallFunc5Callback(&MockFunc5); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc6", []() { + } + }, + { + "CallFunc6", []() { const auto result = cross_call_master::CallFunc6Callback(&MockFunc6); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc7", []() { + } + }, + { + "CallFunc7", []() { const auto result = cross_call_master::CallFunc7Callback(&MockFunc7); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc8", []() { + } + }, + { + "CallFunc8", []() { const auto result = cross_call_master::CallFunc8Callback(&MockFunc8); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc9", []() { + } + }, + { + "CallFunc9", []() { cross_call_master::CallFunc9Callback(&MockFunc9); - }}, - {"CallFunc10", []() { + } + }, + { + "CallFunc10", []() { const auto result = cross_call_master::CallFunc10Callback(&MockFunc10); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc11", []() { + } + }, + { + "CallFunc11", []() { const auto result = cross_call_master::CallFunc11Callback(&MockFunc11); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc12", []() { + } + }, + { + "CallFunc12", []() { const auto result = cross_call_master::CallFunc12Callback(&MockFunc12); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc13", []() { + } + }, + { + "CallFunc13", []() { const auto result = cross_call_master::CallFunc13Callback(&MockFunc13); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc14", []() { + } + }, + { + "CallFunc14", []() { const auto result = cross_call_master::CallFunc14Callback(&MockFunc14); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc15", []() { + } + }, + { + "CallFunc15", []() { const auto result = cross_call_master::CallFunc15Callback(&MockFunc15); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc16", []() { + } + }, + { + "CallFunc16", []() { const auto result = cross_call_master::CallFunc16Callback(&MockFunc16); cross_call_master::ReverseReturn(std::format("{}", result)); - }}, - {"CallFunc17", []() { + } + }, + { + "CallFunc17", []() { const auto result = cross_call_master::CallFunc17Callback(&MockFunc17); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc18", []() { + } + }, + { + "CallFunc18", []() { const auto result = cross_call_master::CallFunc18Callback(&MockFunc18); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc19", []() { + } + }, + { + "CallFunc19", []() { const auto result = cross_call_master::CallFunc19Callback(&MockFunc19); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc20", []() { + } + }, + { + "CallFunc20", []() { const auto result = cross_call_master::CallFunc20Callback(&MockFunc20); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc21", []() { + } + }, + { + "CallFunc21", []() { const auto result = cross_call_master::CallFunc21Callback(&MockFunc21); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc22", []() { + } + }, + { + "CallFunc22", []() { const auto result = cross_call_master::CallFunc22Callback(&MockFunc22); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc23", []() { + } + }, + { + "CallFunc23", []() { const auto result = cross_call_master::CallFunc23Callback(&MockFunc23); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc24", []() { + } + }, + { + "CallFunc24", []() { const auto result = cross_call_master::CallFunc24Callback(&MockFunc24); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc25", []() { + } + }, + { + "CallFunc25", []() { const auto result = cross_call_master::CallFunc25Callback(&MockFunc25); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc26", []() { + } + }, + { + "CallFunc26", []() { const auto result = cross_call_master::CallFunc26Callback(&MockFunc26); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc27", []() { + } + }, + { + "CallFunc27", []() { const auto result = cross_call_master::CallFunc27Callback(&MockFunc27); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc28", []() { + } + }, + { + "CallFunc28", []() { const auto result = cross_call_master::CallFunc28Callback(&MockFunc28); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc29", []() { + } + }, + { + "CallFunc29", []() { const auto result = cross_call_master::CallFunc29Callback(&MockFunc29); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc30", []() { + } + }, + { + "CallFunc30", []() { const auto result = cross_call_master::CallFunc30Callback(&MockFunc30); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc31", []() { + } + }, + { + "CallFunc31", []() { const auto result = cross_call_master::CallFunc31Callback(&MockFunc31); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc32", []() { + } + }, + { + "CallFunc32", []() { const auto result = cross_call_master::CallFunc32Callback(&MockFunc32); cross_call_master::ReverseReturn(result); - }}, - {"CallFunc33", []() { + } + }, + { + "CallFunc33", []() { const auto result = cross_call_master::CallFunc33Callback(&MockFunc33); cross_call_master::ReverseReturn(result); - }}, - {"CallFuncEnum", []() { + } + }, + { + "CallFuncEnum", []() { const auto result = cross_call_master::CallFuncEnumCallback(&MockFuncEnum); cross_call_master::ReverseReturn(result); - }} + } + } }; auto it = tests.find(test); if (it != tests.end()) { diff --git a/test/example_plugin/.clang-format b/test/example_plugin/.clang-format new file mode 100644 index 0000000..36e77ba --- /dev/null +++ b/test/example_plugin/.clang-format @@ -0,0 +1,92 @@ +BasedOnStyle: Mozilla +Language: Cpp +Standard: c++20 + +AccessModifierOffset: "-4" +AlignAfterOpenBracket: BlockIndent +AlignEscapedNewlinesLeft: "false" +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: "false" +AllowShortCaseLabelsOnASingleLine: "false" +AllowShortFunctionsOnASingleLine: "false" +AllowShortIfStatementsOnASingleLine: "false" +AllowShortLoopsOnASingleLine: "false" +AlwaysBreakTemplateDeclarations: "true" +BreakAfterReturnType: ExceptShortType +BinPackArguments: false +BinPackParameters: false +BreakAfterAttributes: Leave +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: "true" +BreakConstructorInitializersBeforeComma: "true" +BreakStringLiterals: "false" +ColumnLimit: "100" +ConstructorInitializerAllOnOneLineOrOnePerLine: "false" +ConstructorInitializerIndentWidth: "4" +ContinuationIndentWidth: "4" +Cpp11BracedListStyle: "false" +DerivePointerAlignment: "false" +DisableFormat: "false" +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: Always +ExperimentalAutoDetectBinPacking: "true" +IncludeBlocks: Regroup +IncludeCategories: + - Regex: <[^.]+> + Priority: -3 + - Regex: + Priority: -1 + - Regex: <.+> + Priority: -2 + - Regex: '"plugify/.+"' + Priority: 0 + - Regex: '"glaze/.+"' + Priority: 0 + - Regex: '"asmjit/.+"' + Priority: 0 + - Regex: '".+/.+"' + Priority: 1 + - Regex: '".+"' + Priority: 2 +IndentCaseLabels: "true" +IndentWidth: "4" +IndentWrappedFunctionNames: "false" +InsertBraces: true # Experimental +KeepEmptyLinesAtTheStartOfBlocks: "false" +MaxEmptyLinesToKeep: "2" +NamespaceIndentation: All +ObjCBlockIndentWidth: "4" +ObjCSpaceAfterProperty: "false" +ObjCSpaceBeforeProtocolList: "false" +PackConstructorInitializers: Never +PenaltyBreakAssignment: 100000 +PenaltyBreakBeforeFirstCallParameter: 0 +PenaltyBreakComment: 10 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakTemplateDeclaration: 0 +PenaltyExcessCharacter: 10 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 10 +PointerAlignment: Left +ReferenceAlignment: Left +QualifierAlignment: Custom # Experimental +QualifierOrder: [inline, static, constexpr, const, volatile, type] +ReflowComments: "true" +SeparateDefinitionBlocks: Always +SortIncludes: CaseInsensitive +SortUsingDeclarations: Never +SpaceAfterCStyleCast: "true" +SpaceAfterTemplateKeyword: "true" +SpaceBeforeAssignmentOperators: "true" +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: "false" +SpacesBeforeTrailingComments: "2" +SpacesInAngles: "false" +SpacesInCStyleCastParentheses: "false" +SpacesInContainerLiterals: "false" +SpacesInParentheses: "false" +SpacesInSquareBrackets: "false" +TabWidth: "4" +UseTab: "ForIndentation" \ No newline at end of file diff --git a/test/example_plugin/.clang-tidy b/test/example_plugin/.clang-tidy new file mode 100644 index 0000000..09fd31b --- /dev/null +++ b/test/example_plugin/.clang-tidy @@ -0,0 +1,159 @@ +# Generated from CLion Inspection settings +--- +Checks: '-*, +bugprone-argument-comment, +bugprone-assert-side-effect, +bugprone-bad-signal-to-kill-thread, +bugprone-branch-clone, +bugprone-copy-constructor-init, +bugprone-dangling-handle, +bugprone-dynamic-static-initializers, +bugprone-fold-init-type, +bugprone-forward-declaration-namespace, +bugprone-forwarding-reference-overload, +bugprone-inaccurate-erase, +bugprone-incorrect-roundings, +bugprone-integer-division, +bugprone-lambda-function-name, +bugprone-macro-parentheses, +bugprone-macro-repeated-side-effects, +bugprone-misplaced-operator-in-strlen-in-alloc, +bugprone-misplaced-pointer-arithmetic-in-alloc, +bugprone-misplaced-widening-cast, +bugprone-move-forwarding-reference, +bugprone-multiple-statement-macro, +bugprone-no-escape, +bugprone-parent-virtual-call, +bugprone-posix-return, +bugprone-reserved-identifier, +bugprone-sizeof-container, +bugprone-sizeof-expression, +bugprone-spuriously-wake-up-functions, +bugprone-string-constructor, +bugprone-string-integer-assignment, +bugprone-string-literal-with-embedded-nul, +bugprone-suspicious-enum-usage, +bugprone-suspicious-include, +bugprone-suspicious-memset-usage, +bugprone-suspicious-missing-comma, +bugprone-suspicious-semicolon, +bugprone-suspicious-string-compare, +bugprone-suspicious-memory-comparison, +bugprone-suspicious-realloc-usage, +bugprone-swapped-arguments, +bugprone-terminating-continue, +bugprone-throw-keyword-missing, +bugprone-too-small-loop-variable, +bugprone-undefined-memory-manipulation, +bugprone-undelegated-constructor, +bugprone-unhandled-self-assignment, +bugprone-unused-raii, +bugprone-unused-return-value, +bugprone-use-after-move, +bugprone-virtual-near-miss, +cert-dcl21-cpp, +cert-dcl58-cpp, +cert-err34-c, +cert-err52-cpp, +cert-err60-cpp, +cert-flp30-c, +cert-msc50-cpp, +cert-msc51-cpp, +cert-str34-c, +cppcoreguidelines-interfaces-global-init, +cppcoreguidelines-narrowing-conversions, +cppcoreguidelines-pro-type-member-init, +cppcoreguidelines-pro-type-static-cast-downcast, +cppcoreguidelines-slicing, +google-default-arguments, +google-explicit-constructor, +google-runtime-operator, +hicpp-exception-baseclass, +hicpp-multiway-paths-covered, +misc-misplaced-const, +misc-new-delete-overloads, +misc-no-recursion, +misc-non-copyable-objects, +misc-throw-by-value-catch-by-reference, +misc-unconventional-assign-operator, +misc-uniqueptr-reset-release, +modernize-avoid-bind, +modernize-concat-nested-namespaces, +modernize-deprecated-headers, +modernize-deprecated-ios-base-aliases, +modernize-loop-convert, +modernize-make-shared, +modernize-make-unique, +modernize-pass-by-value, +modernize-raw-string-literal, +modernize-redundant-void-arg, +modernize-replace-auto-ptr, +modernize-replace-disallow-copy-and-assign-macro, +modernize-replace-random-shuffle, +modernize-return-braced-init-list, +modernize-shrink-to-fit, +modernize-unary-static-assert, +modernize-use-auto, +modernize-use-bool-literals, +modernize-use-emplace, +modernize-use-equals-default, +modernize-use-equals-delete, +modernize-use-nodiscard, +modernize-use-noexcept, +modernize-use-nullptr, +modernize-use-override, +modernize-use-transparent-functors, +modernize-use-uncaught-exceptions, +mpi-buffer-deref, +mpi-type-mismatch, +openmp-use-default-none, +performance-faster-string-find, +performance-for-range-copy, +performance-implicit-conversion-in-loop, +performance-inefficient-algorithm, +performance-inefficient-string-concatenation, +performance-inefficient-vector-operation, +performance-move-const-arg, +performance-move-constructor-init, +performance-no-automatic-move, +performance-noexcept-move-constructor, +performance-trivially-destructible, +performance-type-promotion-in-math-fn, +performance-unnecessary-copy-initialization, +performance-unnecessary-value-param, +portability-simd-intrinsics, +readability-avoid-const-params-in-decls, +readability-const-return-type, +readability-container-size-empty, +readability-convert-member-functions-to-static, +readability-delete-null-pointer, +readability-deleted-default, +readability-inconsistent-declaration-parameter-name, +readability-make-member-function-const, +readability-misleading-indentation, +readability-misplaced-array-index, +readability-non-const-parameter, +readability-redundant-control-flow, +readability-redundant-declaration, +readability-redundant-function-ptr-dereference, +readability-redundant-smartptr-get, +readability-redundant-string-cstr, +readability-redundant-string-init, +readability-simplify-subscript-expr, +readability-static-accessed-through-instance, +readability-static-definition-in-anonymous-namespace, +readability-string-compare, +readability-uniqueptr-delete-release, +readability-use-anyofallof +readability-identifier-naming' +CheckOptions: + - key: readability-identifier-naming.FunctionCase + value: CamelCase + - key: readability-identifier-naming.MethodCase + value: CamelCase + - key: readability-identifier-naming.MemberCase + value: camelBack + - key: readability-identifier-naming.MemberPrefix + value: '_' + - key: readability-identifier-naming.PrivateMemberPrefix + value: '' \ No newline at end of file diff --git a/test/example_plugin/external/plugify/include/plg/enum.hpp b/test/example_plugin/external/plugify/include/plg/enum.hpp index 84f6d23..f8780e1 100644 --- a/test/example_plugin/external/plugify/include/plg/enum.hpp +++ b/test/example_plugin/external/plugify/include/plg/enum.hpp @@ -1,121 +1,130 @@ #pragma once +#include #include +#include #include #include -#include -#include #include "plg/macro.hpp" -// from https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ +// from +// https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ namespace plg { - constexpr auto ENUM_MIN_VALUE = -128; - constexpr auto ENUM_MAX_VALUE = 128; - - template - struct static_string { - constexpr static_string(std::string_view sv) noexcept { - std::copy(sv.begin(), sv.end(), content.begin()); - } - constexpr operator std::string_view() const noexcept { return { content.data(), N }; } - - private: - std::array content{}; - }; - - constexpr auto is_pretty(char ch) noexcept { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); - } - - constexpr auto pretty_name(std::string_view sv) noexcept { - for (std::size_t n = sv.size() - 1; n > 0; --n) { - if (!is_pretty(sv[n])) { - sv.remove_prefix(n + 1); - break; - } - } - return sv; - } - - template - constexpr auto n() noexcept { - #if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG - return pretty_name({ __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2 }); - #elif PLUGIFY_COMPILER_MSVC - return pretty_name({ __FUNCSIG__, sizeof(__FUNCSIG__) - 17 }); - #endif - } - - template - constexpr auto is_valid() { - [[maybe_unused]] constexpr E v = static_cast(V); - return !n().empty(); - } - - template - constexpr auto value(std::size_t v) { - return static_cast(ENUM_MIN_VALUE + static_cast(v)); - } - - template - constexpr auto count_values(const bool (&valid)[N]) { - std::size_t count = 0; - for (std::size_t n = 0; n < N; ++n) - if (valid[n]) ++count; - return count; - } - - template - constexpr auto values(std::index_sequence) noexcept { - constexpr bool valid[sizeof...(I)] = { is_valid(I)>()... }; - constexpr auto num_valid = count_values(valid); - static_assert(num_valid > 0, "no support for empty enums"); - - std::array values = {}; - for(std::size_t offset = 0, n = 0; n < num_valid; ++offset) { - if (valid[offset]) { - values[n] = value(offset); - ++n; - } - } - - return values; - } - - template - constexpr auto values() noexcept { - constexpr auto enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1; - return values(std::make_index_sequence({})); - } - - template - inline constexpr auto values_v = values(); - - template - constexpr auto enum_name() { - constexpr auto name = n(); - return static_string(name); - } - - template - inline constexpr auto enum_name_v = enum_name(); - - template - constexpr auto entries(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {{ values_v[I], enum_name_v[I]>}...} - }; - } - - template - inline constexpr auto entries_v = entries(std::make_index_sequence.size()>()); - - template - constexpr std::string_view enum_to_string(E value) { - for (const auto& [ key, name ]: entries_v) { - if (value == key) return name; - } - return {}; - } + constexpr auto ENUM_MIN_VALUE = -128; + constexpr auto ENUM_MAX_VALUE = 128; + + template + struct static_string { + constexpr static_string(std::string_view sv) noexcept { + std::copy(sv.begin(), sv.end(), content.begin()); + } + + constexpr operator std::string_view() const noexcept { + return { content.data(), N }; + } + + private: + std::array content{}; + }; + + constexpr auto is_pretty(char ch) noexcept { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); + } + + constexpr auto pretty_name(std::string_view sv) noexcept { + for (std::size_t n = sv.size() - 1; n > 0; --n) { + if (!is_pretty(sv[n])) { + sv.remove_prefix(n + 1); + break; + } + } + return sv; + } + + template + constexpr auto n() noexcept { +#if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG + return pretty_name({ __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2 }); +#elif PLUGIFY_COMPILER_MSVC + return pretty_name({ __FUNCSIG__, sizeof(__FUNCSIG__) - 17 }); +#endif + } + + template + constexpr auto is_valid() { + [[maybe_unused]] constexpr E v = static_cast(V); + return !n().empty(); + } + + template + constexpr auto value(std::size_t v) { + return static_cast(ENUM_MIN_VALUE + static_cast(v)); + } + + template + constexpr auto count_values(const bool (&valid)[N]) { + std::size_t count = 0; + for (std::size_t n = 0; n < N; ++n) { + if (valid[n]) { + ++count; + } + } + return count; + } + + template + constexpr auto values(std::index_sequence) noexcept { + constexpr bool valid[sizeof...(I)] = { is_valid(I)>()... }; + constexpr auto num_valid = count_values(valid); + static_assert(num_valid > 0, "no support for empty enums"); + + std::array values = {}; + for (std::size_t offset = 0, n = 0; n < num_valid; ++offset) { + if (valid[offset]) { + values[n] = value(offset); + ++n; + } + } + + return values; + } + + template + constexpr auto values() noexcept { + constexpr auto enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1; + return values(std::make_index_sequence({})); + } + + template + inline constexpr auto values_v = values(); + + template + constexpr auto enum_name() { + constexpr auto name = n(); + return static_string(name); + } + + template + inline constexpr auto enum_name_v = enum_name(); + + template + constexpr auto entries(std::index_sequence) noexcept { + return std::array, sizeof...(I)>{ + { { values_v[I], enum_name_v[I]> }... } + }; + } + + template + inline constexpr auto entries_v = entries(std::make_index_sequence.size()>()); + + template + constexpr std::string_view enum_to_string(E value) { + for (const auto& [key, name] : entries_v) { + if (value == key) { + return name; + } + } + return {}; + } } diff --git a/test/example_plugin/external/plugify/include/plg/flat_map.hpp b/test/example_plugin/external/plugify/include/plg/flat_map.hpp index 9912431..7b5f7b7 100644 --- a/test/example_plugin/external/plugify/include/plg/flat_map.hpp +++ b/test/example_plugin/external/plugify/include/plg/flat_map.hpp @@ -5,8 +5,8 @@ #ifdef __cpp_lib_flat_map #include namespace plg { - template> - using flat_map = std::flat_map; + template> + using flat_map = std::flat_map; } #else #include "plg/vector.hpp" diff --git a/test/example_plugin/external/plugify/include/plg/hash.hpp b/test/example_plugin/external/plugify/include/plg/hash.hpp index 98c9a27..296436a 100644 --- a/test/example_plugin/external/plugify/include/plg/hash.hpp +++ b/test/example_plugin/external/plugify/include/plg/hash.hpp @@ -15,29 +15,32 @@ namespace plg { }; struct string_hash { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup auto operator()(const char* txt) const { return std::hash{}(txt); } + auto operator()(std::string_view txt) const { return std::hash{}(txt); } + auto operator()(const std::string& txt) const { return std::hash{}(txt); } - auto operator()(const plg::string& txt) const { + + auto operator()(const plg::string& txt) const { return std::hash{}(txt); } }; struct case_insensitive_hash { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup - template + template auto operator()(const T& str_like) const noexcept { std::string_view str = str_like; - std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis + std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis for (char c : str) { hash ^= static_cast(std::tolower(static_cast(c))); hash *= 0x100000001b3; @@ -47,26 +50,29 @@ namespace plg { }; struct case_insensitive_equal { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup - template + template bool operator()(const T1& lhs_like, const T2& rhs_like) const noexcept { std::string_view lhs = lhs_like; std::string_view rhs = rhs_like; - if (lhs.size() != rhs.size()) + if (lhs.size() != rhs.size()) { return false; + } for (size_t i = 0; i < lhs.size(); ++i) { - if (std::tolower(static_cast(lhs[i])) != - std::tolower(static_cast(rhs[i]))) + if (std::tolower(static_cast(lhs[i])) + != std::tolower(static_cast(rhs[i]))) { return false; + } } return true; } }; - inline void hash_combine(size_t&) { } + inline void hash_combine(size_t&) { + } template inline void hash_combine(std::size_t& seed, const T& v) { @@ -78,15 +84,15 @@ namespace plg { template inline std::size_t hash_combine_all(const Ts&... args) { std::size_t seed = 0; - (hash_combine(seed, args), ...); // fold expression + (hash_combine(seed, args), ...); // fold expression return seed; } - template - struct pair_hash { - size_t operator()(std::pair const& p) const { - return hash_combine_all(p.first, p.second); - } + template + struct pair_hash { + size_t operator()(const std::pair& p) const { + return hash_combine_all(p.first, p.second); + } }; } diff --git a/test/example_plugin/external/plugify/include/plg/path.hpp b/test/example_plugin/external/plugify/include/plg/path.hpp index 61343f3..afc3d6e 100644 --- a/test/example_plugin/external/plugify/include/plg/path.hpp +++ b/test/example_plugin/external/plugify/include/plg/path.hpp @@ -1,14 +1,14 @@ #pragma once #include -#include #include +#include namespace plg { - using path_view = std::basic_string_view; - using path_string = std::filesystem::path::string_type; - using path_char = path_string::value_type; - using path_diff_t = path_string::difference_type; + using path_view = std::basic_string_view; + using path_string = std::filesystem::path::string_type; + using path_char = path_string::value_type; + using path_diff_t = path_string::difference_type; #if _WIN32 #define PLUGIFY_PATH_LITERAL(x) L##x @@ -16,37 +16,41 @@ namespace plg { #define PLUGIFY_PATH_LITERAL(x) x #endif - template - bool insensitive_equals(const path_char lhs, const path_char rhs) { - if constexpr (std::is_same_v) { - return std::towlower(lhs) == rhs; // NOLINT - } else { - return std::tolower(lhs) == rhs; - } - } - - inline bool insensitive_equals(const path_view lhs, const path_view rhs) { - return lhs.size() == rhs.size() && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); - } - - inline path_view extension_view(const std::filesystem::path& path) { - constexpr path_diff_t extension_size = 4; - if (!path.has_extension()) { return {}; } - const path_string& path_str = path.native(); - const auto offset = static_cast(path_str.size()) - extension_size; - if (offset <= 0) { return {}; } - return { path_str.cbegin() + offset, path_str.cend() }; - } - - inline bool has_extension(const std::filesystem::path& path, const path_view extension) { - return insensitive_equals(extension_view(path), extension); - } - - inline auto as_string(const std::filesystem::path& p) { + template + bool insensitive_equals(const path_char lhs, const path_char rhs) { + if constexpr (std::is_same_v) { + return std::towlower(lhs) == rhs; // NOLINT + } else { + return std::tolower(lhs) == rhs; + } + } + + inline bool insensitive_equals(const path_view lhs, const path_view rhs) { + return lhs.size() == rhs.size() + && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); + } + + inline path_view extension_view(const std::filesystem::path& path, size_t extension_size) { + if (!path.has_extension()) { + return {}; + } + const path_string& path_str = path.native(); + const auto offset = static_cast(path_str.size() - extension_size); + if (offset <= 0) { + return {}; + } + return { path_str.cbegin() + offset, path_str.cend() }; // NOLINT(*-dangling-handle) + } + + inline bool has_extension(const std::filesystem::path& path, const path_view extension) { + return insensitive_equals(extension_view(path, extension.size()), extension); + } + + inline auto as_string(const std::filesystem::path& p) { #if _WIN32 - return p.string(); // returns std::string by value + return p.string(); // returns std::string by value #else - return p.native(); // returns const std::string& + return p.native(); // returns const std::string& #endif - } + } } diff --git a/test/example_plugin/external/plugify/include/plg/string.hpp b/test/example_plugin/external/plugify/include/plg/string.hpp index 175bed2..830f168 100644 --- a/test/example_plugin/external/plugify/include/plg/string.hpp +++ b/test/example_plugin/external/plugify/include/plg/string.hpp @@ -19,6 +19,7 @@ #include // for std::numeric_limits #include // for std::to_chars + #include #include #include @@ -44,63 +45,63 @@ namespace plg { namespace detail { - template - concept is_allocator = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; - - template - concept is_char_traits = requires { - // Required type definitions - typename Traits::char_type; - typename Traits::int_type; - typename Traits::off_type; - typename Traits::pos_type; - typename Traits::state_type; - } && requires( - typename Traits::char_type c1, - typename Traits::char_type c2, - typename Traits::char_type& cr, - const typename Traits::char_type& ccr, - typename Traits::char_type* p, - const typename Traits::char_type* cp, - typename Traits::int_type i1, - typename Traits::int_type i2, - std::size_t n - ) { - // Character operations - { Traits::assign(cr, ccr) } -> std::same_as; - { Traits::eq(ccr, ccr) } -> std::convertible_to; - { Traits::lt(ccr, ccr) } -> std::convertible_to; - - // String operations - { Traits::compare(cp, cp, n) } -> std::convertible_to; - { Traits::length(cp) } -> std::convertible_to; - { Traits::find(cp, n, ccr) } -> std::convertible_to; - - // Memory operations - { Traits::move(p, cp, n) } -> std::same_as; - { Traits::copy(p, cp, n) } -> std::same_as; - { Traits::assign(p, n, c1) } -> std::same_as; - - // int_type operations - { Traits::not_eof(i1) } -> std::same_as; - { Traits::to_char_type(i1) } -> std::same_as; - { Traits::to_int_type(c1) } -> std::same_as; - { Traits::eq_int_type(i1, i2) } -> std::convertible_to; - { Traits::eof() } -> std::same_as; - }; + template + concept is_allocator = requires(Alloc& a, std::size_t n) { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; + + { std::allocator_traits::allocate(a, n) } + -> std::convertible_to::pointer>; + + requires requires(typename std::allocator_traits::pointer p) { + std::allocator_traits::deallocate(a, p, n); + }; + }; + + template + concept is_char_traits = requires { + // Required type definitions + typename Traits::char_type; + typename Traits::int_type; + typename Traits::off_type; + typename Traits::pos_type; + typename Traits::state_type; + } && requires( + typename Traits::char_type c1, + typename Traits::char_type c2, + typename Traits::char_type& cr, + const typename Traits::char_type& ccr, + typename Traits::char_type* p, + const typename Traits::char_type* cp, + typename Traits::int_type i1, + typename Traits::int_type i2, + std::size_t n + ) { + // Character operations + { Traits::assign(cr, ccr) } -> std::same_as; + { Traits::eq(ccr, ccr) } -> std::convertible_to; + { Traits::lt(ccr, ccr) } -> std::convertible_to; + + // String operations + { Traits::compare(cp, cp, n) } -> std::convertible_to; + { Traits::length(cp) } -> std::convertible_to; + { Traits::find(cp, n, ccr) } -> std::convertible_to; + + // Memory operations + { Traits::move(p, cp, n) } -> std::same_as; + { Traits::copy(p, cp, n) } -> std::same_as; + { Traits::assign(p, n, c1) } -> std::same_as; + + // int_type operations + { Traits::not_eof(i1) } -> std::same_as; + { Traits::to_char_type(i1) } -> std::same_as; + { Traits::to_int_type(c1) } -> std::same_as; + { Traits::eq_int_type(i1, i2) } -> std::convertible_to; + { Traits::eof() } -> std::same_as; + }; struct uninitialized_size_tag {}; @@ -909,9 +910,9 @@ namespace plg { // const size_type alignment = 16; // size_type m = allocator_traits::max_size(_allocator); // if (m <= std::numeric_limits::max() / 2) - // return m - alignment; + // return m - alignment; // else - //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; + //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; return (allocator_traits::max_size(_allocator) - 1) / 2; } @@ -1973,21 +1974,21 @@ namespace std { template std::ostream& operator<<(std::ostream& os, const plg::basic_string& str) { - os << str.c_str(); - return os; + os << str.c_str(); + return os; } #ifndef PLUGIFY_STRING_NO_STD_FORMAT #include namespace plg { - namespace detail { - // Concept to match string-like types including char* and const char* - template - concept is_string_like = requires(T v) { - { std::string_view(v) }; - }; - } + namespace detail { + // Concept to match string-like types including char* and const char* + template + concept is_string_like = requires(T v) { + { std::string_view(v) }; + }; + } template constexpr string join(const Range& range, std::string_view separator) { diff --git a/test/example_plugin/external/plugify/include/plg/vector.hpp b/test/example_plugin/external/plugify/include/plg/vector.hpp index 3ec8750..11aada1 100644 --- a/test/example_plugin/external/plugify/include/plg/vector.hpp +++ b/test/example_plugin/external/plugify/include/plg/vector.hpp @@ -27,30 +27,30 @@ #include "plg/allocator.hpp" namespace plg { - namespace detail { - template - concept is_alloc = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; + namespace detail { + template + concept is_alloc = requires(Alloc& a, std::size_t n) { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; + { std::allocator_traits::allocate(a, n) } + -> std::convertible_to::pointer>; - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; + requires requires(typename std::allocator_traits::pointer p) { + std::allocator_traits::deallocate(a, p, n); + }; + }; - struct initialized_value_tag {}; + struct initialized_value_tag {}; #if PLUGIFY_VECTOR_CONTAINERS_RANGES - template - concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; + template + concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; #endif - } // namespace detail + } // namespace detail template struct vector_iterator { diff --git a/test/example_plugin/external/plugify/include/plg/version.hpp b/test/example_plugin/external/plugify/include/plg/version.hpp index b12ac87..6089f12 100644 --- a/test/example_plugin/external/plugify/include/plg/version.hpp +++ b/test/example_plugin/external/plugify/include/plg/version.hpp @@ -24,1021 +24,1021 @@ // from https://github.com/Neargye/semver namespace plg { - namespace detail { - template - struct resize_uninitialized { - constexpr static auto resize(T& str, std::size_t size) -> std::void_t { - str.resize(size); - } - }; - - template - struct resize_uninitialized().__resize_default_init(42))>> { - constexpr static void resize(T& str, std::size_t size) { - str.__resize_default_init(size); - } - }; - - template - constexpr std::size_t length(Int n) noexcept { - std::size_t digits = 0; - do { - digits++; - n /= 10; - } while (n != 0); - return digits; - } - - template - constexpr OutputIt to_chars(OutputIt dest, Int n) noexcept { - do { - *(--dest) = static_cast('0' + (n % 10)); - n /= 10; - } while (n != 0); - return dest; - } - - enum struct prerelease_identifier_type { - numeric, - alphanumeric - }; - - struct prerelease_identifier { - prerelease_identifier_type type; - string identifier; - }; - - class version_parser; - class prerelease_comparator; - } - - template - class version { - friend class detail::version_parser; - friend class detail::prerelease_comparator; - - public: - constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase - constexpr version(const version&) = default; - constexpr version(version&&) = default; - constexpr ~version() = default; - - constexpr version& operator=(const version&) = default; - constexpr version& operator=(version&&) = default; - - constexpr I1 major() const noexcept { return major_; } - constexpr I2 minor() const noexcept { return minor_; } - constexpr I3 patch() const noexcept { return patch_; } - - constexpr const string& prerelease_tag() const { return prerelease_tag_; } - constexpr const string& build_metadata() const { return build_metadata_; } - - constexpr string to_string() const; - - private: - I1 major_ = 0; - I2 minor_ = 1; - I3 patch_ = 0; - string prerelease_tag_; - string build_metadata_; - - vector prerelease_identifiers; - - constexpr std::size_t length() const noexcept { - return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 - + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) - + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); - } - - constexpr void clear() noexcept { - major_ = 0; - minor_ = 1; - patch_ = 0; - - prerelease_tag_.clear(); - prerelease_identifiers.clear(); - build_metadata_.clear(); - } - }; - - template - constexpr string version::to_string() const { - string result; - detail::resize_uninitialized{}.resize(result, length()); - - auto it = result.end(); - if (!build_metadata_.empty()) { - it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); - *(--it) = '+'; - } - - if (!prerelease_tag_.empty()) { - it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); - *(--it) = '-'; - } - - it = detail::to_chars(it, patch_); - *(--it) = '.'; - - it = detail::to_chars(it, minor_); - *(--it) = '.'; - - it = detail::to_chars(it, major_); - - return result; - } + namespace detail { + template + struct resize_uninitialized { + constexpr static auto resize(T& str, std::size_t size) -> std::void_t { + str.resize(size); + } + }; + + template + struct resize_uninitialized().__resize_default_init(42))>> { + constexpr static void resize(T& str, std::size_t size) { + str.__resize_default_init(size); + } + }; + + template + constexpr std::size_t length(Int n) noexcept { + std::size_t digits = 0; + do { + digits++; + n /= 10; + } while (n != 0); + return digits; + } + + template + constexpr OutputIt to_chars(OutputIt dest, Int n) noexcept { + do { + *(--dest) = static_cast('0' + (n % 10)); + n /= 10; + } while (n != 0); + return dest; + } + + enum struct prerelease_identifier_type { + numeric, + alphanumeric + }; + + struct prerelease_identifier { + prerelease_identifier_type type; + string identifier; + }; + + class version_parser; + class prerelease_comparator; + } + + template + class version { + friend class detail::version_parser; + friend class detail::prerelease_comparator; + + public: + constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase + constexpr version(const version&) = default; + constexpr version(version&&) = default; + constexpr ~version() = default; + + constexpr version& operator=(const version&) = default; + constexpr version& operator=(version&&) = default; + + constexpr I1 major() const noexcept { return major_; } + constexpr I2 minor() const noexcept { return minor_; } + constexpr I3 patch() const noexcept { return patch_; } + + constexpr const string& prerelease_tag() const { return prerelease_tag_; } + constexpr const string& build_metadata() const { return build_metadata_; } + + constexpr string to_string() const; + + private: + I1 major_ = 0; + I2 minor_ = 1; + I3 patch_ = 0; + string prerelease_tag_; + string build_metadata_; + + vector prerelease_identifiers; + + constexpr std::size_t length() const noexcept { + return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 + + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) + + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); + } + + constexpr void clear() noexcept { + major_ = 0; + minor_ = 1; + patch_ = 0; + + prerelease_tag_.clear(); + prerelease_identifiers.clear(); + build_metadata_.clear(); + } + }; + + template + constexpr string version::to_string() const { + string result; + detail::resize_uninitialized{}.resize(result, length()); + + auto it = result.end(); + if (!build_metadata_.empty()) { + it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); + *(--it) = '+'; + } + + if (!prerelease_tag_.empty()) { + it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); + *(--it) = '-'; + } + + it = detail::to_chars(it, patch_); + *(--it) = '.'; + + it = detail::to_chars(it, minor_); + *(--it) = '.'; + + it = detail::to_chars(it, major_); + + return result; + } #if __has_include() - struct from_chars_result : std::from_chars_result { - [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } - }; + struct from_chars_result : std::from_chars_result { + [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } + }; #else - struct from_chars_result { - const char* ptr; - std::errc ec; + struct from_chars_result { + const char* ptr; + std::errc ec; - [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } - }; + [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } + }; #endif - enum class version_compare_option : std::uint8_t { - exclude_prerelease, - include_prerelease - }; - - namespace detail { - constexpr from_chars_result success(const char* ptr) noexcept { - return from_chars_result{ ptr, std::errc{} }; - } - - constexpr from_chars_result failure(const char* ptr, std::errc error_code = std::errc::invalid_argument) noexcept { - return from_chars_result{ ptr, error_code }; - } - - constexpr bool is_digit(char c) noexcept { - return c >= '0' && c <= '9'; - } - - constexpr bool is_letter(char c) noexcept { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); - } - - constexpr std::uint8_t to_digit(char c) noexcept { - return static_cast(c - '0'); - } - - constexpr char to_char(int i) noexcept { - return '0' + (char)i; - } - - template - constexpr bool cmp_less(T t, U u) noexcept - { - if constexpr (std::is_signed_v == std::is_signed_v) - return t < u; + enum class version_compare_option : std::uint8_t { + exclude_prerelease, + include_prerelease + }; + + namespace detail { + constexpr from_chars_result success(const char* ptr) noexcept { + return from_chars_result{ ptr, std::errc{} }; + } + + constexpr from_chars_result failure(const char* ptr, std::errc error_code = std::errc::invalid_argument) noexcept { + return from_chars_result{ ptr, error_code }; + } + + constexpr bool is_digit(char c) noexcept { + return c >= '0' && c <= '9'; + } + + constexpr bool is_letter(char c) noexcept { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + + constexpr std::uint8_t to_digit(char c) noexcept { + return static_cast(c - '0'); + } + + constexpr char to_char(int i) noexcept { + return '0' + (char)i; + } + + template + constexpr bool cmp_less(T t, U u) noexcept + { + if constexpr (std::is_signed_v == std::is_signed_v) + return t < u; else if constexpr (std::is_signed_v) - return t < 0 || std::make_unsigned_t(t) < u; + return t < 0 || std::make_unsigned_t(t) < u; else - return u >= 0 && t < std::make_unsigned_t(u); + return u >= 0 && t < std::make_unsigned_t(u); } - template - constexpr bool cmp_less_equal(T t, U u) noexcept - { - return !cmp_less(u, t); - } + template + constexpr bool cmp_less_equal(T t, U u) noexcept + { + return !cmp_less(u, t); + } - template - constexpr bool cmp_greater_equal(T t, U u) noexcept - { - return !cmp_less(t, u); - } + template + constexpr bool cmp_greater_equal(T t, U u) noexcept + { + return !cmp_less(t, u); + } - template - constexpr bool number_in_range(T t) noexcept { - return cmp_greater_equal(t, std::numeric_limits::min()) && cmp_less_equal(t, std::numeric_limits::max()); - } + template + constexpr bool number_in_range(T t) noexcept { + return cmp_greater_equal(t, std::numeric_limits::min()) && cmp_less_equal(t, std::numeric_limits::max()); + } - constexpr int compare(std::string_view lhs, std::string_view rhs) { + constexpr int compare(std::string_view lhs, std::string_view rhs) { #if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) - // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html - // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html - constexpr bool workaround = true; + // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html + constexpr bool workaround = true; #else - constexpr bool workaround = false; + constexpr bool workaround = false; #endif - if constexpr (workaround) { - const auto size = std::min(lhs.size(), rhs.size()); - for (std::size_t i = 0; i < size; ++i) { - if (lhs[i] < rhs[i]) { - return -1; - } else if (lhs[i] > rhs[i]) { - return 1; - } - } - - return static_cast(lhs.size() - rhs.size()); - } else { - return lhs.compare(rhs); - } - } - - constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { - // assume that strings don't have leading zeros (we've already checked it at parsing stage). - - if (lhs.size() != rhs.size()) { - return static_cast(lhs.size() - rhs.size()); - } - - for (std::size_t i = 0; i < lhs.size(); ++i) { - int a = lhs[i] - '0'; - int b = rhs[i] - '0'; - if (a != b) { - return a - b; - } - } - - return 0; - } - - enum class token_type : std::uint8_t { - eol, - space, - dot, - plus, - hyphen, - letter, - digit, - range_operator, - logical_or - }; - - enum class range_operator : std::uint8_t { - less, - less_or_equal, - greater, - greater_or_equal, - equal - }; - - struct token { - using value_t = std::variant; - token_type type; - value_t value; - const char* lexeme; - }; - - class token_stream { - public: - constexpr token_stream() = default; - constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} - - constexpr void push(const token& token) noexcept { - tokens_.push_back(token); - } - - constexpr token advance() noexcept { - const token token = get(current_); - ++current_; - return token; - } - - constexpr token peek(std::size_t k = 0) const noexcept { - return get(current_ + k); - } - - constexpr token previous() const noexcept { - return get(current_ - 1); - } - - constexpr bool advanceIfMatch(token& token, token_type type) noexcept { - if (get(current_).type != type) { - return false; - } - - token = advance(); - return true; - } - - constexpr bool advanceIfMatch(token_type type) noexcept { - token token; - return advanceIfMatch(token, type); - } - - constexpr bool consume(token_type type) noexcept { - return advance().type == type; - } - - constexpr bool check(token_type type) const noexcept { - return peek().type == type; - } - - private: - std::size_t current_ = 0; - vector tokens_; - - constexpr token get(std::size_t i) const noexcept { - return tokens_[i]; - } - }; - - class lexer { - public: - explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} - - constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { - from_chars_result result{ text_.data(), std::errc{} }; - - while (!is_eol()) { - result = scan_token(token_stream); - if (!result) { - return result; - } - } - - token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); - - return result; - } - - private: - std::string_view text_; - std::size_t current_pos_; - - constexpr from_chars_result scan_token(token_stream& stream) noexcept { - const char c = advance(); - - switch (c) { - case ' ': - add_token(stream, token_type::space); - break; - case '.': - add_token(stream, token_type::dot); - break; - case '-': - add_token(stream, token_type::hyphen); - break; - case '+': - add_token(stream, token_type::plus); - break; - case '|': - if (advanceIfMatch('|')) { - add_token(stream, token_type::logical_or); - break; - } - return failure(get_prev_symbol()); - case '<': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); - break; - case '>': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); - break; - case '=': - add_token(stream, token_type::range_operator, range_operator::equal); - break; - default: - if (is_digit(c)) { - add_token(stream, token_type::digit, to_digit(c)); - break; - } - else if (is_letter(c)) { - add_token(stream, token_type::letter, c); - break; - } - return failure(get_prev_symbol()); - } - - return success(get_prev_symbol()); - } - - constexpr void add_token(token_stream& stream, token_type type, token::value_t value = {}) noexcept { - const char* lexeme = get_prev_symbol(); - stream.push({ type, value, lexeme}); - } - - constexpr char advance() noexcept { - char c = text_[current_pos_]; - current_pos_ += 1; - return c; - } - - constexpr bool advanceIfMatch(char c) noexcept { - if (is_eol()) { - return false; - } - - if (text_[current_pos_] != c) { - return false; - } - - current_pos_ += 1; - - return true; - } - - constexpr const char* get_prev_symbol() const noexcept { - return text_.data() + current_pos_ - 1; - } - - constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } - }; - - class prerelease_comparator { - public: - template - [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { - if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { - return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); - } - - const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); - - for (std::size_t i = 0; i < count; ++i) { - const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); - if (compare_result != 0) { - return compare_result; - } - } - - return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); - } - - private: - [[nodiscard]] constexpr int compare_identifier(const prerelease_identifier& lhs, const prerelease_identifier& rhs) const noexcept { - if (lhs.type == prerelease_identifier_type::numeric && rhs.type == prerelease_identifier_type::numeric) { - return compare_numerically(lhs.identifier, rhs.identifier); - } else if (lhs.type == prerelease_identifier_type::alphanumeric && rhs.type == prerelease_identifier_type::alphanumeric) { - return detail::compare(lhs.identifier, rhs.identifier); - } - - return lhs.type == prerelease_identifier_type::alphanumeric ? 1 : -1; - } - }; - - class version_parser { - public: - constexpr explicit version_parser(token_stream& stream) : stream_{stream} { - } - - template - constexpr from_chars_result parse(version& out) noexcept { - out.clear(); - - from_chars_result result = parse_number(out.major_); - if (!result) { - return result; - } - - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); - } - - result = parse_number(out.minor_); - if (!result) { - return result; - } - - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); - } - - result = parse_number(out.patch_); - if (!result) { - return result; - } - - if (stream_.advanceIfMatch(token_type::hyphen)) { - result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); - if (!result) { - return result; - } - } - - if (stream_.advanceIfMatch(token_type::plus)) { - result = parse_build_metadata(out.build_metadata_); - if (!result) { - return result; - } - } - - return result; - } - - - private: - token_stream& stream_; - - template - constexpr from_chars_result parse_number(Int& out) { - token token = stream_.advance(); - - if (!is_digit(token)) { - return failure(token.lexeme); - } - - const auto first_digit = std::get(token.value); - std::uint64_t result = first_digit; - - if (first_digit == 0) { - out = static_cast(result); - return success(stream_.peek().lexeme); - } - - while (stream_.advanceIfMatch(token, token_type::digit)) { - result = result * 10 + std::get(token.value); - } - - if (detail::number_in_range(result)) { - out = static_cast(result); - return success(stream_.peek().lexeme); - } - - return failure(token.lexeme, std::errc::result_out_of_range); - } - - constexpr from_chars_result parse_prerelease_tag(string& out, vector& out_identifiers) { - string result; - - do { - if (!result.empty()) { - result.push_back('.'); - } - - string identifier; - if (const auto res = parse_prerelease_identifier(identifier); !res) { - return res; - } - - result.append(identifier); - out_identifiers.push_back(make_prerelease_identifier(identifier)); - - } while (stream_.advanceIfMatch(token_type::dot)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr from_chars_result parse_build_metadata(string& out) { - string result; - - do { - if (!result.empty()) { - result.push_back('.'); - } - - string identifier; - if (const auto res = parse_build_identifier(identifier); !res) { - return res; - } - - result.append(identifier); - } while (stream_.advanceIfMatch(token_type::dot)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr from_chars_result parse_prerelease_identifier(string& out) { - string result; - token token = stream_.advance(); - - do { - switch (token.type) { - case token_type::hyphen: - result.push_back('-'); - break; - case token_type::letter: - result.push_back(std::get(token.value)); - break; - case token_type::digit: - { - const auto digit = std::get(token.value); - - // numerical prerelease identifier doesn't allow leading zero - // 1.2.3-1.alpha is valid, - // 1.2.3-01b is valid as well, but - // 1.2.3-01.alpha is not valid - - // Only check for leading zero when digit is the first character of the - // prerelease identifier. - if (result.empty() && is_leading_zero(digit)) { - return failure(token.lexeme); - } - - result.push_back(to_char(digit)); - break; - } - default: - return failure(token.lexeme); - } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { - auto type = detail::prerelease_identifier_type::numeric; - for (char c : identifier) { - if (c == '-' || detail::is_letter(c)) { - type = detail::prerelease_identifier_type::alphanumeric; - break; - } - } - return detail::prerelease_identifier{ type, identifier }; - } - - constexpr from_chars_result parse_build_identifier(string& out) { - string result; - token token = stream_.advance(); - - do { - switch (token.type) { - case token_type::hyphen: - result.push_back('-'); - break; - case token_type::letter: - result.push_back(std::get(token.value)); - break; - case token_type::digit: - { - const auto digit = std::get(token.value); - result.push_back(to_char(digit)); - break; - } - default: - return failure(token.lexeme); - } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr bool is_leading_zero(int digit) noexcept { - if (digit != 0) { - return false; - } - - size_t k = 0; - int alpha_numerics = 0; - int digits = 0; - - while (true) { - const token token = stream_.peek(k); - - if (!is_alphanumeric(token)) { - break; - } - - ++alpha_numerics; - - if (is_digit(token)) { - ++digits; - } - - ++k; - } - - return digits > 0 && digits == alpha_numerics; - } - - constexpr bool is_digit(const token& token) const noexcept { - return token.type == token_type::digit; - } - - constexpr bool is_eol(const token& token) const noexcept { - return token.type == token_type::eol; - } - - constexpr bool is_alphanumeric(const token& token) const noexcept { - return token.type == token_type::hyphen || token.type == token_type::letter || token.type == token_type::digit; - } - }; - - template - constexpr int compare_prerelease(const version& lhs, const version& rhs) noexcept { - return prerelease_comparator{}.compare(lhs, rhs); - } - - template - constexpr int compare_parsed(const version& lhs, const version& rhs, version_compare_option compare_option) { - int result = lhs.major() - rhs.major(); - if (result != 0) { - return result; - } - - result = lhs.minor() - rhs.minor(); - if (result != 0) { - return result; - } - - result = lhs.patch() - rhs.patch(); - if (result != 0) { - return result; - } - - if (compare_option == version_compare_option::include_prerelease) { - result = detail::compare_prerelease(lhs, rhs); - } - - return result; - } - - template - constexpr from_chars_result parse(std::string_view str, version& out) { - token_stream token_stream; - from_chars_result result = lexer{ str }.scan_tokens(token_stream); - if (!result) { - return result; - } - - result = version_parser{ token_stream }.parse(out); - if (!result) { - return result; - } - - if (!token_stream.consume(token_type::eol)) { - return failure(token_stream.previous().lexeme); - } - - return success(token_stream.previous().lexeme); - } - - } // namespace semver::detail - - template - [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) == 0; - } - - template - [[nodiscard]] constexpr bool operator!=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) != 0; - } - - template - [[nodiscard]] constexpr bool operator>(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) > 0; - } - - template - [[nodiscard]] constexpr bool operator>=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) >= 0; - } - - template - [[nodiscard]] constexpr bool operator<(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) < 0; - } - - template - [[nodiscard]] constexpr bool operator<=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; - } + if constexpr (workaround) { + const auto size = std::min(lhs.size(), rhs.size()); + for (std::size_t i = 0; i < size; ++i) { + if (lhs[i] < rhs[i]) { + return -1; + } else if (lhs[i] > rhs[i]) { + return 1; + } + } + + return static_cast(lhs.size() - rhs.size()); + } else { + return lhs.compare(rhs); + } + } + + constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { + // assume that strings don't have leading zeros (we've already checked it at parsing stage). + + if (lhs.size() != rhs.size()) { + return static_cast(lhs.size() - rhs.size()); + } + + for (std::size_t i = 0; i < lhs.size(); ++i) { + int a = lhs[i] - '0'; + int b = rhs[i] - '0'; + if (a != b) { + return a - b; + } + } + + return 0; + } + + enum class token_type : std::uint8_t { + eol, + space, + dot, + plus, + hyphen, + letter, + digit, + range_operator, + logical_or + }; + + enum class range_operator : std::uint8_t { + less, + less_or_equal, + greater, + greater_or_equal, + equal + }; + + struct token { + using value_t = std::variant; + token_type type; + value_t value; + const char* lexeme; + }; + + class token_stream { + public: + constexpr token_stream() = default; + constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} + + constexpr void push(const token& token) noexcept { + tokens_.push_back(token); + } + + constexpr token advance() noexcept { + const token token = get(current_); + ++current_; + return token; + } + + constexpr token peek(std::size_t k = 0) const noexcept { + return get(current_ + k); + } + + constexpr token previous() const noexcept { + return get(current_ - 1); + } + + constexpr bool advanceIfMatch(token& token, token_type type) noexcept { + if (get(current_).type != type) { + return false; + } + + token = advance(); + return true; + } + + constexpr bool advanceIfMatch(token_type type) noexcept { + token token; + return advanceIfMatch(token, type); + } + + constexpr bool consume(token_type type) noexcept { + return advance().type == type; + } + + constexpr bool check(token_type type) const noexcept { + return peek().type == type; + } + + private: + std::size_t current_ = 0; + vector tokens_; + + constexpr token get(std::size_t i) const noexcept { + return tokens_[i]; + } + }; + + class lexer { + public: + explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} + + constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { + from_chars_result result{ text_.data(), std::errc{} }; + + while (!is_eol()) { + result = scan_token(token_stream); + if (!result) { + return result; + } + } + + token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); + + return result; + } + + private: + std::string_view text_; + std::size_t current_pos_; + + constexpr from_chars_result scan_token(token_stream& stream) noexcept { + const char c = advance(); + + switch (c) { + case ' ': + add_token(stream, token_type::space); + break; + case '.': + add_token(stream, token_type::dot); + break; + case '-': + add_token(stream, token_type::hyphen); + break; + case '+': + add_token(stream, token_type::plus); + break; + case '|': + if (advanceIfMatch('|')) { + add_token(stream, token_type::logical_or); + break; + } + return failure(get_prev_symbol()); + case '<': + add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); + break; + case '>': + add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); + break; + case '=': + add_token(stream, token_type::range_operator, range_operator::equal); + break; + default: + if (is_digit(c)) { + add_token(stream, token_type::digit, to_digit(c)); + break; + } + else if (is_letter(c)) { + add_token(stream, token_type::letter, c); + break; + } + return failure(get_prev_symbol()); + } + + return success(get_prev_symbol()); + } + + constexpr void add_token(token_stream& stream, token_type type, token::value_t value = {}) noexcept { + const char* lexeme = get_prev_symbol(); + stream.push({ type, value, lexeme}); + } + + constexpr char advance() noexcept { + char c = text_[current_pos_]; + current_pos_ += 1; + return c; + } + + constexpr bool advanceIfMatch(char c) noexcept { + if (is_eol()) { + return false; + } + + if (text_[current_pos_] != c) { + return false; + } + + current_pos_ += 1; + + return true; + } + + constexpr const char* get_prev_symbol() const noexcept { + return text_.data() + current_pos_ - 1; + } + + constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } + }; + + class prerelease_comparator { + public: + template + [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { + if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { + return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); + } + + const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); + + for (std::size_t i = 0; i < count; ++i) { + const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); + if (compare_result != 0) { + return compare_result; + } + } + + return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); + } + + private: + [[nodiscard]] constexpr int compare_identifier(const prerelease_identifier& lhs, const prerelease_identifier& rhs) const noexcept { + if (lhs.type == prerelease_identifier_type::numeric && rhs.type == prerelease_identifier_type::numeric) { + return compare_numerically(lhs.identifier, rhs.identifier); + } else if (lhs.type == prerelease_identifier_type::alphanumeric && rhs.type == prerelease_identifier_type::alphanumeric) { + return detail::compare(lhs.identifier, rhs.identifier); + } + + return lhs.type == prerelease_identifier_type::alphanumeric ? 1 : -1; + } + }; + + class version_parser { + public: + constexpr explicit version_parser(token_stream& stream) : stream_{stream} { + } + + template + constexpr from_chars_result parse(version& out) noexcept { + out.clear(); + + from_chars_result result = parse_number(out.major_); + if (!result) { + return result; + } + + if (!stream_.consume(token_type::dot)) { + return failure(stream_.previous().lexeme); + } + + result = parse_number(out.minor_); + if (!result) { + return result; + } + + if (!stream_.consume(token_type::dot)) { + return failure(stream_.previous().lexeme); + } + + result = parse_number(out.patch_); + if (!result) { + return result; + } + + if (stream_.advanceIfMatch(token_type::hyphen)) { + result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); + if (!result) { + return result; + } + } + + if (stream_.advanceIfMatch(token_type::plus)) { + result = parse_build_metadata(out.build_metadata_); + if (!result) { + return result; + } + } + + return result; + } + + + private: + token_stream& stream_; + + template + constexpr from_chars_result parse_number(Int& out) { + token token = stream_.advance(); + + if (!is_digit(token)) { + return failure(token.lexeme); + } + + const auto first_digit = std::get(token.value); + std::uint64_t result = first_digit; + + if (first_digit == 0) { + out = static_cast(result); + return success(stream_.peek().lexeme); + } + + while (stream_.advanceIfMatch(token, token_type::digit)) { + result = result * 10 + std::get(token.value); + } + + if (detail::number_in_range(result)) { + out = static_cast(result); + return success(stream_.peek().lexeme); + } + + return failure(token.lexeme, std::errc::result_out_of_range); + } + + constexpr from_chars_result parse_prerelease_tag(string& out, vector& out_identifiers) { + string result; + + do { + if (!result.empty()) { + result.push_back('.'); + } + + string identifier; + if (const auto res = parse_prerelease_identifier(identifier); !res) { + return res; + } + + result.append(identifier); + out_identifiers.push_back(make_prerelease_identifier(identifier)); + + } while (stream_.advanceIfMatch(token_type::dot)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr from_chars_result parse_build_metadata(string& out) { + string result; + + do { + if (!result.empty()) { + result.push_back('.'); + } + + string identifier; + if (const auto res = parse_build_identifier(identifier); !res) { + return res; + } + + result.append(identifier); + } while (stream_.advanceIfMatch(token_type::dot)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr from_chars_result parse_prerelease_identifier(string& out) { + string result; + token token = stream_.advance(); + + do { + switch (token.type) { + case token_type::hyphen: + result.push_back('-'); + break; + case token_type::letter: + result.push_back(std::get(token.value)); + break; + case token_type::digit: + { + const auto digit = std::get(token.value); + + // numerical prerelease identifier doesn't allow leading zero + // 1.2.3-1.alpha is valid, + // 1.2.3-01b is valid as well, but + // 1.2.3-01.alpha is not valid + + // Only check for leading zero when digit is the first character of the + // prerelease identifier. + if (result.empty() && is_leading_zero(digit)) { + return failure(token.lexeme); + } + + result.push_back(to_char(digit)); + break; + } + default: + return failure(token.lexeme); + } + } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { + auto type = detail::prerelease_identifier_type::numeric; + for (char c : identifier) { + if (c == '-' || detail::is_letter(c)) { + type = detail::prerelease_identifier_type::alphanumeric; + break; + } + } + return detail::prerelease_identifier{ type, identifier }; + } + + constexpr from_chars_result parse_build_identifier(string& out) { + string result; + token token = stream_.advance(); + + do { + switch (token.type) { + case token_type::hyphen: + result.push_back('-'); + break; + case token_type::letter: + result.push_back(std::get(token.value)); + break; + case token_type::digit: + { + const auto digit = std::get(token.value); + result.push_back(to_char(digit)); + break; + } + default: + return failure(token.lexeme); + } + } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + + out = result; + return success(stream_.peek().lexeme); + } + + constexpr bool is_leading_zero(int digit) noexcept { + if (digit != 0) { + return false; + } + + size_t k = 0; + int alpha_numerics = 0; + int digits = 0; + + while (true) { + const token token = stream_.peek(k); + + if (!is_alphanumeric(token)) { + break; + } + + ++alpha_numerics; + + if (is_digit(token)) { + ++digits; + } + + ++k; + } + + return digits > 0 && digits == alpha_numerics; + } + + constexpr bool is_digit(const token& token) const noexcept { + return token.type == token_type::digit; + } + + constexpr bool is_eol(const token& token) const noexcept { + return token.type == token_type::eol; + } + + constexpr bool is_alphanumeric(const token& token) const noexcept { + return token.type == token_type::hyphen || token.type == token_type::letter || token.type == token_type::digit; + } + }; + + template + constexpr int compare_prerelease(const version& lhs, const version& rhs) noexcept { + return prerelease_comparator{}.compare(lhs, rhs); + } + + template + constexpr int compare_parsed(const version& lhs, const version& rhs, version_compare_option compare_option) { + int result = lhs.major() - rhs.major(); + if (result != 0) { + return result; + } + + result = lhs.minor() - rhs.minor(); + if (result != 0) { + return result; + } + + result = lhs.patch() - rhs.patch(); + if (result != 0) { + return result; + } + + if (compare_option == version_compare_option::include_prerelease) { + result = detail::compare_prerelease(lhs, rhs); + } + + return result; + } + + template + constexpr from_chars_result parse(std::string_view str, version& out) { + token_stream token_stream; + from_chars_result result = lexer{ str }.scan_tokens(token_stream); + if (!result) { + return result; + } + + result = version_parser{ token_stream }.parse(out); + if (!result) { + return result; + } + + if (!token_stream.consume(token_type::eol)) { + return failure(token_stream.previous().lexeme); + } + + return success(token_stream.previous().lexeme); + } + + } // namespace semver::detail + + template + [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) == 0; + } + + template + [[nodiscard]] constexpr bool operator!=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) != 0; + } + + template + [[nodiscard]] constexpr bool operator>(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) > 0; + } + + template + [[nodiscard]] constexpr bool operator>=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) >= 0; + } + + template + [[nodiscard]] constexpr bool operator<(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) < 0; + } + + template + [[nodiscard]] constexpr bool operator<=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; + } #if __cpp_impl_three_way_comparison >= 201907L - template - [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { - int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); - if (compare == 0) - return std::strong_ordering::equal; + template + [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { + int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); + if (compare == 0) + return std::strong_ordering::equal; if (compare > 0) - return std::strong_ordering::greater; + return std::strong_ordering::greater; return std::strong_ordering::less; - } + } #endif - template - constexpr from_chars_result parse(std::string_view str, version& output) { - return detail::parse(str, output); - } - - constexpr bool valid(std::string_view str) { - version v{}; - return detail::parse(str, v); - } - - namespace detail { - template - class range_comparator { - public: - constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} - - constexpr bool contains(const version& other) const noexcept { - switch (op_) { - case range_operator::less: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; - case range_operator::less_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; - case range_operator::greater: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; - case range_operator::greater_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; - case range_operator::equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; - } - return false; - } - - constexpr const version& get_version() const noexcept { return v_; } - - constexpr range_operator get_operator() const noexcept { return op_; } - - constexpr string to_string() const { - string result; - switch (op_) { - case range_operator::less: result += "<"; break; - case range_operator::less_or_equal: result += "<="; break; - case range_operator::greater: result += ">"; break; - case range_operator::greater_or_equal: result += ">="; break; - case range_operator::equal: result += "="; break; - } - result += v_.to_string(); - return result; - } - - private: - version v_; - range_operator op_; - }; - - class range_parser; - - template - class range { - public: - friend class detail::range_parser; - - constexpr bool contains(const version& v, version_compare_option option) const noexcept { - if (option == version_compare_option::exclude_prerelease) { - if (!match_at_least_one_comparator_with_prerelease(v)) { - return false; - } - } - - return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { - return ranges_comparator.contains(v); - }); - } - - constexpr auto begin() const noexcept { - return ranges_comparators_.begin(); - } - - constexpr auto end() const noexcept { - return ranges_comparators_.end(); - } - - constexpr std::size_t size() const noexcept { - return ranges_comparators_.size(); - } - - constexpr bool empty() const noexcept { - return ranges_comparators_.empty(); - } - - constexpr string to_string() const { - return join(ranges_comparators_, " "); - } - - private: - vector> ranges_comparators_; - - constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { - if (v.prerelease_tag().empty()) { - return true; - } - - return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { - const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); - const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; - return has_prerelease && equal_without_prerelease; - }); - } - }; - } - - template - class range_set { - public: - friend class detail::range_parser; - - constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { - return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { - return range.contains(v, option); - }); - } - - constexpr auto begin() const noexcept { - return ranges_.begin(); - } - - constexpr auto end() const noexcept { - return ranges_.end(); - } - - constexpr std::size_t size() const noexcept { - return ranges_.size(); - } - - constexpr bool empty() const noexcept { - return ranges_.empty(); - } - - constexpr string to_string() const { - return join(ranges_, " "); - } - - private: - vector> ranges_; - }; - - namespace detail { - class range_parser { - public: - constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} - - template - constexpr from_chars_result parse(range_set& out) noexcept { - vector> ranges; - - do { - - detail::range range; - if (const auto res = parse_range(range); !res) { - return res; - } - - ranges.push_back(range); - skip_whitespaces(); - - } while (stream_.advanceIfMatch(token_type::logical_or)); - - out.ranges_ = std::move(ranges); - - return success(stream_.peek().lexeme); - } - - private: - token_stream stream_; - - template - constexpr from_chars_result parse_range(detail::range& out) noexcept { - do { - skip_whitespaces(); - - if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { - return res; - } - - skip_whitespaces(); - - } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); - - return success(stream_.peek().lexeme); - } - - template - constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { - range_operator op = range_operator::equal; - token token; - if (stream_.advanceIfMatch(token, token_type::range_operator)) { - op = std::get(token.value); - } - - skip_whitespaces(); - - version ver; - version_parser parser{ stream_ }; - if (const auto res = parser.parse(ver); !res) { - return res; - } - - out.emplace_back(ver, op); - return success(stream_.peek().lexeme); - } - - constexpr void skip_whitespaces() noexcept { - while (stream_.advanceIfMatch(token_type::space)) { - ; - } - } - }; - } // namespace semver::detail - - - template - constexpr from_chars_result parse(std::string_view str, range_set& out) { - detail::token_stream token_stream; - const from_chars_result result = detail::lexer{ str }.scan_tokens(token_stream); - if (!result) { - return result; - } - - return detail::range_parser{ std::move(token_stream) }.parse(out); - } + template + constexpr from_chars_result parse(std::string_view str, version& output) { + return detail::parse(str, output); + } + + constexpr bool valid(std::string_view str) { + version v{}; + return detail::parse(str, v); + } + + namespace detail { + template + class range_comparator { + public: + constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} + + constexpr bool contains(const version& other) const noexcept { + switch (op_) { + case range_operator::less: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; + case range_operator::less_or_equal: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; + case range_operator::greater: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; + case range_operator::greater_or_equal: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; + case range_operator::equal: + return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; + } + return false; + } + + constexpr const version& get_version() const noexcept { return v_; } + + constexpr range_operator get_operator() const noexcept { return op_; } + + constexpr string to_string() const { + string result; + switch (op_) { + case range_operator::less: result += "<"; break; + case range_operator::less_or_equal: result += "<="; break; + case range_operator::greater: result += ">"; break; + case range_operator::greater_or_equal: result += ">="; break; + case range_operator::equal: result += "="; break; + } + result += v_.to_string(); + return result; + } + + private: + version v_; + range_operator op_; + }; + + class range_parser; + + template + class range { + public: + friend class detail::range_parser; + + constexpr bool contains(const version& v, version_compare_option option) const noexcept { + if (option == version_compare_option::exclude_prerelease) { + if (!match_at_least_one_comparator_with_prerelease(v)) { + return false; + } + } + + return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + return ranges_comparator.contains(v); + }); + } + + constexpr auto begin() const noexcept { + return ranges_comparators_.begin(); + } + + constexpr auto end() const noexcept { + return ranges_comparators_.end(); + } + + constexpr std::size_t size() const noexcept { + return ranges_comparators_.size(); + } + + constexpr bool empty() const noexcept { + return ranges_comparators_.empty(); + } + + constexpr string to_string() const { + return join(ranges_comparators_, " "); + } + + private: + vector> ranges_comparators_; + + constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { + if (v.prerelease_tag().empty()) { + return true; + } + + return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); + const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; + return has_prerelease && equal_without_prerelease; + }); + } + }; + } + + template + class range_set { + public: + friend class detail::range_parser; + + constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { + return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { + return range.contains(v, option); + }); + } + + constexpr auto begin() const noexcept { + return ranges_.begin(); + } + + constexpr auto end() const noexcept { + return ranges_.end(); + } + + constexpr std::size_t size() const noexcept { + return ranges_.size(); + } + + constexpr bool empty() const noexcept { + return ranges_.empty(); + } + + constexpr string to_string() const { + return join(ranges_, " "); + } + + private: + vector> ranges_; + }; + + namespace detail { + class range_parser { + public: + constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} + + template + constexpr from_chars_result parse(range_set& out) noexcept { + vector> ranges; + + do { + + detail::range range; + if (const auto res = parse_range(range); !res) { + return res; + } + + ranges.push_back(range); + skip_whitespaces(); + + } while (stream_.advanceIfMatch(token_type::logical_or)); + + out.ranges_ = std::move(ranges); + + return success(stream_.peek().lexeme); + } + + private: + token_stream stream_; + + template + constexpr from_chars_result parse_range(detail::range& out) noexcept { + do { + skip_whitespaces(); + + if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { + return res; + } + + skip_whitespaces(); + + } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); + + return success(stream_.peek().lexeme); + } + + template + constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { + range_operator op = range_operator::equal; + token token; + if (stream_.advanceIfMatch(token, token_type::range_operator)) { + op = std::get(token.value); + } + + skip_whitespaces(); + + version ver; + version_parser parser{ stream_ }; + if (const auto res = parser.parse(ver); !res) { + return res; + } + + out.emplace_back(ver, op); + return success(stream_.peek().lexeme); + } + + constexpr void skip_whitespaces() noexcept { + while (stream_.advanceIfMatch(token_type::space)) { + ; + } + } + }; + } // namespace semver::detail + + + template + constexpr from_chars_result parse(std::string_view str, range_set& out) { + detail::token_stream token_stream; + const from_chars_result result = detail::lexer{ str }.scan_tokens(token_stream); + if (!result) { + return result; + } + + return detail::range_parser{ std::move(token_stream) }.parse(out); + } } // namespace semver #ifndef PLUGIFY_VECTOR_NO_STD_HASH @@ -1078,7 +1078,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); @@ -1089,7 +1089,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); @@ -1100,7 +1100,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); diff --git a/test/example_plugin/plugin.cpp b/test/example_plugin/plugin.cpp index e268285..0bbdcf4 100644 --- a/test/example_plugin/plugin.cpp +++ b/test/example_plugin/plugin.cpp @@ -5,24 +5,24 @@ class ExamplePlugin final : public plg::IPluginEntry { public: - void OnPluginStart() final { - std::cout << "Example Start!" << std::endl; - } + void OnPluginStart() final { + std::cout << "Example Start!" << std::endl; + } - void OnPluginEnd() final { - std::cout << "Example End!" << std::endl; - } + void OnPluginEnd() final { + std::cout << "Example End!" << std::endl; + } - void MakePrint(int count, const plg::string& message) { - for (int i = 0; i < count; ++i) { - std::cout << message.data() << std::endl; - } - } + void MakePrint(int count, const plg::string &message) { + for (int i = 0; i < count; ++i) { + std::cout << message.data() << std::endl; + } + } } g_examplePlugin; EXPOSE_PLUGIN(PLUGIN_API, ExamplePlugin, &g_examplePlugin) extern "C" -PLUGIN_API void MakePrint(int count, const plg::string& message) { - g_examplePlugin.MakePrint(count, message); +PLUGIN_API void MakePrint(int count, const plg::string &message) { + g_examplePlugin.MakePrint(count, message); } From 97d8a9bcfbeab7f6b4a205b2365a9b087ed2e092 Mon Sep 17 00:00:00 2001 From: qubka Date: Mon, 15 Sep 2025 20:19:35 +0100 Subject: [PATCH 05/10] docs: update instalation --- README.md | 4 ++-- README_ru.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6ff15ab..a521377 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,10 @@ The C++ Language Module for Plugify enables developers to write plugins in C++ f #### Option 1: Install via Plugify Plugin Manager -You can install the C++ Language Module using the Plugify plugin manager by running the following command: +You can install the C++ Language Module using the Mamba plugin manager by running the following command: ```bash -plg install plugify-module-cpp +mamba install -n your_env_name -c https://untrustedmodders.github.io/plugify-module-cpp/ plugify-module-cpp ``` #### Option 2: Manual Installation diff --git a/README_ru.md b/README_ru.md index 072e66b..c4e8380 100644 --- a/README_ru.md +++ b/README_ru.md @@ -22,10 +22,10 @@ #### Вариант 1: Установка через менеджер плагинов Plugify -Вы можете установить модуль языка C++ с помощью менеджера плагинов Plugify, выполнив следующую команду: +Вы можете установить модуль языка C++ с помощью менеджера плагинов Mamba, выполнив следующую команду: ```bash -plg install plugify-module-cpp +mamba install -n your_env_name -c https://untrustedmodders.github.io/plugify-module-cpp/ plugify-module-cpp ``` #### Вариант 2: Ручная установка From 0769d48696da23197b3313f00365bed342463214 Mon Sep 17 00:00:00 2001 From: qubka Date: Mon, 15 Sep 2025 20:21:48 +0100 Subject: [PATCH 06/10] docs: update instalation --- README.md | 4 ++-- README_ru.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a521377..bbce77c 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ The C++ Language Module for Plugify enables developers to write plugins in C++ f ### Installation -#### Option 1: Install via Plugify Plugin Manager +#### Option 1: Install via Mamba Package Manager -You can install the C++ Language Module using the Mamba plugin manager by running the following command: +You can install the C++ Language Module using the Mamba package manager by running the following command: ```bash mamba install -n your_env_name -c https://untrustedmodders.github.io/plugify-module-cpp/ plugify-module-cpp diff --git a/README_ru.md b/README_ru.md index c4e8380..28e9115 100644 --- a/README_ru.md +++ b/README_ru.md @@ -20,9 +20,9 @@ ### Установка -#### Вариант 1: Установка через менеджер плагинов Plugify +#### Вариант 1: Установка через менеджер пакетов Mamba -Вы можете установить модуль языка C++ с помощью менеджера плагинов Mamba, выполнив следующую команду: +Вы можете установить модуль языка C++ с помощью менеджера пакетов Mamba, выполнив следующую команду: ```bash mamba install -n your_env_name -c https://untrustedmodders.github.io/plugify-module-cpp/ plugify-module-cpp From adde6637aa24f43e6ee3644be413e7a105c9530d Mon Sep 17 00:00:00 2001 From: qubka Date: Sat, 20 Sep 2025 21:58:57 +0100 Subject: [PATCH 07/10] fix: update plugify --- external/plugify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/plugify b/external/plugify index 17f13ed..7ceb64f 160000 --- a/external/plugify +++ b/external/plugify @@ -1 +1 @@ -Subproject commit 17f13eddb49999617122cc9e6c0d3ca885817fd4 +Subproject commit 7ceb64f5fcd23378ad6f59bf86a3ef0d6a5257cc From ef75a180f2c6015b7660acf40a07e9decd91fbce Mon Sep 17 00:00:00 2001 From: qubka Date: Sat, 27 Sep 2025 13:44:18 +0100 Subject: [PATCH 08/10] feat: update for a new plugify --- CMakeLists.txt | 13 + CMakePresets.json | 8 +- external/plugify | 2 +- include/plg/allocator.hpp | 158 +- include/plg/concepts.hpp | 110 + .../plg/macro.hpp => include/plg/config.hpp | 154 +- include/plg/debugging.hpp | 41 +- include/plg/enum.hpp | 233 +- include/plg/expected.hpp | 129 +- include/plg/flat_map.hpp | 780 --- include/plg/format.hpp | 19 +- include/plg/guards.hpp | 108 + include/plg/hash.hpp | 68 +- include/plg/inplace_vector.hpp | 772 +++ include/plg/numerics.hpp | 3 +- include/plg/path.hpp | 79 +- include/plg/plugin.hpp | 6 +- include/plg/split_buffer.hpp | 907 ++++ include/plg/string.hpp | 4541 ++++++++++++----- include/plg/uninitialized.hpp | 157 + include/plg/variant.hpp | 103 +- include/plg/vector.hpp | 2111 +++++--- include/plg/version.hpp | 2013 ++++---- test/cross_call_master/CMakeLists.txt | 4 +- .../plugify/include/plg/allocator.hpp | 158 +- .../external/plugify/include/plg/concepts.hpp | 111 + .../external/plugify/include/plg/config.hpp | 161 +- .../plugify/include/plg/debugging.hpp | 41 +- .../external/plugify/include/plg/enum.hpp | 8 +- .../external/plugify/include/plg/expected.hpp | 129 +- .../external/plugify/include/plg/flat_map.hpp | 780 --- .../external/plugify/include/plg/format.hpp | 19 +- .../external/plugify/include/plg/guards.hpp | 108 + .../external/plugify/include/plg/hash.hpp | 30 +- .../plugify/include/plg/inplace_vector.hpp | 772 +++ .../external/plugify/include/plg/numerics.hpp | 3 +- .../external/plugify/include/plg/path.hpp | 13 +- .../external/plugify/include/plg/plugin.hpp | 6 +- .../plugify/include/plg/split_buffer.hpp | 907 ++++ .../external/plugify/include/plg/string.hpp | 4526 +++++++++++----- .../plugify/include/plg/uninitialized.hpp | 157 + .../external/plugify/include/plg/variant.hpp | 103 +- .../external/plugify/include/plg/vector.hpp | 2105 +++++--- .../external/plugify/include/plg/version.hpp | 345 +- test/cross_call_worker/CMakeLists.txt | 4 +- .../plugify/include/plg/allocator.hpp | 158 +- .../external/plugify/include/plg/concepts.hpp | 111 + .../external/plugify/include/plg/config.hpp} | 161 +- .../plugify/include/plg/debugging.hpp | 41 +- .../external/plugify/include/plg/enum.hpp | 8 +- .../external/plugify/include/plg/expected.hpp | 129 +- .../external/plugify/include/plg/flat_map.hpp | 780 --- .../external/plugify/include/plg/format.hpp | 19 +- .../external/plugify/include/plg/guards.hpp | 108 + .../external/plugify/include/plg/hash.hpp | 30 +- .../plugify/include/plg/inplace_vector.hpp | 772 +++ .../external/plugify/include/plg/numerics.hpp | 3 +- .../external/plugify/include/plg/path.hpp | 13 +- .../external/plugify/include/plg/plugin.hpp | 6 +- .../plugify/include/plg/split_buffer.hpp | 907 ++++ .../external/plugify/include/plg/string.hpp | 4526 +++++++++++----- .../plugify/include/plg/uninitialized.hpp | 157 + .../external/plugify/include/plg/variant.hpp | 103 +- .../external/plugify/include/plg/vector.hpp | 2105 +++++--- .../external/plugify/include/plg/version.hpp | 345 +- test/example_plugin/CMakeLists.txt | 15 +- .../plugify/include/plg/allocator.hpp | 158 +- .../external/plugify/include/plg/concepts.hpp | 111 + .../external/plugify/include/plg/config.hpp} | 161 +- .../plugify/include/plg/debugging.hpp | 41 +- .../external/plugify/include/plg/enum.hpp | 8 +- .../external/plugify/include/plg/expected.hpp | 129 +- .../external/plugify/include/plg/flat_map.hpp | 780 --- .../external/plugify/include/plg/format.hpp | 19 +- .../external/plugify/include/plg/guards.hpp | 108 + .../external/plugify/include/plg/hash.hpp | 30 +- .../plugify/include/plg/inplace_vector.hpp | 772 +++ .../external/plugify/include/plg/numerics.hpp | 3 +- .../external/plugify/include/plg/path.hpp | 13 +- .../external/plugify/include/plg/plugin.hpp | 6 +- .../plugify/include/plg/split_buffer.hpp | 907 ++++ .../external/plugify/include/plg/string.hpp | 4526 +++++++++++----- .../plugify/include/plg/uninitialized.hpp | 157 + .../external/plugify/include/plg/variant.hpp | 103 +- .../external/plugify/include/plg/vector.hpp | 2105 +++++--- .../external/plugify/include/plg/version.hpp | 345 +- 86 files changed, 29839 insertions(+), 14145 deletions(-) create mode 100644 include/plg/concepts.hpp rename test/cross_call_worker/external/plugify/include/plg/macro.hpp => include/plg/config.hpp (76%) delete mode 100644 include/plg/flat_map.hpp create mode 100644 include/plg/guards.hpp create mode 100644 include/plg/inplace_vector.hpp create mode 100644 include/plg/split_buffer.hpp create mode 100644 include/plg/uninitialized.hpp create mode 100644 test/cross_call_master/external/plugify/include/plg/concepts.hpp rename include/plg/macro.hpp => test/cross_call_master/external/plugify/include/plg/config.hpp (75%) delete mode 100644 test/cross_call_master/external/plugify/include/plg/flat_map.hpp create mode 100644 test/cross_call_master/external/plugify/include/plg/guards.hpp create mode 100644 test/cross_call_master/external/plugify/include/plg/inplace_vector.hpp create mode 100644 test/cross_call_master/external/plugify/include/plg/split_buffer.hpp create mode 100644 test/cross_call_master/external/plugify/include/plg/uninitialized.hpp create mode 100644 test/cross_call_worker/external/plugify/include/plg/concepts.hpp rename test/{example_plugin/external/plugify/include/plg/macro.hpp => cross_call_worker/external/plugify/include/plg/config.hpp} (75%) delete mode 100644 test/cross_call_worker/external/plugify/include/plg/flat_map.hpp create mode 100644 test/cross_call_worker/external/plugify/include/plg/guards.hpp create mode 100644 test/cross_call_worker/external/plugify/include/plg/inplace_vector.hpp create mode 100644 test/cross_call_worker/external/plugify/include/plg/split_buffer.hpp create mode 100644 test/cross_call_worker/external/plugify/include/plg/uninitialized.hpp create mode 100644 test/example_plugin/external/plugify/include/plg/concepts.hpp rename test/{cross_call_master/external/plugify/include/plg/macro.hpp => example_plugin/external/plugify/include/plg/config.hpp} (75%) delete mode 100644 test/example_plugin/external/plugify/include/plg/flat_map.hpp create mode 100644 test/example_plugin/external/plugify/include/plg/guards.hpp create mode 100644 test/example_plugin/external/plugify/include/plg/inplace_vector.hpp create mode 100644 test/example_plugin/external/plugify/include/plg/split_buffer.hpp create mode 100644 test/example_plugin/external/plugify/include/plg/uninitialized.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 32b0e79..f6aaf7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ if(LINUX) set(PLUGIFY_USE_STATIC_STDLIB ON CACHE INTERNAL "") set(PLUGIFY_USE_ABI0 OFF CACHE INTERNAL "") endif() +set(PLUGIFY_USE_SANITIZER ON CACHE INTERNAL "") add_subdirectory(external/plugify) # @@ -69,12 +70,24 @@ else() target_compile_options(${PROJECT_NAME} PRIVATE -Wextra -Wshadow -Wconversion -Wpedantic -Werror) endif() +# Produce PDB file for debug +if(MSVC) + target_compile_options(${PROJECT_NAME} PRIVATE $<$:/Zi>) +else() + target_compile_options(${PROJECT_NAME} PRIVATE $<$:-g1>) +endif() + if(APPLE) target_link_options(${PROJECT_NAME} PRIVATE "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/sym/exported_symbols.lds") elseif(UNIX) target_link_options(${PROJECT_NAME} PRIVATE "-Wl,--version-script,${CMAKE_CURRENT_SOURCE_DIR}/sym/version_script.lds") endif() +if(PLUGIFY_HAS_SANITIZER) + target_compile_options(${PROJECT_NAME} PRIVATE $<$: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) + target_link_libraries(${PROJECT_NAME} PRIVATE $<$: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) +endif() + include(GenerateExportHeader) generate_export_header(${PROJECT_NAME} EXPORT_MACRO_NAME CPPLM_EXPORT EXPORT_FILE_NAME ${CMAKE_BINARY_DIR}/exports/module_export.h) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}/exports) diff --git a/CMakePresets.json b/CMakePresets.json index 80b854f..d3ffa90 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -18,17 +18,13 @@ "name": "Debug", "displayName": "Debug", "inherits": "default", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug" - } + "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } }, { "name": "Release", "displayName": "Release", "inherits": "default", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "RelWithDebInfo" - } + "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } } ], "buildPresets": [ diff --git a/external/plugify b/external/plugify index 7ceb64f..38d6e9f 160000 --- a/external/plugify +++ b/external/plugify @@ -1 +1 @@ -Subproject commit 7ceb64f5fcd23378ad6f59bf86a3ef0d6a5257cc +Subproject commit 38d6e9f5452fee901586219974cd7b177847d7bf diff --git a/include/plg/allocator.hpp b/include/plg/allocator.hpp index 3c01cd5..ea025da 100644 --- a/include/plg/allocator.hpp +++ b/include/plg/allocator.hpp @@ -1,85 +1,59 @@ #pragma once -#include // for std::size_t, std::ptrdiff_t -#include // for std::malloc, std::free, std::aligned_alloc -#include // for std::is_constant_evaluated -#include // for ::operator new, ::operator delete +#include // for std::size_t, std::ptrdiff_t +#include // for std::malloc, std::free, std::aligned_alloc +#include // for ::operator new, ::operator delete +#include // for std::is_constant_evaluated -#include "plg/macro.hpp" +#include "plg/config.hpp" namespace plg { - // Forward declaration for allocator template class allocator; - // Specialization for `void`, but we no longer need to define `pointer` and `const_pointer` template<> class allocator { public: using value_type = void; - // Rebind struct template struct rebind { using other = allocator; }; }; - // Define the custom allocator inheriting from std::allocator template class allocator { + static_assert(!std::is_const_v, "plg::allocator does not support const types"); + static_assert(!std::is_volatile_v, "plg::allocator does not support volatile types"); public: using value_type = T; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - // Default constructor constexpr allocator() noexcept = default; - // Copy constructor template constexpr allocator(const allocator&) noexcept {} - // Rebind struct template struct rebind { using other = allocator; }; - // Override allocate method to use custom allocation function - constexpr pointer allocate(size_type n, [[maybe_unused]] const_pointer hint = nullptr) { + [[nodiscard]] constexpr T* allocate(size_type n) { static_assert(sizeof(T) != 0, "cannot allocate incomplete types"); static_assert((alignof(T) & (alignof(T) - 1)) == 0, "alignof(T) must be a power of 2"); - if (n > max_size()) [[unlikely]] { - if (n > static_cast(-1) / sizeof(T)) { - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): bad array new length", std::bad_array_new_length); - } - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): too big", std::bad_alloc); + if (n > std::allocator_traits::max_size(*this)) { + throw_bad_array_new_length(); } - pointer ret; size_type size = n * sizeof(T); if (std::is_constant_evaluated()) { - ret = static_cast(::operator new(size)); + return static_cast(::operator new(size)); } else { - if constexpr (alignof(T) > alignof(std::max_align_t)) { - size_type aligned_size = (size + (alignof(T) - 1)) & ~(alignof(T) - 1); - ret = static_cast(aligned_allocate(alignof(T), aligned_size)); - } else { - ret = static_cast(std::malloc(size)); - } - - if (!ret) { - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): bad allocation", std::bad_alloc); - } + return malloc_allocate(size); } - - return ret; } - // Override deallocate method to use custom deallocation function - constexpr void deallocate(pointer p, [[maybe_unused]] size_type n) { + constexpr void deallocate(T* p, [[maybe_unused]] size_type n) { if (std::is_constant_evaluated()) { ::operator delete(p); } else { @@ -88,28 +62,114 @@ namespace plg { } private: - constexpr size_type max_size() noexcept { -#if __PTRDIFF_MAX__ < __SIZE_MAX__ - return static_cast(__PTRDIFF_MAX__) / sizeof(T); -#else - return static_cast(-1) / sizeof(T); -#endif // __PTRDIFF_MAX__ + static T* malloc_allocate(size_type size) { + T* ret; + if constexpr (alignof(T) > alignof(std::max_align_t)) { + size_type aligned_size = (size + (alignof(T) - 1)) & ~(alignof(T) - 1); + ret = static_cast(aligned_allocate(alignof(T), aligned_size)); + } else { + ret = static_cast(std::malloc(size)); + } + if (!ret) { + throw_bad_alloc(); + } + return ret; + } + + [[noreturn]] static void throw_bad_array_new_length() { + PLUGIFY_THROW("bad array new length", std::bad_array_new_length); } - void* aligned_allocate(size_type alignment, size_type size) { -#if _WIN32 + [[noreturn]] static void throw_bad_alloc() { + PLUGIFY_THROW("bad allocation", std::bad_alloc); + } + + static void* aligned_allocate(size_type alignment, size_type size) { +#if PLUGIFY_PLATFORM_WINDOWS return _aligned_malloc(size, alignment); #else return std::aligned_alloc(alignment, size); -#endif // _WIN32 +#endif // PLUGIFY_PLATFORM_WINDOWS } }; - // Comparison operators for compatibility template constexpr bool operator==(const allocator&, const allocator) { return true; } template constexpr bool operator!=(const allocator&, const allocator) { return false; } + template + void swap_allocator(Alloc& a1, Alloc& a2, std::true_type) { + using std::swap; + swap(a1, a2); + } + + template + void swap_allocator(Alloc&, Alloc&, std::false_type) noexcept {} + + template + void swap_allocator(Alloc& a1, Alloc& a2) { + swap_allocator(a1, a2, std::integral_constant::propagate_on_container_swap::value>()); + } + + template + struct allocation_result { + Pointer ptr; + Size count; + }; + + template + [[nodiscard]] allocation_result::pointer> + allocate_at_least(Alloc& alloc, size_t n) { + return { alloc.allocate(n), n }; + } + + template + constexpr bool is_pointer_in_range(const T* begin, const T* end, const U* ptr) { + if (std::is_constant_evaluated()) + return false; + return reinterpret_cast(begin) <= reinterpret_cast(ptr) && + reinterpret_cast(ptr) < reinterpret_cast(end); + } + + template + constexpr bool is_overlapping_range(const T* begin, const T* end, const U* begin2) { + auto size = end - begin; + auto end2 = begin2 + size; + return is_pointer_in_range(begin, end, begin2) || is_pointer_in_range(begin2, end2, begin); + } + + // asan_annotate_container_with_allocator determines whether containers with custom allocators are annotated. This is + // a public customization point to disable annotations if the custom allocator assumes that the memory isn't poisoned. + // See the https://libcxx.llvm.org/UsingLibcxx.html#turning-off-asan-annotation-in-containers for more information. +#if __has_feature(address_sanitizer) + template + struct asan_annotate_container_with_allocator : std::true_type {}; +#endif + + // Annotate a contiguous range. + // [__first_storage, __last_storage) is the allocated memory region, + // __old_last_contained is the previously last allowed (unpoisoned) element, and + // __new_last_contained is the new last allowed (unpoisoned) element. + template + void annotate_contiguous_container( + [[maybe_unused]] const void* first_storage, + [[maybe_unused]] const void* last_storage, + [[maybe_unused]] const void* old_last_contained, + [[maybe_unused]] const void* new_last_contained + ) { +#if __has_feature(address_sanitizer) + if (!std::is_constant_evaluated() + && asan_annotate_container_with_allocator::value + && first_storage != nullptr) { + __sanitizer_annotate_contiguous_container( + first_storage, + last_storage, + old_last_contained, + new_last_contained + ); + } +#endif + } } // namespace plg diff --git a/include/plg/concepts.hpp b/include/plg/concepts.hpp new file mode 100644 index 0000000..e54e722 --- /dev/null +++ b/include/plg/concepts.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include + +#if PLUGIFY_HAS_CXX23 +# include +#endif + +namespace plg { +#if PLUGIFY_HAS_CXX23 + template + concept container_compatible_range = std::ranges::input_range && std::convertible_to, Type>; +#endif + + template + concept is_allocator = + // basic nested types (via allocator_traits) + requires { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::void_pointer; + typename std::allocator_traits::const_void_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; + } && + // required expressions / member calls (use allocator_traits helpers where appropriate) + requires( + Alloc& a, + typename std::allocator_traits::size_type n, + typename std::allocator_traits::pointer p, + typename std::allocator_traits::value_type& v, + const typename std::allocator_traits::value_type& cv + ) { + // allocation / deallocation + { a.allocate(n) } -> std::same_as::pointer>; + { a.deallocate(p, n) } -> std::same_as; + + // max_size: prefer allocator_traits::max_size (calls member or fallback) + { std::allocator_traits::max_size(a) } -> std::convertible_to::size_type>; + + // construct / destroy (via allocator_traits helpers; these must be well-formed) + { std::allocator_traits::construct(a, p, cv) } -> std::same_as; + { std::allocator_traits::destroy(a, p) } -> std::same_as; + + // optional helpful factory used by containers when copying them + { std::allocator_traits::select_on_container_copy_construction(a) } -> std::convertible_to; + }; + + template + concept is_char_traits = requires { + // Required type definitions + typename Traits::char_type; + typename Traits::int_type; + typename Traits::off_type; + typename Traits::pos_type; + typename Traits::state_type; + } && requires( + typename Traits::char_type c1, + typename Traits::char_type c2, + typename Traits::char_type& cr, + const typename Traits::char_type& ccr, + typename Traits::char_type* p, + const typename Traits::char_type* cp, + typename Traits::int_type i1, + typename Traits::int_type i2, + std::size_t n + ) { + // Character operations + { Traits::assign(cr, ccr) } -> std::same_as; + { Traits::eq(ccr, ccr) } -> std::convertible_to; + { Traits::lt(ccr, ccr) } -> std::convertible_to; + + // String operations + { Traits::compare(cp, cp, n) } -> std::convertible_to; + { Traits::length(cp) } -> std::convertible_to; + { Traits::find(cp, n, ccr) } -> std::convertible_to; + + // Memory operations + { Traits::move(p, cp, n) } -> std::same_as; + { Traits::copy(p, cp, n) } -> std::same_as; + { Traits::assign(p, n, c1) } -> std::same_as; + + // int_type operations + { Traits::not_eof(i1) } -> std::same_as; + { Traits::to_char_type(i1) } -> std::same_as; + { Traits::to_int_type(c1) } -> std::same_as; + { Traits::eq_int_type(i1, i2) } -> std::convertible_to; + { Traits::eof() } -> std::same_as; + }; + + // A type is trivially relocatable if a move construct + destroy of the original object is equivalent to + // `memcpy(dst, src, sizeof(T))`. + // + // Note that we don't use the __cpp_lib_trivially_relocatable Clang builtin right now because it does not + // implement the semantics of any current or future trivial relocation proposal and it can lead to + // incorrect optimizations on some platforms (Windows) and supported compilers (AppleClang). +#if __has_builtin(__cpp_lib_trivially_relocatable) + template + struct is_trivially_relocatable : std::integral_constant {}; +#else + template + struct is_trivially_relocatable : std::is_trivially_copyable {}; +#endif + + template requires(std::is_same_v) + struct is_trivially_relocatable : std::true_type {}; +} diff --git a/test/cross_call_worker/external/plugify/include/plg/macro.hpp b/include/plg/config.hpp similarity index 76% rename from test/cross_call_worker/external/plugify/include/plg/macro.hpp rename to include/plg/config.hpp index a072fec..1054d97 100644 --- a/test/cross_call_worker/external/plugify/include/plg/macro.hpp +++ b/include/plg/config.hpp @@ -16,57 +16,42 @@ # define __has_builtin(x) 0 #endif -#include - -#define PLUGIFY_HAS_EXCEPTIONS (__cpp_exceptions || __EXCEPTIONS || _HAS_EXCEPTIONS) - -#ifndef PLUGIFY_EXCEPTIONS -# if PLUGIFY_HAS_EXCEPTIONS -# define PLUGIFY_EXCEPTIONS 1 -# else -# define PLUGIFY_EXCEPTIONS 0 -# endif -#endif - -#if PLUGIFY_EXCEPTIONS && (!PLUGIFY_HAS_EXCEPTIONS || !__has_include()) -# undef PLUGIFY_EXCEPTIONS -# define PLUGIFY_EXCEPTIONS 0 -#endif - -#ifndef PLUGIFY_FALLBACK_ASSERT -# define PLUGIFY_FALLBACK_ASSERT 1 +#ifndef __builtin_constant_p +# define __builtin_constant_p(x) std::is_constant_evaluated() #endif -#if PLUGIFY_FALLBACK_ASSERT && !__has_include() -# undef PLUGIFY_FALLBACK_ASSERT -# define PLUGIFY_FALLBACK_ASSERT 0 +#if __has_include() +# include #endif -#ifndef PLUGIFY_FALLBACK_ABORT -# define PLUGIFY_FALLBACK_ABORT 1 -#endif - -#if PLUGIFY_FALLBACK_ABORT && !__has_include() -# undef PLUGIFY_FALLBACK_ABORT -# define PLUGIFY_FALLBACK_ABORT 0 +#if __has_include() +# include +# define PLUGIFY_ASSERT(cond, mesg) assert((cond) && (mesg)) #endif -#ifndef PLUGIFY_FALLBACK_ABORT_FUNCTION -# define PLUGIFY_FALLBACK_ABORT_FUNCTION [] (auto) { } +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# include #endif -#if PLUGIFY_EXCEPTIONS +#define PLUGIFY_HAS_EXCEPTIONS __cpp_exceptions || _CPPUNWIND || __EXCEPTIONS +#if PLUGIFY_HAS_EXCEPTIONS # include # include -# define PLUGIFY_ASSERT(x, str, e) do { if (!(x)) [[unlikely]] plugify_throw(str); } while (0) -#elif PLUGIFY_FALLBACK_ASSERT -# include -# define PLUGIFY_ASSERT(x, str, ...) assert((x) && (str)) -#elif PLUGIFY_FALLBACK_ABORT -# include -# define PLUGIFY_ASSERT(x, ...) do { if (!(x)) [[unlikely]] { std::abort(); } } while (0) +namespace plg { + template + [[noreturn]] constexpr void throw_exception(const char* msg, Args...args) { + if constexpr (std::is_constructible_v) { + throw E(msg); + } else { + throw E(std::forward(args)...); + } + } +} // namespace plg +# define PLUGIFY_THROW(str, exp, ...) ::plg::throw_exception(str, ##__VA_ARGS__); #else -# define PLUGIFY_ASSERT(x, str, ...) do { if (!(x)) [[unlikely]] { PLUGIFY_FALLBACK_ABORT_FUNCTION (str); { while (true) { [] { } (); } } } } while (0) +# include +# include +# define PLUGIFY_THROW(str, ...) { std::fputs(str "\n", stderr); std::abort(); } #endif # define PLUGIFY_COMPILER_MAKE_VERSION2(version, sp) ((version) * 100 + (sp)) @@ -258,12 +243,24 @@ #elif PLUGIFY_COMPILER_MSVC # pragma warning(error: 4714) # define PLUGIFY_FORCE_INLINE [[msvc::forceinline]] -# define PLUGIFY_NOINLINE __declspec(noinline) +# define PLUGIFY_NOINLINE [[msvc::noinline]] #else # define PLUGIFY_FORCE_INLINE inline # define PLUGIFY_NOINLINE #endif +#if __has_feature(nullability) +# define PLUGIFY_NO_NULL _Nonnull +#else +# define PLUGIFY_NO_NULL +#endif + +#if __has_cpp_attribute(__no_sanitize__) +# define PLUGIFY_NO_CFI __attribute__((__no_sanitize__("cfi"))) +#else +# define PLUGIFY_NO_CFI +#endif + #if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG # define PLUGIFY_RESTRICT __restrict__ #elif PLUGIFY_COMPILER_MSVC @@ -272,13 +269,68 @@ # define PLUGIFY_RESTRICT #endif -#if PLUGIFY_EXCEPTIONS -template -[[noreturn]] PLUGIFY_FORCE_INLINE constexpr void plugify_throw(const char* msg) { - if constexpr (std::is_constructible_v) { - throw E(msg); - } else { - throw E(); - } -} -#endif \ No newline at end of file +#ifndef PLUGIFY_PLATFORM_WINDOWS +# if defined(_WIN32) || defined(_WIN64) +# define PLUGIFY_PLATFORM_WINDOWS 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_APPLE +# if defined(__APPLE__) && defined(__MACH__) +# define PLUGIFY_PLATFORM_APPLE 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_LINUX +# if defined(__linux__) +# define PLUGIFY_PLATFORM_LINUX 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_ANDROID +# if defined(__ANDROID__) +# define PLUGIFY_PLATFORM_ANDROID 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_ORBIS +# if defined(__ORBIS__) +# define PLUGIFY_PLATFORM_ORBIS 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_PROSPERO +# if defined(__PROSPERO__) +# define PLUGIFY_PLATFORM_PROSPERO 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_SWITCH +# if defined(__NX__) +# define PLUGIFY_PLATFORM_SWITCH 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_BSD +# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +# define PLUGIFY_PLATFORM_BSD 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_UNIX +# if defined(__unix__) || defined(__unix) || defined(unix) || defined(__APPLE__) +# define PLUGIFY_PLATFORM_UNIX 1 +# endif +#endif + +#if !defined(PLUGIFY_PLATFORM_WINDOWS) && \ + !defined(PLUGIFY_PLATFORM_APPLE) && \ + !defined(PLUGIFY_PLATFORM_LINUX) && \ + !defined(PLUGIFY_PLATFORM_ANDROID) && \ + !defined(PLUGIFY_PLATFORM_ORBIS) && \ + !defined(PLUGIFY_PLATFORM_PROSPERO)&& \ + !defined(PLUGIFY_PLATFORM_SWITCH) && \ + !defined(PLUGIFY_PLATFORM_BSD) && \ + !defined(PLUGIFY_PLATFORM_UNIX) +# error "Unsupported platform! Please extend macro.hpp" +#endif diff --git a/include/plg/debugging.hpp b/include/plg/debugging.hpp index b52ec8c..0326fe7 100644 --- a/include/plg/debugging.hpp +++ b/include/plg/debugging.hpp @@ -1,13 +1,19 @@ #pragma once -#include "plg/macro.hpp" - -#ifdef __cpp_lib_debugging +#include "plg/config.hpp" +#if __has_include() #include +#if defined(__cpp_lib_debugging) && __cpp_lib_debugging >= 202403L +#define PLUGIFY_HAS_STD_DEBUGGING 1 +#else +#define PLUGIFY_HAS_STD_DEBUGGING 0 +#endif +#else +#define PLUGIFY_HAS_STD_DEBUGGING 0 +#endif -#else //def __cpp_lib_debugging - +#if !PLUGIFY_HAS_STD_DEBUGGING #if PLUGIFY_PLATFORM_WINDOWS #include #include @@ -25,16 +31,7 @@ #include #endif -#endif //def __cpp_lib_debugging - namespace plg { -#ifdef __cpp_lib_debugging - - using std::breakpoint; - using std::breakpoint_if_debugging; - using std::is_debugger_present; - -#else //def __cpp_lib_debugging #if PLUGIFY_PLATFORM_WINDOWS @@ -178,7 +175,7 @@ namespace plg { } // namespace debugging } // namespace detail - PLUGIFY_NOINLINE inline bool is_debugger_present() noexcept { + inline bool is_debugger_present() noexcept { return plg::detail::debugging::parse_proc_status(); } @@ -190,7 +187,7 @@ namespace plg { #endif - PLUGIFY_FORCE_INLINE void breakpoint() noexcept { + inline void breakpoint() noexcept { #if PLUGIFY_COMPILER_MSVC __debugbreak(); #elif PLUGIFY_COMPILER_CLANG @@ -202,11 +199,17 @@ namespace plg { #endif } - PLUGIFY_FORCE_INLINE void breakpoint_if_debugging() noexcept { + inline void breakpoint_if_debugging() noexcept { if (plg::is_debugger_present()) { plg::breakpoint(); } } - -#endif //def __cpp_lib_debugging } // namespace plg + +namespace std { + using plg::breakpoint; + using plg::breakpoint_if_debugging; + using plg::is_debugger_present; +} // namespace std + +#endif // !PLUGIFY_HAS_STD_DEBUGGING diff --git a/include/plg/enum.hpp b/include/plg/enum.hpp index 84f6d23..802b7c1 100644 --- a/include/plg/enum.hpp +++ b/include/plg/enum.hpp @@ -1,121 +1,130 @@ #pragma once +#include #include +#include #include #include -#include -#include -#include "plg/macro.hpp" +#include "plg/config.hpp" -// from https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ +// from +// https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ namespace plg { - constexpr auto ENUM_MIN_VALUE = -128; - constexpr auto ENUM_MAX_VALUE = 128; - - template - struct static_string { - constexpr static_string(std::string_view sv) noexcept { - std::copy(sv.begin(), sv.end(), content.begin()); - } - constexpr operator std::string_view() const noexcept { return { content.data(), N }; } - - private: - std::array content{}; - }; - - constexpr auto is_pretty(char ch) noexcept { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); - } - - constexpr auto pretty_name(std::string_view sv) noexcept { - for (std::size_t n = sv.size() - 1; n > 0; --n) { - if (!is_pretty(sv[n])) { - sv.remove_prefix(n + 1); - break; - } - } - return sv; - } - - template - constexpr auto n() noexcept { - #if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG - return pretty_name({ __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2 }); - #elif PLUGIFY_COMPILER_MSVC - return pretty_name({ __FUNCSIG__, sizeof(__FUNCSIG__) - 17 }); - #endif - } - - template - constexpr auto is_valid() { - [[maybe_unused]] constexpr E v = static_cast(V); - return !n().empty(); - } - - template - constexpr auto value(std::size_t v) { - return static_cast(ENUM_MIN_VALUE + static_cast(v)); - } - - template - constexpr auto count_values(const bool (&valid)[N]) { - std::size_t count = 0; - for (std::size_t n = 0; n < N; ++n) - if (valid[n]) ++count; - return count; - } - - template - constexpr auto values(std::index_sequence) noexcept { - constexpr bool valid[sizeof...(I)] = { is_valid(I)>()... }; - constexpr auto num_valid = count_values(valid); - static_assert(num_valid > 0, "no support for empty enums"); - - std::array values = {}; - for(std::size_t offset = 0, n = 0; n < num_valid; ++offset) { - if (valid[offset]) { - values[n] = value(offset); - ++n; - } - } - - return values; - } - - template - constexpr auto values() noexcept { - constexpr auto enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1; - return values(std::make_index_sequence({})); - } - - template - inline constexpr auto values_v = values(); - - template - constexpr auto enum_name() { - constexpr auto name = n(); - return static_string(name); - } - - template - inline constexpr auto enum_name_v = enum_name(); - - template - constexpr auto entries(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {{ values_v[I], enum_name_v[I]>}...} - }; - } - - template - inline constexpr auto entries_v = entries(std::make_index_sequence.size()>()); - - template - constexpr std::string_view enum_to_string(E value) { - for (const auto& [ key, name ]: entries_v) { - if (value == key) return name; - } - return {}; - } + constexpr auto ENUM_MIN_VALUE = -128; + constexpr auto ENUM_MAX_VALUE = 128; + + template + struct static_string { + constexpr static_string(std::string_view sv) noexcept { + std::copy(sv.begin(), sv.end(), _content.begin()); + } + + constexpr operator std::string_view() const noexcept { + return { _content.data(), N }; + } + + private: + std::array _content{}; + }; + + constexpr auto is_pretty(char ch) noexcept { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); + } + + constexpr auto pretty_name(std::string_view sv) noexcept { + for (std::size_t n = sv.size() - 1; n > 0; --n) { + if (!is_pretty(sv[n])) { + sv.remove_prefix(n + 1); + break; + } + } + return sv; + } + + template + constexpr auto n() noexcept { +#if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG + return pretty_name({ __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2 }); +#elif PLUGIFY_COMPILER_MSVC + return pretty_name({ __FUNCSIG__, sizeof(__FUNCSIG__) - 17 }); +#endif + } + + template + constexpr auto is_valid() { + [[maybe_unused]] constexpr E v = static_cast(V); + return !n().empty(); + } + + template + constexpr auto value(std::size_t v) { + return static_cast(ENUM_MIN_VALUE + static_cast(v)); + } + + template + constexpr auto count_values(const bool (&valid)[N]) { + std::size_t count = 0; + for (std::size_t n = 0; n < N; ++n) { + if (valid[n]) { + ++count; + } + } + return count; + } + + template + constexpr auto values(std::index_sequence) noexcept { + constexpr bool valid[sizeof...(I)] = { is_valid(I)>()... }; + constexpr auto num_valid = count_values(valid); + static_assert(num_valid > 0, "no support for empty enums"); + + std::array values = {}; + for (std::size_t offset = 0, n = 0; n < num_valid; ++offset) { + if (valid[offset]) { + values[n] = value(offset); + ++n; + } + } + + return values; + } + + template + constexpr auto values() noexcept { + constexpr auto enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1; + return values(std::make_index_sequence({})); + } + + template + inline constexpr auto values_v = values(); + + template + constexpr auto enum_name() { + constexpr auto name = n(); + return static_string(name); + } + + template + inline constexpr auto enum_name_v = enum_name(); + + template + constexpr auto entries(std::index_sequence) noexcept { + return std::array, sizeof...(I)>{ + { { values_v[I], enum_name_v[I]> }... } + }; + } + + template + inline constexpr auto entries_v = entries(std::make_index_sequence.size()>()); + + template + constexpr std::string_view enum_to_string(E value) { + for (const auto& [key, name] : entries_v) { + if (value == key) { + return name; + } + } + return {}; + } } diff --git a/include/plg/expected.hpp b/include/plg/expected.hpp index d6bc137..f35fea5 100644 --- a/include/plg/expected.hpp +++ b/include/plg/expected.hpp @@ -1,14 +1,19 @@ #pragma once -#include "plg/macro.hpp" +#include "plg/config.hpp" -#ifdef __cpp_lib_expected +#if __has_include() #include -namespace plg { - using std::expected; - using std::unexpected; -} +#if defined(__cpp_lib_expected) && __cpp_lib_expected >= 202202L +#define PLUGIFY_HAS_STD_EXPECTED 1 +#else +#define PLUGIFY_HAS_STD_EXPECTED 0 +#endif #else +#define PLUGIFY_HAS_STD_EXPECTED 0 +#endif + +#if !PLUGIFY_HAS_STD_EXPECTED #include #include #include @@ -524,27 +529,39 @@ namespace plg { // precondition: has_value() = true constexpr auto operator->() const noexcept -> T const* { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::addressof(this->val); } // precondition: has_value() = true constexpr auto operator->() noexcept -> T* { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::addressof(this->val); } // precondition: has_value() = true - constexpr auto operator*() const& noexcept -> T const& { return this->val; } + constexpr auto operator*() const& noexcept -> T const& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return this->val; + } // precondition: has_value() = true - constexpr auto operator*() & noexcept -> T& { return this->val; } + constexpr auto operator*() & noexcept -> T& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return this->val; + } // precondition: has_value() = true constexpr auto operator*() const&& noexcept -> T const&& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::move(this->val); } // precondition: has_value() = true - constexpr auto operator*() && noexcept -> T&& { return std::move(this->val); } + constexpr auto operator*() && noexcept -> T&& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return std::move(this->val); + } constexpr explicit operator bool() const noexcept { return has_val; } @@ -553,44 +570,56 @@ namespace plg { } constexpr auto value() const& -> T const& { - if (has_value()) { - return this->val; + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } - throw bad_expected_access(error()); + return this->val; } constexpr auto value() & -> T& { - if (has_value()) { - return this->val; + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } - throw bad_expected_access(error()); + return this->val; } constexpr auto value() const&& -> T const&& { - if (has_value()) { - return std::move(this->val); + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } - throw bad_expected_access(std::move(error())); + return std::move(this->val); } constexpr auto value() && -> T&& { - if (has_value()) { - return std::move(this->val); + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } - throw bad_expected_access(std::move(error())); + return std::move(this->val); } // precondition: has_value() = false - constexpr auto error() const& -> E const& { return this->unex; } + constexpr auto error() const& -> E const& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() & -> E& { return this->unex; } + constexpr auto error() & -> E& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() const&& -> E const&& { return std::move(this->unex); } + constexpr auto error() const&& -> E const&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // precondition: has_value() = false - constexpr auto error() && -> E&& { return std::move(this->unex); } + constexpr auto error() && -> E&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } template requires std::is_copy_constructible_v && std::is_convertible_v @@ -1126,27 +1155,39 @@ namespace plg { constexpr void value() const& { if (!has_value()) { - throw bad_expected_access(error()); + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } } constexpr void value() && { if (!has_value()) { - throw bad_expected_access(std::move(error())); + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } } // precondition: has_value() = false - constexpr auto error() const& -> E const& { return this->unex; } + constexpr auto error() const& -> E const& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() & -> E& { return this->unex; } + constexpr auto error() & -> E& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() const&& -> E const&& { return std::move(this->unex); } + constexpr auto error() const&& -> E const&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // precondition: has_value() = false - constexpr auto error() && -> E&& { return std::move(this->unex); } + constexpr auto error() && -> E&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // monadic template>> @@ -1426,5 +1467,27 @@ namespace plg { }; }; -}// namespace plg -#endif \ No newline at end of file +} // namespace plg + +namespace std { + template + using expected = plg::expected; + + template + concept is_expected = std::same_as, expected >; + +#if PLUGIFY_COMPILER_CLANG + template + struct unexpected : public plg::unexpected { + using plg::unexpected::unexpected; + }; + template + unexpected(U) -> unexpected; +#else + template + using unexpected = plg::unexpected; +#endif + +} // namespace std + +#endif // !PLUGIFY_HAS_STD_EXPECTED \ No newline at end of file diff --git a/include/plg/flat_map.hpp b/include/plg/flat_map.hpp deleted file mode 100644 index 9912431..0000000 --- a/include/plg/flat_map.hpp +++ /dev/null @@ -1,780 +0,0 @@ -#pragma once - -#include "plg/macro.hpp" - -#ifdef __cpp_lib_flat_map -#include -namespace plg { - template> - using flat_map = std::flat_map; -} -#else -#include "plg/vector.hpp" - -namespace plg { - namespace detail { - template < typename T, typename U, typename = void > - struct is_transparent - : std::false_type {}; - - template < typename T, typename U > - struct is_transparent> - : std::true_type {}; - - template < typename T, typename U > - inline constexpr bool is_transparent_v = is_transparent::value; - - template - constexpr bool is_sorted(Iter first, Iter last, Compare comp) { - if (first != last) { - Iter next = first; - while (++next != last) { - if (comp(*next, *first)) { - return false; - } - ++first; - } - } - return true; - } - - template - constexpr bool is_sorted_unique(Iter first, Iter last, Compare comp) { - if (first != last) { - Iter next = first; - while (++next != last) { - if (!comp(*first, *next)) { - return false; - } - ++first; - } - } - return true; - } - - template - struct pair_compare : public Compare { - pair_compare() = default; - - explicit pair_compare(const Compare& compare) - : Compare(compare) {} - - bool operator()( - const typename Pair::first_type& l, - const typename Pair::first_type& r) const { - return Compare::operator()(l, r); - } - - bool operator()(const Pair& l, const Pair& r) const { - return Compare::operator()(l.first, r.first); - } - - bool operator()( - const typename Pair::first_type& l, - const Pair& r) const { - return Compare::operator()(l, r.first); - } - - bool operator()( - const Pair& l, - const typename Pair::first_type& r) const { - return Compare::operator()(l.first, r); - } - - template - requires (is_transparent_v) - bool operator()(const K& l, const Pair& r) const { - return Compare::operator()(l, r.first); - } - - template - requires (is_transparent_v) - bool operator()(const Pair& l, const K& r) const { - return Compare::operator()(l.first, r); - } - }; - - template - struct eq_compare : public Compare { - eq_compare() = default; - - explicit eq_compare(const Compare& compare) - : Compare(compare) {} - - template - bool operator()(const L& l, const R& r) const { - return !Compare::operator()(l, r) && !Compare::operator()(r, l); - } - }; - } // namespace detail - - struct sorted_range_t {}; - inline constexpr sorted_range_t sorted_range = sorted_range_t(); - - struct sorted_unique_range_t : public sorted_range_t {}; - inline constexpr sorted_unique_range_t sorted_unique_range = sorted_unique_range_t(); - - template, typename Container = std::vector>> - class flat_map { - public: - using key_type = Key; - using mapped_type = Value; - using value_type = typename Container::value_type; - - using size_type = typename Container::size_type; - using difference_type = typename Container::difference_type; - - using key_compare = Compare; - using container_type = Container; - - using reference = typename Container::reference; - using const_reference = typename Container::const_reference; - using pointer = typename Container::pointer; - using const_pointer = typename Container::const_pointer; - - using iterator = typename Container::iterator; - using const_iterator = typename Container::const_iterator; - using reverse_iterator = typename Container::reverse_iterator; - using const_reverse_iterator = typename Container::const_reverse_iterator; - - struct value_compare : private key_compare { - value_compare() = default; - - explicit value_compare(key_compare compare) - : key_compare(std::move(compare)) {} - - bool operator()(const value_type& l, const value_type& r) const { - return key_compare::operator()(l.first, r.first); - } - }; - - public: - flat_map() = default; - ~flat_map() = default; - - explicit flat_map(const Compare& c) - : _compare(c) {} - - template - explicit flat_map(const Allocator& a) - : _data(a) {} - - template - flat_map(const Compare& c, const Allocator& a) - : _compare(c), _data(a) {} - - template - flat_map(Iterator first, Iterator last) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_unique_range, first, last); - } - - flat_map(std::initializer_list list) { - from_range(list.begin(), list.end()); - } - - flat_map(sorted_range_t, std::initializer_list list) { - from_range(sorted_range, list.begin(), list.end()); - } - - flat_map(sorted_unique_range_t, std::initializer_list list) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - flat_map(std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(list.begin(), list.end()); - } - - flat_map(sorted_range_t, std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(sorted_range, list.begin(), list.end()); - } - - flat_map(sorted_unique_range_t, std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(list.begin(), list.end()); - } - - template - flat_map(sorted_range_t, std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(sorted_range, list.begin(), list.end()); - } - - template - flat_map(sorted_unique_range_t, std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(list.begin(), list.end()); - } - - template - flat_map(sorted_range_t, std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_range, list.begin(), list.end()); - } - - template - flat_map(sorted_unique_range_t, std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(flat_map&& other, const Allocator& a) - : _compare(std::move(other._compare)), _data(std::move(other._data), a) {} - - template - flat_map(const flat_map& other, const Allocator& a) - : _compare(other._compare), _data(other._data, a) {} - - flat_map(flat_map&& other) noexcept = default; - flat_map(const flat_map& other) = default; - - flat_map& operator=(flat_map&& other) noexcept = default; - flat_map& operator=(const flat_map& other) = default; - - flat_map& operator=(std::initializer_list list) { - flat_map(list).swap(*this); - return *this; - } - - iterator begin() noexcept(noexcept(std::declval().begin())) { - return _data.begin(); - } - - const_iterator begin() const - noexcept(noexcept(std::declval().begin())) { - return _data.begin(); - } - - const_iterator cbegin() const - noexcept(noexcept(std::declval().cbegin())) { - return _data.cbegin(); - } - - iterator end() noexcept(noexcept(std::declval().end())) { - return _data.end(); - } - - const_iterator end() const - noexcept(noexcept(std::declval().end())) { - return _data.end(); - } - - const_iterator cend() const - noexcept(noexcept(std::declval().cend())) { - return _data.cend(); - } - - reverse_iterator rbegin() noexcept(noexcept(std::declval().rbegin())) { - return _data.rbegin(); - } - - const_reverse_iterator rbegin() const - noexcept(noexcept(std::declval().rbegin())) { - return _data.rbegin(); - } - - const_reverse_iterator crbegin() const - noexcept(noexcept(std::declval().crbegin())) { - return _data.crbegin(); - } - - reverse_iterator rend() noexcept(noexcept(std::declval().rend())) { - return _data.rend(); - } - - const_reverse_iterator rend() const - noexcept(noexcept(std::declval().rend())) { - return _data.rend(); - } - - const_reverse_iterator crend() const - noexcept(noexcept(std::declval().crend())) { - return _data.crend(); - } - - bool empty() const - noexcept(noexcept(std::declval().empty())) { - return _data.empty(); - } - - size_type size() const - noexcept(noexcept(std::declval().size())) { - return _data.size(); - } - - size_type max_size() const - noexcept(noexcept(std::declval().max_size())) { - return _data.max_size(); - } - - size_type capacity() const - noexcept(noexcept(std::declval().capacity())) { - return _data.capacity(); - } - - void reserve(size_type capacity) { - _data.reserve(capacity); - } - - void shrink_to_fit() { - _data.shrink_to_fit(); - } - - mapped_type& operator[](key_type&& key) { - const iterator iter = find(key); - return iter != end() - ? iter->second - : emplace(std::move(key), mapped_type()).first->second; - } - - mapped_type& operator[](const key_type& key) { - const iterator iter = find(key); - return iter != end() - ? iter->second - : emplace(key, mapped_type()).first->second; - } - - mapped_type& at(const key_type& key) { - const iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - const mapped_type& at(const key_type& key) const { - const const_iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - template - requires (detail::is_transparent_v) - mapped_type& at(const K& key) { - const iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - template - requires (detail::is_transparent_v) - const mapped_type& at(const K& key) const { - const const_iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - std::pair insert(value_type&& value) { - const iterator iter = lower_bound(value.first); - return iter == end() || _compare(value, *iter) - ? std::make_pair(_data.insert(iter, std::move(value)), true) - : std::make_pair(iter, false); - } - - std::pair insert(const value_type& value) { - const iterator iter = lower_bound(value.first); - return iter == end() || _compare(value, *iter) - ? std::make_pair(_data.insert(iter, value), true) - : std::make_pair(iter, false); - } - - iterator insert(const_iterator hint, value_type&& value) { - return (hint == begin() || _compare(*(hint - 1), value)) && (hint == end() || _compare(value, *hint)) - ? _data.insert(hint, std::move(value)) - : insert(std::move(value)).first; - } - - iterator insert(const_iterator hint, const value_type& value) { - return (hint == begin() || _compare(*(hint - 1), value)) && (hint == end() || _compare(value, *hint)) - ? _data.insert(hint, value) - : insert(value).first; - } - - template - std::pair insert_or_assign(key_type&& key, V&& value) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, std::move(key), std::forward(value)); - return {iter, true}; - } - (*iter).second = std::forward(value); - return {iter, false}; - } - - template - std::pair insert_or_assign(const key_type& key, V&& value) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, key, std::forward(value)); - return {iter, true}; - } - (*iter).second = std::forward(value); - return {iter, false}; - } - - template - void insert(Iterator first, Iterator last) { - insert_range(first, last); - } - - template - void insert(sorted_range_t, Iterator first, Iterator last) { - insert_range(sorted_range, first, last); - } - - void insert(std::initializer_list list) { - insert_range(list.begin(), list.end()); - } - - void insert(sorted_range_t, std::initializer_list list) { - insert_range(sorted_range, list.begin(), list.end()); - } - - template - std::pair emplace(Args&&... args) { - return insert(value_type(std::forward(args)...)); - } - - template - iterator emplace_hint(const_iterator hint, Args&&... args) { - return insert(hint, value_type(std::forward(args)...)); - } - - template - std::pair try_emplace(key_type&& key, Args&&... args) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, std::move(key), std::forward(args)...); - return {iter, true}; - } - return {iter, false}; - } - - template - std::pair try_emplace(const key_type& key, Args&&... args) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, key, std::forward(args)...); - return {iter, true}; - } - return {iter, false}; - } - - void clear() noexcept(noexcept(std::declval().clear())) { - _data.clear(); - } - - iterator erase(const_iterator iter) { - return _data.erase(iter); - } - - iterator erase(const_iterator first, const_iterator last) { - return _data.erase(first, last); - } - - size_type erase(const key_type& key) { - const const_iterator iter = find(key); - return iter != end() - ? (erase(iter), 1) - : 0; - } - - void swap(flat_map& other) noexcept(std::is_nothrow_swappable_v && std::is_nothrow_swappable_v) { - using std::swap; - swap(_compare, other._compare); - swap(_data, other._data); - } - - size_type count(const key_type& key) const { - const const_iterator iter = find(key); - return iter != end() ? 1 : 0; - } - - template - requires (detail::is_transparent_v) - size_type count(const K& key) const { - const const_iterator iter = find(key); - return iter != end() ? 1 : 0; - } - - iterator find(const key_type& key) { - const iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - const_iterator find(const key_type& key) const { - const const_iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - template - requires (detail::is_transparent_v) - iterator find(const K& key) { - const iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - template - requires (detail::is_transparent_v) - const_iterator find(const K& key) const { - const const_iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - bool contains(const key_type& key) const { - return find(key) != end(); - } - - template - requires (detail::is_transparent_v) - bool contains(const K& key) const { - return find(key) != end(); - } - - std::pair equal_range(const key_type& key) { - return std::equal_range(begin(), end(), key, _compare); - } - - std::pair equal_range(const key_type& key) const { - return std::equal_range(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - std::pair equal_range(const K& key) { - return std::equal_range(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - std::pair equal_range(const K& key) const { - return std::equal_range(begin(), end(), key, _compare); - } - - iterator lower_bound(const key_type& key) { - return std::lower_bound(begin(), end(), key, _compare); - } - - const_iterator lower_bound(const key_type& key) const { - return std::lower_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - iterator lower_bound(const K& key) { - return std::lower_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - const_iterator lower_bound(const K& key) const { - return std::lower_bound(begin(), end(), key, _compare); - } - - iterator upper_bound(const key_type& key) { - return std::upper_bound(begin(), end(), key, _compare); - } - - const_iterator upper_bound(const key_type& key) const { - return std::upper_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - iterator upper_bound(const K& key) { - return std::upper_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - const_iterator upper_bound(const K& key) const { - return std::upper_bound(begin(), end(), key, _compare); - } - - key_compare key_comp() const { - return _compare; - } - - value_compare value_comp() const { - return value_compare(key_comp()); - } - - private: - template - void from_range(Iter first, Iter last) { - assert(_data.empty()); - _data.insert(_data.end(), first, last); - std::sort(_data.begin(), _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void from_range(sorted_range_t, Iter first, Iter last) { - assert(_data.empty()); - assert(detail::is_sorted(first, last, value_comp())); - _data.insert(_data.end(), first, last); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void from_range(sorted_unique_range_t, Iter first, Iter last) { - assert(_data.empty()); - assert(detail::is_sorted_unique(first, last, value_comp())); - _data.insert(_data.end(), first, last); - } - - private: - template - void insert_range(Iter first, Iter last) { - const auto mid_iter = _data.insert(_data.end(), first, last); - std::sort(mid_iter, _data.end(), value_comp()); - std::inplace_merge(_data.begin(), mid_iter, _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void insert_range(sorted_range_t, Iter first, Iter last) { - assert(detail::is_sorted(first, last, value_comp())); - const auto mid_iter = _data.insert(_data.end(), first, last); - std::inplace_merge(_data.begin(), mid_iter, _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - private: - PLUGIFY_NO_UNIQUE_ADDRESS - detail::pair_compare _compare; - container_type _data; - }; - - template - void swap( - flat_map& l, - flat_map& r) noexcept(noexcept(l.swap(r))) { - l.swap(r); - } - - template - bool operator==( - const flat_map& l, - const flat_map& r) { - return l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin()); - } - - template - auto operator<=>( - const flat_map& l, - const flat_map& r) { - if (l.size() < r.size()) { - return std::partial_ordering::less; - } else if (l.size() > r.size()) { - return std::partial_ordering::greater; - } else { - if (std::lexicographical_compare(l.cbegin(), l.cend(), r.cbegin(), r.cend())) { - return std::partial_ordering::less; - } else { - return std::partial_ordering::greater; - } - } - } - - template, typename Container = plg::vector>> - using map = flat_map; - -}// namespace plg -#endif \ No newline at end of file diff --git a/include/plg/format.hpp b/include/plg/format.hpp index 94e5bdb..9abb9fe 100644 --- a/include/plg/format.hpp +++ b/include/plg/format.hpp @@ -1,12 +1,19 @@ #pragma once -#include "plg/macro.hpp" - -#ifdef __cpp_lib_format +#include "plg/config.hpp" +#if __has_include() #include +#if defined(__cpp_lib_format) && __cpp_lib_format >= 201907L +#define PLUGIFY_HAS_STD_FORMAT 1 +#else +#define PLUGIFY_HAS_STD_FORMAT 0 +#endif +#else +#define PLUGIFY_HAS_STD_FORMAT 0 +#endif -#else // __cpp_lib_format +#if !PLUGIFY_HAS_STD_FORMAT // Define FMT_FORMAT_H externally to force a difference location for {fmt} #ifndef FMT_FORMAT_H @@ -21,6 +28,6 @@ namespace std { using namespace fmt; using namespace fmt::detail; -} +} // namespace std -#endif // __cpp_lib_format +#endif // !PLUGIFY_HAS_STD_FORMAT diff --git a/include/plg/guards.hpp b/include/plg/guards.hpp new file mode 100644 index 0000000..4691341 --- /dev/null +++ b/include/plg/guards.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include "plg/config.hpp" + +namespace plg { +#if PLUGIFY_HAS_EXCEPTIONS + template + struct exception_guard_exceptions { + exception_guard_exceptions() = delete; + + constexpr explicit exception_guard_exceptions(Rollback rollback) + : _rollback(std::move(rollback)) + , _completed(false) { + } + + constexpr exception_guard_exceptions( + exception_guard_exceptions&& other + ) noexcept(std::is_nothrow_move_constructible_v) + : _rollback(std::move(other._rollback)) + , _completed(other._completed) { + other._completed = true; + } + + exception_guard_exceptions(const exception_guard_exceptions&) = delete; + exception_guard_exceptions& operator=(const exception_guard_exceptions&) = delete; + exception_guard_exceptions& operator=(exception_guard_exceptions&&) = delete; + + constexpr void complete() noexcept { + _completed = true; + } + + constexpr ~exception_guard_exceptions() { + if (!_completed) { + _rollback(); + } + } + + private: + PLUGIFY_NO_UNIQUE_ADDRESS Rollback _rollback; + bool _completed; + }; + + template + using exception_guard = exception_guard_exceptions; +#else + template + struct exception_guard_noexceptions { + exception_guard_noexceptions() = delete; + + constexpr explicit exception_guard_noexceptions(Rollback) { + } + + constexpr exception_guard_noexceptions( + exception_guard_noexceptions&& other + ) noexcept(std::is_nothrow_move_constructible_v) + : _completed(other._completed) { + other._completed = true; + } + + exception_guard_noexceptions(const exception_guard_noexceptions&) = delete; + exception_guard_noexceptions& operator=(const exception_guard_noexceptions&) = delete; + exception_guard_noexceptions& operator=(exception_guard_noexceptions&&) = delete; + + constexpr void complete() noexcept { + _completed = true; + } + + constexpr ~exception_guard_noexceptions() { + PLUGIFY_ASSERT(_completed, "exception_guard not completed with exceptions disabled"); + } + + private: + bool _completed = false; + }; + + template + using exception_guard = exception_guard_noexceptions; +#endif + + template + constexpr exception_guard make_exception_guard(Rollback rollback) { + return exception_guard(std::move(rollback)); + } + + template + class scope_guard { + PLUGIFY_NO_UNIQUE_ADDRESS Func _func; + + public: + constexpr explicit scope_guard(Func func) + : _func(std::move(func)) { + } + + constexpr ~scope_guard() { + _func(); + } + + scope_guard(const scope_guard&) = delete; + scope_guard& operator=(const scope_guard&) = delete; + scope_guard& operator=(scope_guard&&) = delete; + scope_guard(scope_guard&&) = delete; + }; + + template + constexpr scope_guard make_scope_guard(Func func) { + return scope_guard(std::move(func)); + } +} diff --git a/include/plg/hash.hpp b/include/plg/hash.hpp index 98c9a27..4028e57 100644 --- a/include/plg/hash.hpp +++ b/include/plg/hash.hpp @@ -15,78 +15,102 @@ namespace plg { }; struct string_hash { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup auto operator()(const char* txt) const { return std::hash{}(txt); } + auto operator()(std::string_view txt) const { return std::hash{}(txt); } + auto operator()(const std::string& txt) const { return std::hash{}(txt); } - auto operator()(const plg::string& txt) const { + + auto operator()(const plg::string& txt) const { return std::hash{}(txt); } }; + // --- Hash traits depending on pointer size --- + template + struct hash_traits; + + template <> + struct hash_traits<4> { // 32-bit + static constexpr std::size_t fnv_basis = 0x811C9DC5u; + static constexpr std::size_t fnv_prime = 0x01000193u; + static constexpr std::size_t golden_ratio = 0x9e3779b9u; + }; + + template <> + struct hash_traits<8> { // 64-bit + static constexpr std::size_t fnv_basis = 0xcbf29ce484222325ULL; + static constexpr std::size_t fnv_prime = 0x100000001b3ULL; + static constexpr std::size_t golden_ratio = 0x9e3779b97f4a7c15ULL; + }; + + using active_hash_traits = hash_traits; + struct case_insensitive_hash { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup - template + template auto operator()(const T& str_like) const noexcept { std::string_view str = str_like; - std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis - for (char c : str) { + std::size_t hash = active_hash_traits::fnv_basis; // FNV-1a + for (const char& c : str) { hash ^= static_cast(std::tolower(static_cast(c))); - hash *= 0x100000001b3; + hash *= active_hash_traits::fnv_prime; } return hash; } }; struct case_insensitive_equal { - using is_transparent = void; // Enables heterogeneous lookup + using is_transparent = void; // Enables heterogeneous lookup - template + template bool operator()(const T1& lhs_like, const T2& rhs_like) const noexcept { std::string_view lhs = lhs_like; std::string_view rhs = rhs_like; - if (lhs.size() != rhs.size()) + if (lhs.size() != rhs.size()) { return false; + } for (size_t i = 0; i < lhs.size(); ++i) { - if (std::tolower(static_cast(lhs[i])) != - std::tolower(static_cast(rhs[i]))) + if (std::tolower(static_cast(lhs[i])) + != std::tolower(static_cast(rhs[i]))) { return false; + } } return true; } }; - inline void hash_combine(size_t&) { } + inline void hash_combine(size_t&) { + } template inline void hash_combine(std::size_t& seed, const T& v) { std::hash hasher; - // 0x9e3779b97f4a7c15 is 64-bit golden ratio constant - seed ^= hasher(v) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2); + seed ^= hasher(v) + active_hash_traits::golden_ratio + (seed << 6) + (seed >> 2); } template inline std::size_t hash_combine_all(const Ts&... args) { std::size_t seed = 0; - (hash_combine(seed, args), ...); // fold expression + (hash_combine(seed, args), ...); // fold expression return seed; } - template - struct pair_hash { - size_t operator()(std::pair const& p) const { - return hash_combine_all(p.first, p.second); - } + template + struct pair_hash { + size_t operator()(const std::pair& p) const { + return hash_combine_all(p.first, p.second); + } }; - } diff --git a/include/plg/inplace_vector.hpp b/include/plg/inplace_vector.hpp new file mode 100644 index 0000000..71292c8 --- /dev/null +++ b/include/plg/inplace_vector.hpp @@ -0,0 +1,772 @@ +#pragma once + +#include "plg/config.hpp" + +#if __has_include() +#include +#if defined(__cpp_lib_inplace_vector) && __cpp_lib_inplace_vector >= 202406L +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 1 +#else +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 0 +#endif +#else +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 0 +#endif + +#if !PLUGIFY_HAS_STD_INPLACE_VECTOR +#include +#include +#include +#include +#include +#include + +#if PLUGIFY_CPP_VERSION >= 202002L +#include +#include +#endif + +#ifndef PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF +#if defined(__cpp_impl_trivially_relocatable) && defined(__cpp_lib_trivially_relocatable) +#define PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(x) [[trivially_relocatable(x)]] +#else +#define PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(x) +#endif // __cpp_impl_trivially_relocatable +#endif // PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF + +// from https://github.com/Quuxplusone/SG14 +namespace plg { + namespace detail { + + template && std::is_copy_assignable_v), + bool = (std::is_move_constructible_v && std::is_move_assignable_v)> + struct ipvbase_assignable { + // Base for copyable types + }; + + template + struct ipvbase_assignable { + // Base for immobile types like std::mutex + explicit ipvbase_assignable() = default; + ipvbase_assignable(ipvbase_assignable&&) = delete; + ipvbase_assignable(const ipvbase_assignable&) = delete; + void operator=(ipvbase_assignable&&) = delete; + void operator=(const ipvbase_assignable&) = delete; + ~ipvbase_assignable() = default; + }; + + template + struct ipvbase_assignable { + explicit ipvbase_assignable() = default; + ipvbase_assignable(const ipvbase_assignable&) = delete; + ipvbase_assignable(ipvbase_assignable&&) = default; + void operator=(const ipvbase_assignable&) = delete; + ipvbase_assignable& operator=(ipvbase_assignable&&) = default; + ~ipvbase_assignable() = default; + }; + + template + struct PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(std::is_trivially_relocatable_v) ipvbase + { + size_t _size = 0; + union { + [[maybe_unused]] char _dummy; + T _data[N]; + }; + + constexpr T *base_data() { return _data; } + constexpr const T *base_data() const { return _data; } + constexpr void set_size(size_t n) { _size = n; } + + constexpr explicit ipvbase() noexcept {} + ipvbase(const ipvbase& rhs) + noexcept(std::is_nothrow_copy_constructible_v) + { + if constexpr (std::is_trivially_copy_constructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else { + std::uninitialized_copy_n(rhs._data, rhs._size, _data); + _size = rhs._size; + } + } + ipvbase(ipvbase&& rhs) + noexcept(std::is_nothrow_move_constructible_v +#if defined(__cpp_lib_trivially_relocatable) + || std::is_trivially_relocatable_v +#endif // __cpp_lib_trivially_relocatable + ) + { + if constexpr (std::is_trivially_move_constructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); +#if defined(__cpp_lib_trivially_relocatable) + } else if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_n(rhs._data, rhs._size, _data); + _size = rhs._size; + rhs._size = 0; +#endif // __cpp_lib_trivially_relocatable + } else { + std::uninitialized_move_n(rhs._data, rhs._size, _data); + _size = rhs._size; + } + } + void operator=(const ipvbase& rhs) + noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_copy_assignable_v) + { + if constexpr (std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v && std::is_trivially_destructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else if (this == std::addressof(rhs)) { + // do nothing + } else if (rhs._size <= _size) { + std::copy(rhs._data, rhs._data + rhs._size, _data); + std::destroy(_data + rhs._size, _data + _size); + _size = rhs._size; + } else { + std::copy(rhs._data, rhs._data + _size, _data); + std::uninitialized_copy(rhs._data + _size, rhs._data + rhs._size, _data + _size); + _size = rhs._size; + } + } + void operator=(ipvbase&& rhs) + noexcept(std::is_nothrow_move_constructible_v && std::is_nothrow_move_assignable_v) + { + if constexpr (std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v && std::is_trivially_destructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else if (this == std::addressof(rhs)) { + // do nothing + } else if (rhs._size <= _size) { + std::move(rhs._data, rhs._data + rhs._size, _data); + std::destroy(_data + rhs._size, _data + _size); + _size = rhs._size; + } else { + std::move(rhs._data, rhs._data + _size, _data); +#if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate(rhs._data + _size, rhs._data + rhs._size, _data + _size); + std::swap(rhs._size, _size); + return; + } +#endif // __cpp_lib_trivially_relocatable + std::uninitialized_move(rhs._data + _size, rhs._data + rhs._size, _data + _size); + _size = rhs._size; + } + } + +#if __cpp_concepts >= 202002L + ipvbase(const ipvbase&) requires std::is_trivially_copy_constructible_v = default; + ipvbase(ipvbase&&) requires std::is_trivially_move_constructible_v = default; + ipvbase& operator=(const ipvbase&) requires std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v && std::is_trivially_destructible_v = default; + ipvbase& operator=(ipvbase&&) requires std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v && std::is_trivially_destructible_v = default; + ~ipvbase() requires std::is_trivially_destructible_v = default; +#endif // __cpp_concepts >= 202002L + +#if PLUGIFY_CPP_VERSION >= 202002L + constexpr +#endif // PLUGIFY_CPP_VERSION >= 202002L + ~ipvbase() { + std::destroy(_data, _data + _size); + } + }; + + template + struct ipvbase_zero { + static constexpr size_t _size = 0; + constexpr T *base_data() { return nullptr; } + constexpr const T *base_data() const { return nullptr; } + constexpr void set_size(size_t) { } + }; + + template + struct ipvbase_trivial { + size_t _size = 0; + union { + [[maybe_unused]] char _dummy; + T _data[N]; + }; + constexpr explicit ipvbase_trivial() {} + constexpr T *base_data() { return _data; } + constexpr const T *base_data() const { return _data; } + constexpr void set_size(size_t n) { _size = n; } + }; + + template + using ipvbase_t = std::conditional_t< + N == 0, + ipvbase_zero, + std::conditional_t< + std::is_trivially_copyable_v, + ipvbase_trivial, + ipvbase + > + >; + } // namespace detail + + template + class inplace_vector : detail::ipvbase_assignable, detail::ipvbase_t { + using detail::ipvbase_t::_size; + using detail::ipvbase_t::set_size; + public: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = T*; + using const_iterator = const T*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // [inplace.vector.cons] + + inplace_vector() = default; + inplace_vector(inplace_vector&&) = default; + inplace_vector(const inplace_vector&) = default; + inplace_vector& operator=(inplace_vector&&) = default; + inplace_vector& operator=(const inplace_vector&) = default; + inplace_vector& operator=(std::initializer_list il) + requires std::is_copy_constructible_v + { + assign(il.begin(), il.end()); + return *this; + } + + constexpr inplace_vector(std::initializer_list il) + requires std::copy_constructible : inplace_vector(il.begin(), il.end()) { } + constexpr explicit inplace_vector(size_t n) + requires std::default_initializable + { + if (n > N) { + throw_bad_alloc(); + } + std::uninitialized_value_construct_n(data(), n); + set_size(n); + } + constexpr explicit inplace_vector(size_t n, const value_type& value) + requires std::copy_constructible + { + assign(n, value); + } + + template + requires std::constructible_from::value_type> + constexpr explicit inplace_vector(InputIterator first, InputIterator last) + { + if constexpr (std::random_access_iterator) { + size_t n = static_cast(std::distance(first, last)); + if (n > N) { + throw_bad_alloc(); + } + std::uninitialized_copy_n(first, n, data()); + set_size(n); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } + } + } + + constexpr void assign(std::initializer_list il) + requires std::is_copy_constructible_v + { + assign(il.begin(), il.end()); + } + + constexpr void assign(size_t n, const value_type& value) + requires std::is_copy_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::fill_n(data(), n, value); + std::destroy(data() + n, data() + _size); + } else { + std::fill_n(data(), _size, value); + std::uninitialized_fill_n(data() + _size, n - _size, value); + } + set_size(n); + } + + template + requires std::is_constructible_v::value_type> + constexpr void assign(InputIterator first, InputIterator last) { + const size_type n = static_cast(std::distance(first, last)); + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::copy(first, last, data()); + std::destroy(data() + n, data() + _size); + } else { + std::copy(first, first + _size, data()); + std::uninitialized_copy(first + _size, last, data() + _size); + } + set_size(n); + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + constexpr explicit inplace_vector(std::from_range_t, R&& rg) { + if constexpr (std::ranges::sized_range) { + size_t n = std::ranges::size(rg); + if (n > N) { + throw_bad_alloc(); + } + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, data(), std::unreachable_sentinel); + set_size(n); + } else { + for (auto&& e : rg) { + emplace_back(decltype(e)(e)); + } + } + } + + template + requires std::convertible_to, value_type> + constexpr void assign_range(R&& rg) { + auto first = std::ranges::begin(rg); + auto last = std::ranges::end(rg); + size_t n = std::ranges::size(rg); + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::ranges::copy(first, last, data()); + std::destroy(data() + n, data() + _size); + } else { + auto mid = std::ranges::next(first, _size, last); + std::ranges::copy(first, mid, data()); + std::ranges::uninitialized_copy(mid, last, data() + _size); + } + set_size(n); + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + // iterators + + constexpr iterator begin() noexcept { return data(); } + constexpr iterator end() noexcept { return data() + _size; } + constexpr const_iterator begin() const noexcept { return data(); } + constexpr const_iterator end() const noexcept { return data() + _size; } + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + constexpr const_iterator cbegin() const noexcept { return data(); } + constexpr const_iterator cend() const noexcept { return data() + _size; } + constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + constexpr void resize(size_type n) + requires std::is_default_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (n < _size) { + std::destroy(data() + n, data() + _size); + set_size(n); + } else { + std::uninitialized_value_construct(data() + _size, data() + n); + set_size(_size + n); + } + } + + constexpr void resize(size_type n, const value_type& value) + requires std::is_copy_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (n < _size) { + std::destroy(data() + n, data() + _size); + set_size(n); + } else { + std::uninitialized_fill(data() + _size, data() + n, value); + set_size(_size + n); + } + } + + static constexpr void reserve(size_type n) { + if (n > N) { + throw_bad_alloc(); + } + } + static constexpr void shrink_to_fit() noexcept {} + + // element access + + constexpr reference operator[](size_type pos) { + PLUGIFY_ASSERT(pos < size(), "index out of bounds"); + return data()[pos]; + } + constexpr reference front() { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[0]; + } + constexpr reference back() { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[_size - 1]; + } + + constexpr const_reference operator[](size_type pos) const { + PLUGIFY_ASSERT(pos < size(), "index out of bounds"); + return data()[pos]; + } + constexpr const_reference front() const { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[0]; + } + constexpr const_reference back() const { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[_size - 1]; + } + + constexpr reference at(size_type i) { + if (i >= _size) { + throw_out_of_range(); + } + return data()[i]; + } + constexpr const_reference at(size_type i) const { + if (i >= _size) { + throw_out_of_range(); + } + return data()[i]; + } + + // [inplace.vector.data] + + constexpr T* data() noexcept { return this->base_data(); } + constexpr const T* data() const noexcept { return this->base_data(); } + constexpr size_type size() const noexcept { return _size; } + static constexpr size_type max_size() noexcept { return N; } + static constexpr size_type capacity() noexcept { return N; } + [[nodiscard]] constexpr bool empty() const noexcept { return _size == 0; }; + + // [inplace.vector.modifiers] + + template + requires std::is_constructible_v + value_type& unchecked_emplace_back(Args&&... args) { + // Precondition: (_size < N) + value_type* p = data() + _size; + p = std::construct_at(p, std::forward(args)...); + set_size(_size + 1); + return *p; + } + value_type& unchecked_push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return unchecked_emplace_back(value); + } + value_type& unchecked_push_back(value_type&& value) + requires std::is_move_constructible_v + { + return unchecked_emplace_back(static_cast(value)); + } + + template + requires std::is_constructible_v + constexpr value_type* try_emplace_back(Args&&... args) { + if (_size == N) { + return nullptr; + } + return std::addressof(unchecked_emplace_back(static_cast(args)...)); + } + constexpr value_type* try_push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return try_emplace_back(value); + } + constexpr value_type* try_push_back(value_type&& value) + requires std::is_move_constructible_v + { + return try_emplace_back(static_cast(value)); + } + + template + requires std::is_constructible_v + value_type& emplace_back(Args&&... args) { + if (_size == N) { + throw_bad_alloc(); + } + return unchecked_emplace_back(static_cast(args)...); + } + value_type& push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return emplace_back(value); + } + value_type& push_back(value_type&& value) + requires std::is_move_constructible_v + { + return emplace_back(static_cast(value)); + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + constexpr void append_range(R&& rg) { + for (auto&& e : rg) { + emplace_back(static_cast(e)); + } + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + void pop_back() { + std::destroy_at(data() + _size - 1); + set_size(_size - 1); + } + + template + requires std::is_constructible_v + iterator emplace(const_iterator pos, Args&&... args) { + auto it = iterator(pos); + emplace_back(static_cast(args)...); + std::rotate(it, end() - 1, end()); + return it; + } + iterator insert(const_iterator pos, const value_type& value) + requires std::is_copy_constructible_v + { + return emplace(pos, value); + } + iterator insert(const_iterator pos, value_type&& value) + requires std::is_move_constructible_v + { + return emplace(pos, static_cast(value)); + } + + iterator insert(const_iterator pos, size_type n, const value_type& value) + requires std::is_copy_constructible_v + { + if (N - _size < n) { + throw_bad_alloc(); + } + auto it = iterator(pos); + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::uninitialized_fill_n(it, n, value); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::uninitialized_fill_n(oldend, n, value); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + return it; + } + + template + requires (std::is_constructible_v::value_type> && !std::is_const_v) + iterator insert(const_iterator pos, InputIterator first, InputIterator last) { + auto it = iterator(pos); + auto oldend = end(); + if constexpr (std::random_access_iterator) { + size_type n = static_cast(std::distance(first, last)); + if (N - _size < n) { + throw_bad_alloc(); + } + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::uninitialized_copy_n(first, n, it); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::uninitialized_copy_n(first, n, oldend); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } + std::rotate(it, oldend, end()); + } + return it; + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + iterator insert_range(const_iterator pos, R&& rg) { + auto it = iterator(pos); + auto oldend = end(); + if constexpr (std::ranges::sized_range) { + size_type n = std::ranges::size(rg); + if (N - _size < n) { + throw_bad_alloc(); + } + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, it, std::unreachable_sentinel); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, oldend, std::unreachable_sentinel); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + } else { + auto [rgend, newend] = std::ranges::uninitialized_copy(rg, std::ranges::subrange(oldend, data() + N)); + if (rgend != std::ranges::end(rg)) { + std::destroy(oldend, newend); + throw_bad_alloc(); + } else { + set_size(newend - data()); + std::rotate(it, oldend, newend); + } + } + return it; + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + iterator insert(const_iterator pos, std::initializer_list il) + requires (std::is_copy_constructible_v && !std::is_const_v) + { + return insert(pos, il.begin(), il.end()); + } + + iterator erase(const_iterator pos) + requires (!std::is_const_v) + { + auto it = iterator(pos); + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::destroy_at(it); + std::uninitialized_relocate(it + 1, oldend, it); + set_size(_size - 1); + return it; + } + #endif + std::move(it + 1, oldend, it); + std::destroy_at(oldend - 1); + set_size(_size - 1); + return it; + } + + iterator erase(const_iterator first, const_iterator last) + requires (!std::is_const_v) + { + auto ifirst = iterator(first); + auto ilast = iterator(last); + auto n = static_cast(std::distance(ifirst, ilast)); + if (n != 0) { + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::destroy(ifirst, ilast); + std::uninitialized_relocate(ilast, oldend, ifirst); + set_size(_size - n); + return ifirst; + } + #endif // __cpp_lib_trivially_relocatable + std::destroy(std::move(ilast, oldend, ifirst), oldend); + set_size(_size - n); + } + return ifirst; + } + + constexpr void clear() noexcept { + std::destroy(data(), data() + _size); + set_size(0); + } + + constexpr void swap(inplace_vector& b) + noexcept(N == 0 || (std::is_nothrow_swappable_v && std::is_nothrow_move_constructible_v)) + requires (!std::is_const_v) + { + auto& a = *this; + if (a._size < b._size) { + b.swap(a); + } else { + std::swap_ranges(a.data(), a.data() + b._size, b.data()); + #if defined(__cpp_lib_trivially_relocatable) + size_t n = a._size; + a.set_size(b._size); + std::uninitialized_relocate(a.data() + b._size, a.data() + n, b.data() + b._size); + b.set_size(n); + #else + std::uninitialized_move(a.data() + b._size, a.data() + a._size, b.data() + b._size); + std::destroy(a.data() + b._size, a.data() + a._size); + if constexpr (N != 0) { + std::swap(a._size, b._size); + } + #endif + } + } + + friend constexpr void swap(inplace_vector& a, inplace_vector& b) noexcept(noexcept(a.swap(b))) { + a.swap(b); + } + + constexpr friend bool operator==(const inplace_vector& lhs, const inplace_vector& rhs) { + if (lhs.size() != rhs.size()) return false; + return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + } + + #if __cpp_impl_three_way_comparison >= 201907L + constexpr friend auto operator<=>(const inplace_vector& lhs, const inplace_vector& rhs) { + return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + #else + constexpr friend bool operator<(const inplace_vector& a, const inplace_vector& b) { + const T* adata = a.data(); + const T* bdata = b.data(); + size_t n = (a._size < b._size) ? a._size : b._size; + for (size_t i = 0; i < n; ++i) { + if (adata[i] < bdata[i]) { + return true; + } else if (bdata[i] < adata[i]) { + return false; + } + } + return (a._size < b._size); + } + constexpr friend bool operator>(const inplace_vector& a, const inplace_vector& b) { return (b < a); } + constexpr friend bool operator<=(const inplace_vector& a, const inplace_vector& b) { return !(b < a); } + constexpr friend bool operator>=(const inplace_vector& a, const inplace_vector& b) { return !(a < b); } + constexpr friend bool operator!=(const inplace_vector& a, const inplace_vector& b) { return !(a == b); } + #endif + + private: + [[noreturn]] static void throw_bad_alloc() { + PLUGIFY_THROW("memory size would exceed capacity()", std::bad_alloc); + } + + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); + } + }; +} // namespace plg + +namespace std { + template + using inplace_vector = plg::inplace_vector; +} // namespace std + +#endif \ No newline at end of file diff --git a/include/plg/numerics.hpp b/include/plg/numerics.hpp index 9dd82f3..f975f3d 100644 --- a/include/plg/numerics.hpp +++ b/include/plg/numerics.hpp @@ -1,7 +1,6 @@ #pragma once -#include "plg/string.hpp" -#include "plg/vector.hpp" +#include "plg/config.hpp" namespace plg { PLUGIFY_WARN_PUSH() diff --git a/include/plg/path.hpp b/include/plg/path.hpp index 61343f3..7c44925 100644 --- a/include/plg/path.hpp +++ b/include/plg/path.hpp @@ -1,52 +1,57 @@ #pragma once #include -#include #include +#include + +#include "plg/config.hpp" namespace plg { - using path_view = std::basic_string_view; - using path_string = std::filesystem::path::string_type; - using path_char = path_string::value_type; - using path_diff_t = path_string::difference_type; + using path_view = std::basic_string_view; + using path_string = std::filesystem::path::string_type; + using path_char = path_string::value_type; + using path_diff_t = path_string::difference_type; -#if _WIN32 +#if PLUGIFY_PLATFORM_WINDOWS #define PLUGIFY_PATH_LITERAL(x) L##x #else #define PLUGIFY_PATH_LITERAL(x) x #endif - template - bool insensitive_equals(const path_char lhs, const path_char rhs) { - if constexpr (std::is_same_v) { - return std::towlower(lhs) == rhs; // NOLINT - } else { - return std::tolower(lhs) == rhs; - } - } - - inline bool insensitive_equals(const path_view lhs, const path_view rhs) { - return lhs.size() == rhs.size() && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); - } - - inline path_view extension_view(const std::filesystem::path& path) { - constexpr path_diff_t extension_size = 4; - if (!path.has_extension()) { return {}; } - const path_string& path_str = path.native(); - const auto offset = static_cast(path_str.size()) - extension_size; - if (offset <= 0) { return {}; } - return { path_str.cbegin() + offset, path_str.cend() }; - } - - inline bool has_extension(const std::filesystem::path& path, const path_view extension) { - return insensitive_equals(extension_view(path), extension); - } - - inline auto as_string(const std::filesystem::path& p) { -#if _WIN32 - return p.string(); // returns std::string by value + template + bool insensitive_equals(const path_char lhs, const path_char rhs) { + if constexpr (std::is_same_v) { + return std::towlower(static_cast(lhs)) == std::towlower(static_cast(rhs)); + } else { + return std::tolower(static_cast(lhs)) == std::tolower(static_cast(rhs)); + } + } + + inline bool insensitive_equals(const path_view lhs, const path_view rhs) { + return lhs.size() == rhs.size() && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); + } + + inline path_view extension_view(const std::filesystem::path& path, size_t extension_size) { + if (!path.has_extension()) { + return {}; + } + const path_string& path_str = path.native(); + const auto offset = static_cast(path_str.size() - extension_size); + if (offset <= 0) { + return {}; + } + return { path_str.cbegin() + offset, path_str.cend() }; // NOLINT(*-dangling-handle) + } + + inline bool has_extension(const std::filesystem::path& path, const path_view extension) { + return insensitive_equals(extension_view(path, extension.size()), extension); + } + + inline auto as_string(const std::filesystem::path& p) { +#if PLUGIFY_PLATFORM_WINDOWS + return p.string(); // returns std::string by value #else - return p.native(); // returns const std::string& + return p.native(); // returns const std::string& #endif - } + } } diff --git a/include/plg/plugin.hpp b/include/plg/plugin.hpp index 76f2286..550b623 100644 --- a/include/plg/plugin.hpp +++ b/include/plg/plugin.hpp @@ -181,15 +181,15 @@ namespace plg { namespace plg { namespace raw { struct vector { - [[maybe_unused]] uint8_t padding[sizeof(plg::vector)]{}; + uint8_t pad[sizeof(plg::vector)]{}; }; struct string { - [[maybe_unused]] uint8_t padding[sizeof(plg::string)]{}; + uint8_t pad[sizeof(plg::string)]{}; }; struct variant { - [[maybe_unused]] uint8_t padding[sizeof(plg::any)]{}; + uint8_t pad[sizeof(plg::any)]{}; }; } // namespace raw diff --git a/include/plg/split_buffer.hpp b/include/plg/split_buffer.hpp new file mode 100644 index 0000000..0568d15 --- /dev/null +++ b/include/plg/split_buffer.hpp @@ -0,0 +1,907 @@ +#pragma once + +#include "plg/config.hpp" +#include "plg/concepts.hpp" + +namespace plg { + template class Layout> + class split_buffer; + + template + class split_buffer_pointer_layout { + protected: + using value_type = T; + using allocator_type = Allocator; + using alloc_rr = std::remove_reference_t; + using alloc_traits = std::allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using constIterator = const_pointer; + using sentinel_type = pointer; + + public: + constexpr split_buffer_pointer_layout() + : _back_cap(nullptr) { + } + + constexpr explicit split_buffer_pointer_layout(const allocator_type& alloc) + : _back_cap(nullptr) + , _alloc(alloc) { + } + + constexpr pointer front_cap() noexcept { + return _front_cap; + } + + constexpr const_pointer front_cap() const noexcept { + return _front_cap; + } + + constexpr pointer begin() noexcept { + return _begin; + } + + constexpr const_pointer begin() const noexcept { + return _begin; + } + + constexpr pointer end() noexcept { + return _end; + } + + constexpr pointer end() const noexcept { + return _end; + } + + constexpr size_type size() const noexcept { + return static_cast(_end - _begin); + } + + constexpr bool empty() const noexcept { + return _begin == _end; + } + + constexpr size_type capacity() const noexcept { + return static_cast(_back_cap - _front_cap); + } + + constexpr allocator_type& get_allocator() noexcept { + return _alloc; + } + + constexpr const allocator_type& get_allocator() const noexcept { + return _alloc; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type + // deduction, not explicit types. + constexpr sentinel_type raw_sentinel() const noexcept { + return _end; + } + + constexpr sentinel_type raw_capacity() const noexcept { + return _back_cap; + } + + constexpr void set_data(pointer new_first) noexcept { + _front_cap = new_first; + } + + constexpr void + set_valid_range(pointer new_begin, pointer new_end) noexcept { + _begin = new_begin; + _end = new_end; + } + + constexpr void + set_valid_range(pointer new_begin, size_type new_size) noexcept { + _begin = new_begin; + _end = _begin + new_size; + } + + constexpr void set_sentinel(pointer new_end) noexcept { + PLUGIFY_ASSERT(_front_cap <= new_end, "new_end cannot precede _front_cap"); + _end = new_end; + } + + constexpr void set_sentinel(size_type new_size) noexcept { + _end = _begin + new_size; + } + + constexpr void set_capacity(size_type new_capacity) noexcept { + _back_cap = _front_cap + new_capacity; + } + + constexpr void set_capacity(pointer new_capacity) noexcept { + _back_cap = new_capacity; + } + + constexpr size_type front_spare() const noexcept { + return static_cast(_begin - _front_cap); + } + + constexpr size_type back_spare() const noexcept { + return static_cast(_back_cap - _end); + } + + constexpr reference back() noexcept { + return *(_end - 1); + } + + constexpr const_reference back() const noexcept { + return *(_end - 1); + } + + constexpr void swap_without_allocator( + split_buffer_pointer_layout< + split_buffer, + value_type, + alloc_rr&>& other + ) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_back_cap, other._back_cap); + std::swap(_end, other._end); + } + + constexpr void swap(split_buffer_pointer_layout& other) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_back_cap, other._back_cap); + std::swap(_end, other._end); + swap_allocator(_alloc, other._alloc); + } + + constexpr void reset() noexcept { + _front_cap = nullptr; + _begin = nullptr; + _end = nullptr; + _back_cap = nullptr; + } + + constexpr void copy_without_alloc( + const split_buffer_pointer_layout& other + ) noexcept(std::is_nothrow_copy_assignable::value) { + _front_cap = other._front_cap; + _begin = other._begin; + _end = other._end; + _back_cap = other._back_cap; + } + + private: + pointer _front_cap = nullptr; + pointer _begin = nullptr; + pointer _end = nullptr; + pointer _back_cap = nullptr; + PLUGIFY_NO_UNIQUE_ADDRESS allocator_type _alloc; + + template + friend class split_buffer_pointer_layout; + }; + + template + class split_buffer_size_layout { + protected: + using value_type = T; + using allocator_type = Allocator; + using alloc_rr = std::remove_reference_t; + using alloc_traits = std::allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using constIterator = const_pointer; + using sentinel_type = size_type; + + public: + constexpr split_buffer_size_layout() = default; + + constexpr explicit split_buffer_size_layout(const allocator_type& alloc) + : _alloc(alloc) { + } + + constexpr pointer front_cap() noexcept { + return _front_cap; + } + + constexpr const_pointer front_cap() const noexcept { + return _front_cap; + } + + constexpr pointer begin() noexcept { + return _begin; + } + + constexpr const_pointer begin() const noexcept { + return _begin; + } + + constexpr pointer end() noexcept { + return _begin + _size; + } + + constexpr pointer end() const noexcept { + return _begin + _size; + } + + constexpr size_type size() const noexcept { + return _size; + } + + constexpr bool empty() const noexcept { + return _size == 0; + } + + constexpr size_type capacity() const noexcept { + return _cap; + } + + constexpr allocator_type& get_allocator() noexcept { + return _alloc; + } + + constexpr const allocator_type& get_allocator() const noexcept { + return _alloc; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type + // deduction, not explicit types. + constexpr sentinel_type raw_sentinel() const noexcept { + return _size; + } + + constexpr sentinel_type raw_capacity() const noexcept { + return _cap; + } + + constexpr void set_data(pointer new_first) noexcept { + _front_cap = new_first; + } + + constexpr void + set_valid_range(pointer new_begin, pointer new_end) noexcept { + // Size-based split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + _size -= new_begin - _begin; + _begin = new_begin; + set_sentinel(new_end); + } + + constexpr void + set_valid_range(pointer new_begin, size_type new_size) noexcept { + // Size-based split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + _size -= new_begin - _begin; + _begin = new_begin; + set_sentinel(new_size); + } + + constexpr void set_sentinel(pointer new_end) noexcept { + _LIBCPP_ASSERT_INTERNAL(_front_cap <= new_end, "new_end cannot precede _front_cap"); + _size += new_end - end(); + } + + constexpr void set_sentinel(size_type new_size) noexcept { + _size = new_size; + } + + constexpr void set_capacity(size_type new_capacity) noexcept { + _cap = new_capacity; + } + + constexpr void set_capacity(pointer new_capacity) noexcept { + _cap = new_capacity - _begin; + } + + constexpr size_type front_spare() const noexcept { + return static_cast(_begin - _front_cap); + } + + constexpr size_type back_spare() const noexcept { + // `_cap - _end` tells us the total number of spares when in size-mode. We need to remove + // the front_spare from the count. + return _cap - _size - front_spare(); + } + + constexpr reference back() noexcept { + return _begin[_size - 1]; + } + + constexpr const_reference back() const noexcept { + return _begin[_size - 1]; + } + + constexpr void swap_without_allocator( + split_buffer_pointer_layout< + split_buffer, + value_type, + alloc_rr&>& other + ) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_cap, other._cap); + std::swap(_size, other._size); + } + + constexpr void swap(split_buffer_size_layout& other) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_cap, other._cap); + std::swap(_size, other._size); + swap_allocator(_alloc, other._alloc); + } + + constexpr void reset() noexcept { + _front_cap = nullptr; + _begin = nullptr; + _size = 0; + _cap = 0; + } + + constexpr void copy_without_alloc( + const split_buffer_size_layout& other + ) noexcept(std::is_nothrow_copy_assignable::value) { + _front_cap = other._front_cap; + _begin = other._begin; + _cap = other._cap; + _size = other._size; + } + + private: + pointer _front_cap = nullptr; + pointer _begin = nullptr; + size_type _size = 0; + size_type _cap = 0; + PLUGIFY_NO_UNIQUE_ADDRESS allocator_type _alloc; + + template + friend class split_buffer_size_layout; + }; + + // `split_buffer` is a contiguous array data structure. It may hold spare capacity at both ends of + // the sequence. This allows for a `split_buffer` to grow from both the front and the back without + // relocating its contents until it runs out of room. This characteristic sets it apart from + // `std::vector`, which only holds spare capacity at its end. As such, `split_buffer` is useful + // for implementing both `std::vector` and `std::deque`. + // + // The sequence is stored as a contiguous chunk of memory delimited by the following "pointers" (`o` + // denotes uninitialized memory and `x` denotes a valid object): + // + // |oooooooooooooooooooxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxoooooooooooooooooooooooo| + // ^ ^ ^ ^ + // _front_cap _begin _end _back_cap + // + // The range [_front_cap, _begin) contains uninitialized memory. It is referred to as the "front + // spare capacity". The range [_begin, _end) contains valid objects. It is referred to as the "valid + // range". The range [_end, _back_cap) contains uninitialized memory. It is referred to as the "back + // spare capacity". + // + // The layout of `split_buffer` is determined by the `Layout` template template parameter. This + // `Layout` allows the above pointers to be stored as different representations, such as integer + // offsets. A layout class template must provide the following interface: + // + // template + // class layout { + // protected: + // using value_type = T; + // using allocator_type = Allocator; + // using alloc_rr = std::remove_reference_t; + // using alloc_traits = allocator_traits; + // using reference = value_type&; + // using const_reference = const value_type&; + // using size_type = typename alloc_traits::size_type; + // using difference_type = typename alloc_traits::difference_type; + // using pointer = typename alloc_traits::pointer; + // using const_pointer = typename alloc_traits::const_pointer; + // using iterator = pointer; + // using constIterator = const_pointer; + // using sentinel_type = /* type that represents the layout's sentinel */; + // + // public: + // layout() = default; + // explicit layout(const allocator_type&); + // + // pointer front_cap(); + // const_pointer front_cap() const; + // + // pointer begin(); + // const_pointer begin() const; + // + // pointer end(); + // pointer end() const; + // + // size_type size() const; + // bool empty() const; + // size_type capacity() const; + // + // allocator_type& get_allocator(); + // allocator_type const& get_allocator() const; + // + // sentinel_type raw_sentinel() const; + // sentinel_type raw_capacity() const; + // + // void set_data(pointer); + // void set_valid_range(pointer begin, pointer end); + // void set_valid_range(pointer begin, size_type size); + // void set_sentinel(pointer end); + // void set_sentinel(size_type size); + // + // void set_capacity(size_type capacity); + // void set_capacity(pointer capacity); + // + // size_type front_spare() const; + // size_type back_spare() const; + // + // reference back(); + // const_reference back() const; + // + // template + // void swap_without_allocator(_OtherLayout&); + // void swap(layout&); + // + // void reset(); + // void copy_without_alloc(layout const&); + // }; + // + template class Layout> + class split_buffer : Layout, T, Allocator> { + using base_type = Layout, T, Allocator>; + + public: + using base_type::back_spare; + using base_type::copy_without_alloc; + using base_type::front_cap; + using base_type::front_spare; + using base_type::get_allocator; + using base_type::raw_capacity; + using base_type::raw_sentinel; + using base_type::reset; + using base_type::set_capacity; + using base_type::set_data; + using base_type::set_sentinel; + using base_type::set_valid_range; + + using typename base_type::alloc_rr; + using typename base_type::alloc_traits; + using typename base_type::allocator_type; + using typename base_type::constIterator; + using typename base_type::const_pointer; + using typename base_type::const_reference; + using typename base_type::difference_type; + using typename base_type::iterator; + using typename base_type::pointer; + using typename base_type::reference; + using typename base_type::size_type; + using typename base_type::value_type; + + // A split_buffer contains the following members which may be trivially relocatable: + // - pointer: may be trivially relocatable, so it's checked + // - allocator_type: may be trivially relocatable, so it's checked + // split_buffer doesn't have any self-references, so it's trivially relocatable if its members + // are. + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value, + split_buffer, + void>; + + split_buffer(const split_buffer&) = delete; + split_buffer& operator=(const split_buffer&) = delete; + + split_buffer() = default; + + constexpr explicit split_buffer(alloc_rr& a) + : base_type(a) { + } + + constexpr explicit split_buffer(const alloc_rr& a) + : base_type(a) { + } + + constexpr split_buffer(size_type cap, size_type start, alloc_rr& a); + + constexpr + split_buffer(split_buffer&& c) noexcept(std::is_nothrow_move_constructible_v); + + constexpr split_buffer(split_buffer&& c, const alloc_rr& a); + + + constexpr split_buffer& operator=(split_buffer&& c) noexcept( + (alloc_traits::propagate_on_container_move_assignment::value + && std::is_nothrow_move_assignable_v) + || !alloc_traits::propagate_on_container_move_assignment::value + ); + + constexpr ~split_buffer(); + + using base_type::back; + using base_type::begin; + using base_type::capacity; + using base_type::empty; + using base_type::end; + using base_type::size; + + constexpr void clear() noexcept { + destruct_at_end(begin()); + } + + constexpr reference front() { + return *begin(); + } + + constexpr const_reference front() const { + return *begin(); + } + + constexpr void shrink_to_fit() noexcept; + + template + constexpr void emplace_front(Args&&... args); + template + constexpr void emplace_back(Args&&... args); + + constexpr void pop_front() { + destruct_at_begin(begin() + 1); + } + + constexpr void pop_back() { + destruct_at_end(end() - 1); + } + + constexpr void construct_at_end(size_type n); + constexpr void construct_at_end(size_type n, const_reference x); + + template + constexpr void + construct_at_end(ForwardIterator first, ForwardIterator last); + + template + constexpr void + construct_at_end_with_sentinel(Iterator first, Sentinel last); + + template + constexpr void construct_at_end_with_size(Iterator first, size_type n); + + constexpr void destruct_at_begin(pointer new_begin) { + destruct_at_begin(new_begin, std::is_trivially_destructible()); + } + + constexpr void destruct_at_begin(pointer new_begin, std::false_type); + constexpr void destruct_at_begin(pointer new_begin, std::true_type); + + constexpr void destruct_at_end(pointer new_last) noexcept { + destruct_at_end(new_last, std::false_type()); + } + + constexpr void destruct_at_end(pointer new_last, std::false_type) noexcept; + constexpr void destruct_at_end(pointer new_last, std::true_type) noexcept; + + constexpr void swap( + split_buffer& x + ) noexcept(!alloc_traits::propagate_on_container_swap::value || std::is_nothrow_swappable_v); + + constexpr bool invariants() const { + if (front_cap() == nullptr) { + if (begin() != nullptr) { + return false; + } + + if (!empty()) { + return false; + } + + if (capacity() != 0) { + return false; + } + + return true; + } else { + if (begin() < front_cap()) { + return false; + } + + if (capacity() < size()) { + return false; + } + + if (end() < begin()) { + return false; + } + + return true; + } + } + + constexpr void + swap_without_allocator(split_buffer& other) noexcept { + base_type::swap_without_allocator(other); + } + + private: + constexpr void move_assign_alloc(split_buffer& c, std::true_type) noexcept( + std::is_nothrow_move_assignable_v + ) { + get_allocator() = std::move(c.get_allocator()); + } + + constexpr void move_assign_alloc(split_buffer&, std::false_type) noexcept { + } + + struct ConstructTransaction { + constexpr explicit ConstructTransaction( + split_buffer* parent, + pointer p, + size_type n + ) noexcept + : _pos(p) + , _end(p + n) + , _parent(parent) { + } + + constexpr ~ConstructTransaction() { + _parent->set_sentinel(_pos); + } + + pointer _pos; + const pointer _end; + + private: + split_buffer* _parent; + }; + + template class L2> + friend class split_buffer; + }; + + // Default constructs n objects starting at `end()` + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == size() + n + template class Layout> + constexpr void split_buffer::construct_at_end(size_type n) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos)); + } + } + + // Copy constructs n objects starting at `end()` from x + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == old size() + n + // Postcondition: [i] == x for all i in [size() - n, n) + template class Layout> + constexpr void + split_buffer::construct_at_end(size_type n, const_reference x) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos), x); + } + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end_with_sentinel(Iterator first, Sentinel last) { + alloc_rr& a = get_allocator(); + for (; first != last; ++first) { + if (back_spare() == 0) { + size_type old_cap = capacity(); + size_type new_cap = std::max(2 * old_cap, 8); + split_buffer buf(new_cap, 0, a); + pointer buf_end = buf.end(); + pointer cur_end = end(); + for (pointer p = begin(); p != cur_end; ++p) { + alloc_traits::construct(buf.get_allocator(), std::to_address(buf_end), std::move(*p)); + buf.set_sentinel(++buf_end); + } + swap(buf); + } + + alloc_traits::construct(a, std::to_address(end()), *first); + set_sentinel(size() + 1); + } + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end(ForwardIterator first, ForwardIterator last) { + construct_at_end_with_size(first, std::distance(first, last)); + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end_with_size(ForwardIterator first, size_type n) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos, (void) ++first) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos), *first); + } + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_begin(pointer new_begin, std::false_type) { + pointer pos = begin(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (pos != new_begin) { + alloc_traits::destroy(get_allocator(), std::to_address(pos++)); + } + set_valid_range(pos, end()); + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_begin(pointer new_begin, std::true_type) { + set_valid_range(new_begin, end()); + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_end(pointer new_last, std::false_type) noexcept { + pointer cur_end = end(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (new_last != cur_end) { + alloc_traits::destroy(get_allocator(), std::to_address(--cur_end)); + } + set_sentinel(cur_end); + } + + template class Layout> + constexpr split_buffer::split_buffer(size_type cap, size_type start, alloc_rr& a) + : base_type(a) { + PLUGIFY_ASSERT(cap >= start, "can't have a start point outside the capacity"); + if (cap > 0) { + auto allocation = allocate_at_least(get_allocator(), cap); + set_data(allocation.ptr); + cap = allocation.count; + } + + pointer pos = front_cap() + start; + set_valid_range(pos, pos); + set_capacity(cap); + } + + template class Layout> + constexpr split_buffer::~split_buffer() { + clear(); + if (front_cap()) { + alloc_traits::deallocate(get_allocator(), front_cap(), capacity()); + } + } + + template class Layout> + constexpr split_buffer::split_buffer(split_buffer&& c) noexcept( + std::is_nothrow_move_constructible_v + ) + : base_type(std::move(c)) { + c.reset(); + } + + template class Layout> + constexpr split_buffer::split_buffer(split_buffer&& c, const alloc_rr& a) + : base_type(a) { + if (a == c.get_allocator()) { + set_data(c.front_cap()); + set_valid_range(c.begin(), c.end()); + set_capacity(c.capacity()); + c.reset(); + } else { + auto allocation = allocate_at_least(get_allocator(), c.size()); + set_data(allocation.ptr); + set_valid_range(front_cap(), front_cap()); + set_capacity(allocation.count); + using Ip = std::move_iterator; + construct_at_end(Ip(c.begin()), Ip(c.end())); + } + } + + template class Layout> + constexpr split_buffer& + split_buffer::operator=(split_buffer&& c) noexcept( + (alloc_traits::propagate_on_container_move_assignment::value + && std::is_nothrow_move_assignable_v) + || !alloc_traits::propagate_on_container_move_assignment::value + ) { + clear(); + shrink_to_fit(); + copy_without_alloc(c); + move_assign_alloc( + c, + std::integral_constant() + ); + c.reset(); + return *this; + } + + template class Layout> + constexpr void split_buffer::swap( + split_buffer& x + ) noexcept(!alloc_traits::propagate_on_container_swap::value || std::is_nothrow_swappable_v) { + base_type::swap(x); + } + + template class Layout> + constexpr void split_buffer::shrink_to_fit() noexcept { + if (capacity() > size()) { +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + split_buffer t(size(), 0, get_allocator()); + if (t.capacity() < capacity()) { + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(end())); + t.set_sentinel(size()); + swap_without_allocator(t); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } + } + + template class Layout> + template + constexpr void split_buffer::emplace_front(Args&&... args) { + if (front_spare() == 0) { + pointer cur_end = end(); + if (back_spare() > 0) { + // The elements are pressed up against the front of the buffer: we need to move them + // back a little bit to make `emplace_front` have amortised O(1) complexity. + difference_type d = back_spare(); + d = (d + 1) / 2; + auto new_end = cur_end + d; + set_valid_range(std::move_backward(begin(), cur_end, new_end), new_end); + } else { + size_type c = std::max(2 * capacity(), 1); + split_buffer t(c, (c + 3) / 4, get_allocator()); + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(cur_end)); + base_type::swap_without_allocator(t); + } + } + + alloc_traits::construct(get_allocator(), std::to_address(begin() - 1), std::forward(args)...); + set_valid_range(begin() - 1, size() + 1); + } + + template class Layout> + template + constexpr void split_buffer::emplace_back(Args&&... args) { + pointer cur_end = end(); + if (back_spare() == 0) { + if (front_spare() > 0) { + difference_type d = front_spare(); + d = (d + 1) / 2; + cur_end = std::move(begin(), cur_end, begin() - d); + set_valid_range(begin() - d, cur_end); + } else { + size_type c = std::max(2 * capacity(), 1); + split_buffer t(c, c / 4, get_allocator()); + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(cur_end)); + base_type::swap_without_allocator(t); + } + } + + alloc_traits::construct(get_allocator(), std::to_address(cur_end), std::forward(args)...); + set_sentinel(++cur_end); + } + + template class Layout> + inline constexpr void + swap(split_buffer& x, split_buffer& y) noexcept( + noexcept(x.swap(y)) + ) { + x.swap(y); + } +} // namespace plg diff --git a/include/plg/string.hpp b/include/plg/string.hpp index 175bed2..c2dbacf 100644 --- a/include/plg/string.hpp +++ b/include/plg/string.hpp @@ -1,5 +1,615 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #pragma once +// clang-format off + +/* + string synopsis + +#include +#include + +namespace std +{ + +template +class fpos +{ +private: + stateT st; +public: + fpos(streamoff = streamoff()); + + operator streamoff() const; + + stateT state() const; + void state(stateT); + + fpos& operator+=(streamoff); + fpos operator+ (streamoff) const; + fpos& operator-=(streamoff); + fpos operator- (streamoff) const; +}; + +template streamoff operator-(const fpos& x, const fpos& y); + +template bool operator==(const fpos& x, const fpos& y); +template bool operator!=(const fpos& x, const fpos& y); + +template +struct char_traits +{ + using char_type = charT; + using int_type = ...; + using off_type = streamoff; + using pos_type = streampos; + using state_type = mbstate_t; + using comparison_category = strong_ordering; // Since C++20 only for the specializations + // char, wchar_t, char8_t, char16_t, and char32_t. + + static void assign(char_type& c1, const char_type& c2) noexcept; + static constexpr bool eq(char_type c1, char_type c2) noexcept; + static constexpr bool lt(char_type c1, char_type c2) noexcept; + + static int compare(const char_type* s1, const char_type* s2, size_t n); + static size_t length(const char_type* s); + static const char_type* find(const char_type* s, size_t n, const char_type& a); + static char_type* move(char_type* s1, const char_type* s2, size_t n); + static char_type* copy(char_type* s1, const char_type* s2, size_t n); + static char_type* assign(char_type* s, size_t n, char_type a); + + static constexpr int_type not_eof(int_type c) noexcept; + static constexpr char_type to_char_type(int_type c) noexcept; + static constexpr int_type to_int_type(char_type c) noexcept; + static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept; + static constexpr int_type eof() noexcept; +}; + +template <> struct char_traits; +template <> struct char_traits; +template <> struct char_traits; // C++20 +template <> struct char_traits; +template <> struct char_traits; + +template, class Allocator = allocator > +class basic_string +{ +public: +// types: + typedef traits traits_type; + typedef typename traits_type::char_type value_type; + typedef Allocator allocator_type; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef implementation-defined iterator; + typedef implementation-defined const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static const size_type npos = -1; + + basic_string() + noexcept(std::is_nothrow_default_constructible::value); // constexpr since C++20 + explicit basic_string(const allocator_type& a); // constexpr since C++20 + basic_string(const basic_string& str); // constexpr since C++20 + basic_string(basic_string&& str) + noexcept(std::is_nothrow_move_constructible::value); // constexpr since C++20 + basic_string(const basic_string& str, size_type pos, + const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(const basic_string& str, size_type pos, size_type n, + const Allocator& a = Allocator()); // constexpr since C++20 + constexpr basic_string( + basic_string&& str, size_type pos, const Allocator& a = Allocator()); // since C++23 + constexpr basic_string( + basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); // since C++23 + template + basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); // C++17, constexpr since C++20 + template + explicit basic_string(const T& t, const Allocator& a = Allocator()); // C++17, constexpr since C++20 + basic_string(const value_type* s, const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(const value_type* s, size_type n, const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(nullptr_t) = delete; // C++23 + basic_string(size_type n, value_type c, const allocator_type& a = allocator_type()); // constexpr since C++20 + template + basic_string(InputIterator begin, InputIterator end, + const allocator_type& a = allocator_type()); // constexpr since C++20 + template R> + constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); // since C++23 + basic_string(std::initializer_list, const Allocator& = Allocator()); // constexpr since C++20 + basic_string(const basic_string&, const Allocator&); // constexpr since C++20 + basic_string(basic_string&&, const Allocator&); // constexpr since C++20 + + ~basic_string(); // constexpr since C++20 + + operator std::basic_string_view() const noexcept; // constexpr since C++20 + + basic_string& operator=(const basic_string& str); // constexpr since C++20 + template + basic_string& operator=(const T& t); // C++17, constexpr since C++20 + basic_string& operator=(basic_string&& str) + noexcept( + allocator_type::propagate_on_container_move_assignment::value || + allocator_type::is_always_equal::value ); // C++17, constexpr since C++20 + basic_string& operator=(const value_type* s); // constexpr since C++20 + basic_string& operator=(nullptr_t) = delete; // C++23 + basic_string& operator=(value_type c); // constexpr since C++20 + basic_string& operator=(std::initializer_list); // constexpr since C++20 + + iterator begin() noexcept; // constexpr since C++20 + const_iterator begin() const noexcept; // constexpr since C++20 + iterator end() noexcept; // constexpr since C++20 + const_iterator end() const noexcept; // constexpr since C++20 + + reverse_iterator rbegin() noexcept; // constexpr since C++20 + const_reverse_iterator rbegin() const noexcept; // constexpr since C++20 + reverse_iterator rend() noexcept; // constexpr since C++20 + const_reverse_iterator rend() const noexcept; // constexpr since C++20 + + const_iterator cbegin() const noexcept; // constexpr since C++20 + const_iterator cend() const noexcept; // constexpr since C++20 + const_reverse_iterator crbegin() const noexcept; // constexpr since C++20 + const_reverse_iterator crend() const noexcept; // constexpr since C++20 + + size_type size() const noexcept; // constexpr since C++20 + size_type length() const noexcept; // constexpr since C++20 + size_type max_size() const noexcept; // constexpr since C++20 + size_type capacity() const noexcept; // constexpr since C++20 + + void resize(size_type n, value_type c); // constexpr since C++20 + void resize(size_type n); // constexpr since C++20 + + template + constexpr void resize_and_overwrite(size_type n, Operation op); // since C++23 + + void reserve(size_type res_arg); // constexpr since C++20 + void reserve(); // deprecated in C++20, removed in C++26 + void shrink_to_fit(); // constexpr since C++20 + void clear() noexcept; // constexpr since C++20 + bool empty() const noexcept; // constexpr since C++20 + + const_reference operator[](size_type pos) const; // constexpr since C++20 + reference operator[](size_type pos); // constexpr since C++20 + + const_reference at(size_type n) const; // constexpr since C++20 + reference at(size_type n); // constexpr since C++20 + + basic_string& operator+=(const basic_string& str); // constexpr since C++20 + template + basic_string& operator+=(const T& t); // C++17, constexpr since C++20 + basic_string& operator+=(const value_type* s); // constexpr since C++20 + basic_string& operator+=(value_type c); // constexpr since C++20 + basic_string& operator+=(std::initializer_list); // constexpr since C++20 + + basic_string& append(const basic_string& str); // constexpr since C++20 + template + basic_string& append(const T& t); // C++17, constexpr since C++20 + basic_string& append(const basic_string& str, size_type pos, size_type n=npos); // C++14, constexpr since C++20 + template + basic_string& append(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 + basic_string& append(const value_type* s, size_type n); // constexpr since C++20 + basic_string& append(const value_type* s); // constexpr since C++20 + basic_string& append(size_type n, value_type c); // constexpr since C++20 + template + basic_string& append(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& append_range(R&& rg); // C++23 + basic_string& append(std::initializer_list); // constexpr since C++20 + + void push_back(value_type c); // constexpr since C++20 + void pop_back(); // constexpr since C++20 + reference front(); // constexpr since C++20 + const_reference front() const; // constexpr since C++20 + reference back(); // constexpr since C++20 + const_reference back() const; // constexpr since C++20 + + basic_string& assign(const basic_string& str); // constexpr since C++20 + template + basic_string& assign(const T& t); // C++17, constexpr since C++20 + basic_string& assign(basic_string&& str); // constexpr since C++20 + basic_string& assign(const basic_string& str, size_type pos, size_type n=npos); // C++14, constexpr since C++20 + template + basic_string& assign(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 + basic_string& assign(const value_type* s, size_type n); // constexpr since C++20 + basic_string& assign(const value_type* s); // constexpr since C++20 + basic_string& assign(size_type n, value_type c); // constexpr since C++20 + template + basic_string& assign(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& assign_range(R&& rg); // C++23 + basic_string& assign(std::initializer_list); // constexpr since C++20 + + basic_string& insert(size_type pos1, const basic_string& str); // constexpr since C++20 + template + basic_string& insert(size_type pos1, const T& t); // constexpr since C++20 + basic_string& insert(size_type pos1, const basic_string& str, + size_type pos2, size_type n2=npos); // constexpr since C++20 + template + basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n=npos); // C++17, constexpr since C++20 + basic_string& insert(size_type pos, const value_type* s, size_type n=npos); // C++14, constexpr since C++20 + basic_string& insert(size_type pos, const value_type* s); // constexpr since C++20 + basic_string& insert(size_type pos, size_type n, value_type c); // constexpr since C++20 + iterator insert(const_iterator p, value_type c); // constexpr since C++20 + iterator insert(const_iterator p, size_type n, value_type c); // constexpr since C++20 + template + iterator insert(const_iterator p, InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr iterator insert_range(const_iterator p, R&& rg); // C++23 + iterator insert(const_iterator p, std::initializer_list); // constexpr since C++20 + + basic_string& erase(size_type pos = 0, size_type n = npos); // constexpr since C++20 + iterator erase(const_iterator position); // constexpr since C++20 + iterator erase(const_iterator first, const_iterator last); // constexpr since C++20 + + basic_string& replace(size_type pos1, size_type n1, const basic_string& str); // constexpr since C++20 + template + basic_string& replace(size_type pos1, size_type n1, const T& t); // C++17, constexpr since C++20 + basic_string& replace(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2=npos); // C++14, constexpr since C++20 + template + basic_string& replace(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2=npos); // C++17, constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, const value_type* s, size_type n2); // constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, const value_type* s); // constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str); // constexpr since C++20 + template + basic_string& replace(const_iterator i1, const_iterator i2, const T& t); // C++17, constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, size_type n, value_type c); // constexpr since C++20 + template + basic_string& replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2); // constexpr since C++20 + template R> + constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); // C++23 + basic_string& replace(const_iterator i1, const_iterator i2, std::initializer_list); // constexpr since C++20 + + size_type copy(value_type* s, size_type n, size_type pos = 0) const; // constexpr since C++20 + basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr in C++20, removed in C++23 + basic_string substr(size_type pos = 0, size_type n = npos) const&; // since C++23 + constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; // since C++23 + void swap(basic_string& str) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); // C++17, constexpr since C++20 + + const value_type* c_str() const noexcept; // constexpr since C++20 + const value_type* data() const noexcept; // constexpr since C++20 + value_type* data() noexcept; // C++17, constexpr since C++20 + + allocator_type get_allocator() const noexcept; // constexpr since C++20 + + size_type find(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type rfind(const T& t, size_type pos = npos) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type rfind(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type rfind(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type rfind(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find_first_of(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_first_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_first_of(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find_first_of(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type find_last_of(const T& t, size_type pos = npos) const noexcept noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_last_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_last_of(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type find_last_of(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_first_not_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_first_not_of(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_last_not_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_last_not_of(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + int compare(const basic_string& str) const noexcept; // constexpr since C++20 + template + int compare(const T& t) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + int compare(size_type pos1, size_type n1, const basic_string& str) const; // constexpr since C++20 + template + int compare(size_type pos1, size_type n1, const T& t) const; // C++17, constexpr since C++20 + int compare(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2=npos) const; // C++14, constexpr since C++20 + template + int compare(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2=npos) const; // C++17, constexpr since C++20 + int compare(const value_type* s) const noexcept; // constexpr since C++20 + int compare(size_type pos1, size_type n1, const value_type* s) const; // constexpr since C++20 + int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; // constexpr since C++20 + + constexpr bool starts_with(std::basic_string_view sv) const noexcept; // C++20 + constexpr bool starts_with(charT c) const noexcept; // C++20 + constexpr bool starts_with(const charT* s) const; // C++20 + constexpr bool ends_with(std::basic_string_view sv) const noexcept; // C++20 + constexpr bool ends_with(charT c) const noexcept; // C++20 + constexpr bool ends_with(const charT* s) const; // C++20 + + constexpr bool contains(std::basic_string_view sv) const noexcept; // C++23 + constexpr bool contains(charT c) const noexcept; // C++23 + constexpr bool contains(const charT* s) const; // C++23 +}; + +template::value_type>> +basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string::value_type, + char_traits::value_type>, + Allocator>; // C++17 + +template>> + basic_string(from_range_t, R&&, Allocator = Allocator()) + -> basic_string, char_traits>, + Allocator>; // C++23 + +template> + explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) + -> basic_string; // C++17 + +template> + basic_string(std::basic_string_view, + typename see below::size_type, typename see below::size_type, + const Allocator& = Allocator()) + -> basic_string; // C++17 + +template +basic_string +operator+(const basic_string& lhs, + const basic_string& rhs); // constexpr since C++20 + +template +basic_string +operator+(const charT* lhs , const basic_string&rhs); // constexpr since C++20 + +template +basic_string +operator+(charT lhs, const basic_string& rhs); // constexpr since C++20 + +template +basic_string +operator+(const basic_string& lhs, const charT* rhs); // constexpr since C++20 + +template +basic_string +operator+(const basic_string& lhs, charT rhs); // constexpr since C++20 + +template + constexpr basic_string + operator+(const basic_string& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(basic_string&& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + const basic_string& rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + basic_string&& rhs); // Since C++26 + + +template +bool operator==(const basic_string& lhs, + const basic_string& rhs) noexcept; // constexpr since C++20 + +template +bool operator==(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator==(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 + +template +bool operator!=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator!=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator!=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator< (const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator< (const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator< (const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator> (const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator> (const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator> (const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator<=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator<=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator<=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator>=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator>=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator>=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const basic_string& rhs) noexcept; + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const charT* rhs) noexcept; + +template +void swap(basic_string& lhs, + basic_string& rhs) + noexcept(noexcept(lhs.swap(rhs))); // constexpr since C++20 + +template +std::basic_istream& +operator>>(std::basic_istream& is, basic_string& str); + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const basic_string& str); + +template +std::basic_istream& +getline(std::basic_istream& is, basic_string& str, + charT delim); + +template +std::basic_istream& +getline(std::basic_istream& is, basic_string& str); + +template +constexpr typename basic_string::size_type +erase(basic_string& c, const U& value); // C++20 +template +constexpr typename basic_string::size_type +erase_if(basic_string& c, Predicate pred); // C++20 + +typedef basic_string string; +typedef basic_string wstring; +typedef basic_string u8string; // C++20 +typedef basic_string u16string; +typedef basic_string u32string; + +int stoi (const string& str, size_t* idx = nullptr, int base = 10); +long stol (const string& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul (const string& str, size_t* idx = nullptr, int base = 10); +long long stoll (const string& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10); + +float stof (const string& str, size_t* idx = nullptr); +double stod (const string& str, size_t* idx = nullptr); +long double stold(const string& str, size_t* idx = nullptr); + +string to_string(int val); +string to_string(unsigned val); +string to_string(long val); +string to_string(unsigned long val); +string to_string(long long val); +string to_string(unsigned long long val); +string to_string(float val); +string to_string(double val); +string to_string(long double val); + +int stoi (const wstring& str, size_t* idx = nullptr, int base = 10); +long stol (const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul (const wstring& str, size_t* idx = nullptr, int base = 10); +long long stoll (const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10); + +float stof (const wstring& str, size_t* idx = nullptr); +double stod (const wstring& str, size_t* idx = nullptr); +long double stold(const wstring& str, size_t* idx = nullptr); + +wstring to_wstring(int val); +wstring to_wstring(unsigned val); +wstring to_wstring(long val); +wstring to_wstring(unsigned long val); +wstring to_wstring(long long val); +wstring to_wstring(unsigned long long val); +wstring to_wstring(float val); +wstring to_wstring(double val); +wstring to_wstring(long double val); + +template <> struct hash; +template <> struct hash; // C++20 +template <> struct hash; +template <> struct hash; +template <> struct hash; + +basic_string operator""s( const char *str, size_t len ); // C++14, constexpr since C++20 +basic_string operator""s( const wchar_t *str, size_t len ); // C++14, constexpr since C++20 +constexpr basic_string operator""s( const char8_t *str, size_t len ); // C++20 +basic_string operator""s( const char16_t *str, size_t len ); // C++14, constexpr since C++20 +basic_string operator""s( const char32_t *str, size_t len ); // C++14, constexpr since C++20 + +} // std + +*/ + +// clang-format on + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "plg/allocator.hpp" +#include "plg/guards.hpp" +#include "plg/concepts.hpp" + +#ifndef PLUGIFY_STRING_NO_STD_FORMAT +#include "plg/format.hpp" +#endif + // Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc #if PLUGIFY_COMPILER_CLANG # pragma clang system_header @@ -7,1685 +617,2992 @@ # pragma GCC system_header #endif -#include // for std::initializer_list -#include // for std::basic_string_view -#include // for std::is_constant_evaluated, std::declval, std::false_type -#include // for std::min, std::max -#include // for std::unsigned_integral, std::signed_integral -#include // for std::distance, std::next, std::iterator_traits, std::input_iterator -#include // for std::move, std::hash -#include // for std::strong_ordering -#include // for std::allocator, std::swap, std::allocator_traits -#include // for std::numeric_limits -#include // for std::to_chars +// from https://github.com/llvm/llvm-project/blob/main/libcxx/include/string +namespace plg { + // basic_string + template + class basic_string; -#include -#include -#include + template + constexpr basic_string concatenate_strings( + const Allocator& alloc, + std::type_identity_t> str1, + std::type_identity_t> str2 + ); -#if PLUGIFY_STRING_CONTAINERS_RANGES && (__cplusplus <= 202002L || !__has_include() || !defined(__cpp_lib_containers_ranges)) -# undef PLUGIFY_STRING_CONTAINERS_RANGES -# define PLUGIFY_STRING_CONTAINERS_RANGES 0 -#endif + template + inline const bool string_is_trivial_iterator_v = false; -#if PLUGIFY_STRING_CONTAINERS_RANGES -# include -#endif + template + concept string_is_trivial_iterator = std::is_arithmetic_v; -#ifndef PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS -# include -#endif + template + concept string_view_convertible = std::is_convertible_v> && !std::is_convertible_v; -#ifndef PLUGIFY_STRING_NO_STD_FORMAT -#include "plg/format.hpp" -#endif + // second concept = the above, but exclude std::basic_string itself + template + concept string_view_convertible_with_exceptiom = string_view_convertible && !std::is_same_v, basic_string>; -#include "plg/allocator.hpp" + template + concept string_like = requires(T v) { + { std::string_view(v) }; + }; -namespace plg { - namespace detail { - template - concept is_allocator = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; - - template - concept is_char_traits = requires { - // Required type definitions - typename Traits::char_type; - typename Traits::int_type; - typename Traits::off_type; - typename Traits::pos_type; - typename Traits::state_type; - } && requires( - typename Traits::char_type c1, - typename Traits::char_type c2, - typename Traits::char_type& cr, - const typename Traits::char_type& ccr, - typename Traits::char_type* p, - const typename Traits::char_type* cp, - typename Traits::int_type i1, - typename Traits::int_type i2, - std::size_t n - ) { - // Character operations - { Traits::assign(cr, ccr) } -> std::same_as; - { Traits::eq(ccr, ccr) } -> std::convertible_to; - { Traits::lt(ccr, ccr) } -> std::convertible_to; - - // String operations - { Traits::compare(cp, cp, n) } -> std::convertible_to; - { Traits::length(cp) } -> std::convertible_to; - { Traits::find(cp, n, ccr) } -> std::convertible_to; - - // Memory operations - { Traits::move(p, cp, n) } -> std::same_as; - { Traits::copy(p, cp, n) } -> std::same_as; - { Traits::assign(p, n, c1) } -> std::same_as; - - // int_type operations - { Traits::not_eof(i1) } -> std::same_as; - { Traits::to_char_type(i1) } -> std::same_as; - { Traits::to_int_type(c1) } -> std::same_as; - { Traits::eq_int_type(i1, i2) } -> std::convertible_to; - { Traits::eof() } -> std::same_as; - }; - - struct uninitialized_size_tag {}; - - template - constexpr bool dependent_false = false; - -#if PLUGIFY_STRING_CONTAINERS_RANGES - template - concept string_compatible_range = std::ranges::input_range && std::convertible_to, Type>; -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - - } // namespace detail + template + struct padding { + char _pad[N]; + }; - // basic_string - // based on implementations from libc++, libstdc++ and Microsoft STL - template, detail::is_allocator Allocator = plg::allocator> + template <> + struct padding<0> {}; + + struct uninitialized_size_tag {}; + + struct init_with_sentinel_tag {}; + + template , class Allocator = allocator> class basic_string { - private: - using allocator_traits = std::allocator_traits; public: + // using self = std::basic_string; + using self_view = std::basic_string_view; using traits_type = Traits; - using value_type = typename traits_type::char_type; + using value_type = CharT; using allocator_type = Allocator; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; + using alloc_traits = std::allocator_traits; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; using reference = value_type&; using const_reference = const value_type&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + + // A basic_string contains the following members which may be trivially relocatable: + // - pointer: is currently assumed to be trivially relocatable, but is still checked in case + // that changes + // - size_type: is always trivially relocatable, since it has to be an integral type + // - value_type: is always trivially relocatable, since it has to be trivial + // - unsigned char: is a fundamental type, so it's trivially relocatable + // - allocator_type: may or may not be trivially relocatable, so it's checked + // + // This string implementation doesn't contain any references into itself. It only contains a + // bit that says whether it is in small or large string mode, so the entire structure is + // trivially relocatable if its members are. +#if __has_feature(address_sanitizer) + // When compiling with AddressSanitizer (ASan), basic_string cannot be trivially + // relocatable. Because the object's memory might be poisoned when its content + // is kept inside objects memory (short string optimization), instead of in allocated + // external memory. In such cases, the destructor is responsible for unpoisoning + // the memory to avoid triggering false positives. + // Therefore it's crucial to ensure the destructor is called. + // + // However, it is replaceable since implementing move-assignment as a destroy + + // move-construct will maintain the right ASAN state. + using trivially_relocatable = void; +#else + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value, + basic_string, + void>; +#endif + +#if __has_cpp_attribute(__no_sanitize__) && __has_feature(address_sanitizer) +# define PLUGIFY_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address"))) +// This macro disables AddressSanitizer (ASan) instrumentation for a specific function, +// allowing memory accesses that would normally trigger ASan errors to proceed without crashing. +// This is useful for accessing parts of objects memory, which should not be accessed, +// such as unused bytes in short strings, that should never be accessed +// by other parts of the program. +#else +# define PLUGIFY_INTERNAL_MEMORY_ACCESS +#endif + +#if __has_feature(address_sanitizer) + constexpr pointer asan_volatile_wrapper(pointer const& ptr) const { + if (std::is_constant_evaluated()) { + return ptr; + } + + volatile pointer copy_ptr = ptr; + + return const_cast(copy_ptr); + } + + constexpr const_pointer asan_volatile_wrapper(const const_pointer& ptr) const { + if (std::is_constant_evaluated()) { + return ptr; + } + + volatile const_pointer copy_ptr = ptr; + + return const_cast(copy_ptr); + } + +# define PLUGIFY_ASAN_VOLATILE_WRAPPER(PTR) asan_volatile_wrapper(PTR) +#else +# define PLUGIFY_ASAN_VOLATILE_WRAPPER(PTR) PTR +#endif + + static_assert(!std::is_array_v, "Character type of basic_string must not be an array"); + static_assert( + std::is_standard_layout_v, + "Character type of basic_string must be standard-layout" + ); + static_assert( + std::is_trivially_default_constructible_v, + "Character type of basic_string must be trivially default constructible" + ); + static_assert( + std::is_trivially_copyable_v, + "Character type of basic_string must be trivially copyable" + ); + static_assert( + std::is_same_v, + "traits_type::char_type must be the same type as CharT" + ); + static_assert( + std::is_same_v, + "Allocator::value_type must be same type as value_type" + ); + // static_assert(std::check_valid_allocator::value, ""); + using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - using sview_type = std::basic_string_view; - constexpr static size_type npos = static_cast(-1); + using alloc_result = allocation_result; private: - constexpr static auto _terminator = value_type(); - - PLUGIFY_NO_UNIQUE_ADDRESS - allocator_type _allocator; + static constexpr int char_bit = std::numeric_limits::digits + std::numeric_limits::is_signed; + static_assert(char_bit == 8, "This implementation assumes that one byte contains 8 bits"); - PLUGIFY_WARN_PUSH() + struct long_ { + constexpr long_() = default; -#if PLUGIFY_COMPILER_CLANG - PLUGIFY_WARN_IGNORE("-Wgnu-anonymous-struct") - PLUGIFY_WARN_IGNORE("-Wzero-length-array") -#elif PLUGIFY_COMPILER_GCC - PLUGIFY_WARN_IGNORE("-Wpedantic") -#elif PLUGIFY_COMPILER_MSVC - PLUGIFY_WARN_IGNORE(4201) - PLUGIFY_WARN_IGNORE(4200) -#endif + constexpr long_(alloc_result alloc, size_type size) + : _data(alloc.ptr) + , _size(size) + , _cap(alloc.count / endian_factor) + , _is_long(true) { + PLUGIFY_ASSERT(!fits_in_sso(alloc.count), "Long capacity should always be larger than the SSO"); + } - template - struct padding { - [[maybe_unused]] uint8_t pad[sizeof(CharT) - 1]; + pointer _data; + size_type _size; + size_type _cap : sizeof(size_type) * char_bit - 1; + size_type _is_long : 1; }; - template - struct padding { - // template specialization to remove the padding structure to avoid warnings on zero length arrays - // also, this allows us to take advantage of the empty-base-class optimization. - }; + static constexpr size_type min_cap = ((sizeof(long_) - 1) / sizeof(value_type) > 2 ? (sizeof(long_) - 1) / sizeof(value_type) : 2) + 1; - // size must correspond to the last byte of long_data.cap, so we don't want the compiler to insert - // padding after size if sizeof(value_type) != 1; Also ensures both layouts are the same size. - struct sso_size : padding { - PLUGIFY_PACK(struct { - uint8_t spare_size : 7; - uint8_t is_long : 1; - }); - }; + struct short_ { + constexpr short_() + : _data{} + , _spare_size(min_cap - 1) + , _is_long(false) { + } - static constexpr int char_bit = std::numeric_limits::digits + std::numeric_limits::is_signed; - static_assert(char_bit == 8, "assumes an 8 bit byte."); - - struct long_data { - pointer data; - size_type size; - PLUGIFY_PACK(struct { - size_type cap : sizeof(size_type) * char_bit - 1; - size_type is_long : 1; - }); + value_type _data[min_cap - 1]; + PLUGIFY_NO_UNIQUE_ADDRESS padding _padding; + uint8_t _spare_size : 7; + uint8_t _is_long : 1; }; - static constexpr size_type min_cap = (sizeof(long_data) - 1) / sizeof(value_type) > 2 ? (sizeof(long_data) - 1) / sizeof(value_type) : 2; + // The endian_factor is required because the field we use to store the size + // has one fewer bit than it would if it were not a bitfield. + // + // If the LSB is used to store the short-flag in the short string representation, + // we have to multiply the size by two when it is stored and divide it by two when + // it is loaded to make sure that we always store an even number. In the long string + // representation, we can ignore this because we can assume that we always allocate + // an even amount of value_types. + // + // If the MSB is used for the short-flag, the max_size() is numeric_limits::max() + // / 2. This does not impact the short string representation, since we never need the MSB + // for representing the size of a short string anyway. + + static constexpr size_type endian_factor = std::endian::native == std::endian::big ? 2 : 1; + + static_assert( + sizeof(short_) == (sizeof(value_type) * min_cap), + "short has an unexpected size." + ); + static_assert( + sizeof(short_) == sizeof(long_), + "short and long layout structures must be the same size" + ); + + union rep { + short_ s{}; + long_ l; + } _rep; + PLUGIFY_NO_UNIQUE_ADDRESS + allocator_type _alloc; + + // annotate the string with its size() at scope exit. The string has to be in a valid state + // at that point. + struct annotate_new_size { + basic_string& _str; + + constexpr explicit annotate_new_size(basic_string& str) + : _str(str) { + } - struct short_data { - value_type data[min_cap]; - sso_size size; + constexpr void operator()() { + _str.annotate_new(_str.size()); + } }; - PLUGIFY_WARN_POP() + // Construct a string with the given allocator and enough storage to hold `size` characters, + // but don't initialize the characters. The contents of the string, including the null + // terminator, must be initialized separately. + constexpr /*explicit*/ basic_string(uninitialized_size_tag, size_type size, const allocator_type& a) + : _alloc(a) { + init_internal_buffer(size); + } - static_assert(sizeof(short_data) == (sizeof(value_type) * (min_cap + 1)), "short has an unexpected size."); - static_assert(sizeof(short_data) == sizeof(long_data), "short and long layout structures must be the same size"); + template + constexpr basic_string(init_with_sentinel_tag, Iter first, Sent last, const allocator_type& a) + : _alloc(a) { + init_with_sentinel(std::move(first), std::move(last)); + } - union { - long_data _long; - short_data _short{}; - } _storage; + constexpr iterator make_iterator(pointer p) { + return iterator(p); + } - constexpr static bool fits_in_sso(size_type size) noexcept { - return size < min_cap; + constexpr const_iterator make_const_iterator(const_pointer p) const { + return const_iterator(p); } - constexpr void long_init() noexcept { - set_long(true); - set_long_data(nullptr); - set_long_size(0); - set_long_cap(0); + public: + static const size_type npos = static_cast(-1); + + constexpr basic_string() noexcept(std::is_nothrow_default_constructible_v) + : _rep(short_()) { + annotate_new(0); } - constexpr void short_init() noexcept { - set_long(false); - set_short_size(0); + constexpr /*explicit*/ basic_string(const allocator_type& a) noexcept + : _rep(short_()) + , _alloc(a) { + annotate_new(0); } - constexpr void default_init(size_type size) noexcept { - if (fits_in_sso(size)) - short_init(); - else - long_init(); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& str) + : _alloc(alloc_traits::select_on_container_copy_construction(str._alloc)) { + if (!str.is_long()) { + _rep = str._rep; + annotate_new(get_short_size()); + } else { + init_copy_ctor_external(std::to_address(str.get_long_pointer()), str.get_long_size()); + } } - constexpr auto& get_long_data() noexcept { - return _storage._long.data; + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS + basic_string(const basic_string& str, const allocator_type& a) + : _alloc(a) { + if (!str.is_long()) { + _rep = str._rep; + annotate_new(get_short_size()); + } else { + init_copy_ctor_external(std::to_address(str.get_long_pointer()), str.get_long_size()); + } } - constexpr const auto& get_long_data() const noexcept { - return _storage._long.data; + constexpr basic_string(basic_string&& str) noexcept + // Turning off ASan instrumentation for variable initialization with + // PLUGIFY_INTERNAL_MEMORY_ACCESS does not work consistently during + // initialization of r_, so we instead unpoison str's memory manually first. str's + // memory needs to be unpoisoned only in the case where it's a short string. + : _rep([](basic_string& s) -> decltype(s._rep)&& { + if (!s.is_long()) { + s.annotate_delete(); + } + return std::move(s._rep); + }(str)) + , _alloc(std::move(str._alloc)) { + str._rep = rep(); + str.annotate_new(0); + if (!is_long()) { + annotate_new(size()); + } } - constexpr auto& get_short_data() noexcept { - return _storage._short.data; + constexpr basic_string(basic_string&& str, const allocator_type& a) + : _alloc(a) { + if (str.is_long() && a != str._alloc) { // copy, not move + init(std::to_address(str.get_long_pointer()), str.get_long_size()); + } else { + if (std::is_constant_evaluated()) { + _rep = rep(); + } + if (!str.is_long()) { + str.annotate_delete(); + } + _rep = str._rep; + str._rep = rep(); + str.annotate_new(0); + if (!is_long() && this != std::addressof(str)) { + annotate_new(size()); + } + } } - constexpr const auto& get_short_data() const noexcept { - return _storage._short.data; + constexpr basic_string(const CharT* PLUGIFY_NO_NULL s) + requires(is_allocator) + { + PLUGIFY_ASSERT(s != nullptr, "basic_string(const char*) detected nullptr"); + init(s, traits_type::length(s)); } - constexpr void set_short_size(size_type size) noexcept { - _storage._short.size.spare_size = min_cap - (size & 0x7F); + constexpr basic_string(const CharT* PLUGIFY_NO_NULL s, const Allocator& a) + requires(is_allocator) + : _alloc(a) { + PLUGIFY_ASSERT(s != nullptr, "basic_string(const char*, allocator) detected nullptr"); + init(s, traits_type::length(s)); } - constexpr size_type get_short_size() const noexcept { - return min_cap - _storage._short.size.spare_size; + basic_string(std::nullptr_t) = delete; + + constexpr basic_string(const CharT* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "basic_string(const char*, n) detected nullptr"); + init(s, n); } - constexpr void set_long_size(size_type size) noexcept { - _storage._long.size = size; + constexpr basic_string(const CharT* s, size_type n, const Allocator& a) + : _alloc(a) { + PLUGIFY_ASSERT( + n == 0 || s != nullptr, + "basic_string(const char*, n, allocator) detected nullptr" + ); + init(s, n); } - constexpr size_type get_long_size() const noexcept { - return _storage._long.size; + constexpr basic_string(size_type n, CharT c) { + init(n, c); } - constexpr void set_long_cap(size_type cap) noexcept { - _storage._long.cap = (cap & 0x7FFFFFFFFFFFFFFF); + constexpr basic_string(basic_string&& str, size_type pos, const Allocator& alloc = Allocator()) + : basic_string(std::move(str), pos, npos, alloc) { } - constexpr size_type get_long_cap() const noexcept { - return _storage._long.cap; + constexpr basic_string( + basic_string&& str, + size_type pos, + size_type n, + const Allocator& alloc = Allocator() + ) + : _alloc(alloc) { + if (pos > str.size()) { + this->throw_out_of_range(); + } + + auto len = std::min(n, str.size() - pos); + if (alloc_traits::is_always_equal::value || alloc == str._alloc) { + move_assign(std::move(str), pos, len); + } else { + // Perform a copy because the allocators are not compatible. + init(str.data() + pos, len); + } } - constexpr void set_long_data(value_type* data) noexcept { - _storage._long.data = data; + constexpr basic_string(size_type n, CharT c, const Allocator& a) + requires(is_allocator) + : _alloc(a) { + init(n, c); } - constexpr bool is_long() const noexcept { - return _storage._long.is_long == true; + constexpr basic_string( + const basic_string& str, + size_type pos, + size_type n, + const Allocator& a = Allocator() + ) + : _alloc(a) { + size_type str_sz = str.size(); + if (pos > str_sz) { + this->throw_out_of_range(); + } + init(str.data() + pos, std::min(n, str_sz - pos)); } - constexpr void set_long(bool is_long) noexcept { - _storage._long.is_long = is_long; + constexpr basic_string(const basic_string& str, size_type pos, const Allocator& a = Allocator()) + : _alloc(a) { + size_type str_sz = str.size(); + if (pos > str_sz) { + this->throw_out_of_range(); + } + init(str.data() + pos, str_sz - pos); } - constexpr void set_size(size_type size) noexcept { - if (is_long()) - set_long_size(size); - else - set_short_size(size); + template T> + constexpr basic_string( + const T& t, + size_type pos, + size_type n, + const allocator_type& a = allocator_type() + ) + : _alloc(a) { + self_view sv0 = t; + self_view sv = sv0.substr(pos, n); + init(sv.data(), sv.size()); } - constexpr sview_type view() const noexcept { - return sview_type(data(), size()); + template T> + constexpr /*explicit*/ basic_string(const T& t) { + self_view sv = t; + init(sv.data(), sv.size()); } - constexpr void reallocate(size_type new_cap, bool copy_old) { - if (new_cap == get_long_cap()) - return; + template T> + constexpr /*explicit*/ basic_string(const T& t, const allocator_type& a) + : _alloc(a) { + self_view sv = t; + init(sv.data(), sv.size()); + } - auto old_len = get_long_size(); - auto old_cap = get_long_cap(); - auto& old_buffer = get_long_data(); + template + constexpr basic_string(InputIterator first, InputIterator last) { + init(first, last); + } - auto new_len = std::min(new_cap, old_len); - auto new_data = allocator_traits::allocate(_allocator, new_cap + 1); + template + constexpr basic_string(InputIterator first, InputIterator last, const allocator_type& a) + : _alloc(a) { + init(first, last); + } - if (old_buffer != nullptr) { - if (old_len != 0 && copy_old) - Traits::copy(new_data, old_buffer, new_len); - allocator_traits::deallocate(_allocator, old_buffer, old_cap + 1); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string(std::from_range_t, Range&& range, const allocator_type& a = allocator_type()) + : _alloc(a) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + init_with_size( + std::ranges::begin(range), + std::ranges::end(range), + std::ranges::distance(range) + ); + } else { + init_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } + } +#endif - set_long_data(new_data); - set_long_size(new_len); - set_long_cap(new_cap); + constexpr basic_string(std::initializer_list il) { + init(il.begin(), il.end()); } - constexpr void deallocate() { - if (is_long()) { - if (auto& buffer = get_long_data(); buffer != nullptr) { - allocator_traits::deallocate(_allocator, buffer, get_long_cap() + 1); - buffer = nullptr; - } - } + constexpr basic_string(std::initializer_list il, const Allocator& a) + : _alloc(a) { + init(il.begin(), il.end()); } - constexpr void grow_to(size_type new_cap) { - if (is_long() == true) { - reallocate(new_cap, true); - return; - } + inline constexpr ~basic_string() { + reset_internal_buffer(); + } - auto buffer = allocator_traits::allocate(_allocator, new_cap + 1); - auto len = get_short_size(); + constexpr operator self_view() const noexcept { + return self_view(begin(), end()); + } - Traits::copy(buffer, get_short_data(), len); - Traits::assign(buffer[len], _terminator); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string& operator=(const basic_string& str); - long_init(); - set_long_data(buffer); - set_long_size(len); - set_long_cap(new_cap); + template T> + constexpr basic_string& operator=(const T& t) { + self_view sv = t; + return assign(sv); } - constexpr void null_terminate() { - auto buffer = data(); - if (buffer == nullptr) [[unlikely]] - return; - Traits::assign(buffer[size()], _terminator); + constexpr basic_string& operator=(basic_string&& str + ) noexcept(alloc_traits::propagate_on_container_move_assignment::value) { + move_assign( + str, + std::integral_constant() + ); + return *this; } - constexpr bool addr_in_range(const_pointer ptr) const noexcept { - if (std::is_constant_evaluated()) - return false; - else - return data() <= ptr && ptr <= data() + size(); + constexpr basic_string& operator=(std::initializer_list il) { + return assign(il.begin(), il.size()); } - template - constexpr void internal_replace_impl(const F& func, size_type pos, size_type oldcount, size_type count) { - auto cap = capacity(); - auto sz = size(); + constexpr basic_string& operator=(const value_type* PLUGIFY_NO_NULL s) { + return assign(s); + } - auto rsz = sz - oldcount + count; + basic_string& operator=(std::nullptr_t) = delete; + constexpr basic_string& operator=(value_type c); - if (cap < rsz) - grow_to(rsz); + constexpr iterator begin() noexcept { + return make_iterator(get_pointer()); + } + + constexpr const_iterator begin() const noexcept { + return make_const_iterator(get_pointer()); + } - if (oldcount != count) - Traits::move(data() + pos + count, data() + pos + oldcount, sz - pos - oldcount); + constexpr iterator end() noexcept { + return make_iterator(get_pointer() + size()); + } - func(); + constexpr const_iterator end() const noexcept { + return make_const_iterator(get_pointer() + size()); + } - set_size(rsz); - null_terminate(); + constexpr reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); } - constexpr void internal_replace(size_type pos, const_pointer str, size_type oldcount, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_replace_impl([&]() { Traits::copy(data() + pos, rstr.data(), count); }, pos, oldcount, count); - } else - internal_replace_impl([&]() { Traits::copy(data() + pos, str, count); }, pos, oldcount, count); + constexpr const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); } - constexpr void internal_replace(size_type pos, value_type ch, size_type oldcount, size_type count) { - internal_replace_impl([&]() { Traits::assign(data() + pos, count, ch); }, pos, oldcount, count); + constexpr reverse_iterator rend() noexcept { + return reverse_iterator(begin()); } - template - constexpr void internal_insert_impl(const F& func, size_type pos, size_type count) { - if (count == 0) [[unlikely]] - return; + constexpr const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - auto cap = capacity(); - auto sz = size(); - auto rsz = sz + count; + constexpr const_iterator cbegin() const noexcept { + return begin(); + } - if (cap < rsz) - grow_to(rsz); + constexpr const_iterator cend() const noexcept { + return end(); + } - Traits::move(data() + pos + count, data() + pos, sz - pos); - func(); + constexpr const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } - set_size(rsz); - null_terminate(); + constexpr const_reverse_iterator crend() const noexcept { + return rend(); } - constexpr void internal_insert(size_type pos, const_pointer str, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_insert_impl([&]() { Traits::copy(data() + pos, rstr.data(), count); }, pos, count); - } else - internal_insert_impl([&]() { Traits::copy(data() + pos, str, count); }, pos, count); + constexpr size_type size() const noexcept { + return is_long() ? get_long_size() : get_short_size(); } - constexpr void internal_insert(size_type pos, value_type ch, size_type count) { - internal_insert_impl([&]() { Traits::assign(data() + pos, count, ch); }, pos, count); + constexpr size_type length() const noexcept { + return size(); } - template - constexpr void internal_append_impl(const F& func, size_type count) { - if (count == 0) [[unlikely]] - return; + constexpr size_type max_size() const noexcept { + constexpr bool uses_lsb = endian_factor == 2; - auto cap = capacity(); - auto sz = size(); - auto rsz = sz + count; + if (size_type m = alloc_traits::max_size(_alloc); + m <= std::numeric_limits::max() / 2) { + size_type res = m - alignment; - if (cap < rsz) - grow_to(rsz); + // When the endian_factor == 2, our string representation assumes that the capacity + // (including the null terminator) is always even, so we have to make sure the + // lowest bit isn't set when the string grows to max_size() + if constexpr (uses_lsb) { + res &= ~size_type(1); + } - func(sz); - set_size(rsz); - null_terminate(); + // We have to allocate space for the null terminator, but max_size() doesn't include + // it. + return res - 1; + } else { + return uses_lsb ? m - alignment - 1 : (m / 2) - alignment - 1; + } } - constexpr void internal_append(const_pointer str, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_append_impl([&](size_type pos) { Traits::copy(data() + pos, rstr.data(), count); }, count); - } else - internal_append_impl([&](size_type pos) { Traits::copy(data() + pos, str, count); }, count); + constexpr size_type capacity() const noexcept { + return (is_long() ? get_long_cap() : min_cap) - 1; } - constexpr void internal_append(value_type ch, size_type count) { - internal_append_impl([&](size_type pos) { Traits::assign(data() + pos, count, ch); }, count); - } + constexpr void resize(size_type n, value_type c); - template - constexpr void internal_assign_impl(const F& func, size_type size, bool copy_old) { - if (fits_in_sso(size)) { - if (is_long() == true) { - deallocate(); - short_init(); - } + constexpr void resize(size_type n) { + resize(n, value_type()); + } - set_short_size(size); - func(get_short_data()); - null_terminate(); - } else { - if (is_long() == false) - long_init(); - if (get_long_cap() < size) - reallocate(size, copy_old); + constexpr void reserve(size_type requested_capacity); - func(get_long_data()); - set_long_size(size); - null_terminate(); +#if PLUGIFY_HAS_CXX23 + /*template + constexpr void resize_and_overwrite(size_type n, Op op) { + size_type sz = size(); + size_type cap = capacity(); + if (n > cap) { + grow_by_without_replace(cap, n - cap, sz, sz, 0); } - } + annotate_delete(); + set_size(n); + annotate_new(n); + erase_to_end(std::move(op)(data(), auto(n))); + }*/ +#endif - constexpr void internal_assign(const_pointer str, size_type size, bool copy_old = false) { - if (addr_in_range(str)) { - basic_string rstr(str, size); - internal_assign_impl([&](auto data) { Traits::copy(data, rstr.data(), size); }, size, copy_old); - } else - internal_assign_impl([&](auto data) { Traits::copy(data, str, size); }, size, copy_old); + constexpr void shrink_to_fit() noexcept; + constexpr void clear() noexcept; + + [[nodiscard]] constexpr bool empty() const noexcept { + return size() == 0; } - constexpr void internal_assign(value_type ch, size_type count, bool copy_old = false) { - internal_assign_impl([&](auto data) { Traits::assign(data, count, ch); }, count, copy_old); + constexpr const_reference operator[](size_type pos) const noexcept { + PLUGIFY_ASSERT(pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(pos) && !fits_in_sso(pos)) { + return *(get_long_pointer() + pos); + } + return *(data() + pos); } - public: - explicit constexpr basic_string(detail::uninitialized_size_tag, size_type size, const Allocator& allocator) - : _allocator(allocator) { - PLUGIFY_ASSERT(size <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - if (fits_in_sso(size)) - short_init(); - else { - long_init(); - reallocate(size, false); + constexpr reference operator[](size_type pos) noexcept { + PLUGIFY_ASSERT(pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(pos) && !fits_in_sso(pos)) { + return *(get_long_pointer() + pos); } - set_size(size); + return *(get_pointer() + pos); } - constexpr basic_string() noexcept(std::is_nothrow_default_constructible::value) - : basic_string(Allocator()) {} + constexpr const_reference at(size_type n) const; + constexpr reference at(size_type n); - explicit constexpr basic_string(const Allocator& allocator) noexcept - : _allocator(allocator) { - short_init(); + constexpr basic_string& operator+=(const basic_string& str) { + return append(str); } - constexpr basic_string(size_type count, value_type ch, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(ch, count); + template T> + constexpr basic_string& operator+=(const T& t) { + self_view sv = t; + return append(sv); } - constexpr basic_string(const basic_string& str, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - auto len = std::min(count, str.size() - pos); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str.data() + pos, len); + constexpr basic_string& operator+=(const value_type* PLUGIFY_NO_NULL s) { + return append(s); } - constexpr basic_string(const basic_string& str, size_type pos, const Allocator& allocator = Allocator()) - : basic_string(str, pos, npos, allocator) {} - constexpr basic_string(const value_type* str, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str, count); + constexpr basic_string& operator+=(value_type c) { + push_back(c); + return *this; } - constexpr basic_string(const value_type* str, const Allocator& allocator = Allocator()) - : basic_string(str, Traits::length(str), allocator) {} - - template - constexpr basic_string(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - if constexpr (std::contiguous_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(first), len); - } else { - if constexpr (std::random_access_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - reserve(len); - } - for (auto it = first; it != last; ++it) { - push_back(*it); - } - } + constexpr basic_string& operator+=(std::initializer_list il) { + return append(il); } - constexpr basic_string(const basic_string& str, const Allocator& allocator) - : _allocator(allocator) { - auto len = str.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str.data(), len); + constexpr basic_string& append(const basic_string& str) { + return append(str.data(), str.size()); } - constexpr basic_string(const basic_string& str) - : basic_string(str, str.get_allocator()) {} - constexpr basic_string(basic_string&& str) noexcept(std::is_nothrow_move_constructible::value) - : _allocator(std::move(str._allocator)), _storage(std::move(str._storage)) { - str.short_init(); + template T> + constexpr basic_string& append(const T& t) { + self_view sv = t; + return append(sv.data(), sv.size()); } - constexpr basic_string(basic_string&& str, const Allocator& allocator) - : _allocator(allocator) { - if constexpr (allocator_traits::is_always_equal::value) { - std::swap(_storage, str._storage); - } else { - if (!str.is_long() || get_allocator() == str.get_allocator()) { - std::swap(_storage, str._storage); - } else { - internal_assign(str.data(), str.size()); - str.deallocate(); - } + constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); + + template T> + constexpr basic_string& append(const T& t, size_type pos, size_type n = npos) { + self_view sv = t; + size_type sz = sv.size(); + if (pos > sz) { + throw_out_of_range(); } - str.short_init(); + return append(sv.data() + pos, std::min(n, sz - pos)); } - constexpr basic_string(std::initializer_list list, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - auto len = list.size(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(list.begin()), len); + constexpr basic_string& append(const value_type* s, size_type n); + constexpr basic_string& append(const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& append(size_type n, value_type c); + + template + constexpr basic_string& append(InputIterator first, InputIterator last) { + const basic_string temp(first, last, _alloc); + append(temp.data(), temp.size()); + return *this; } - template - requires (std::is_convertible_v) - constexpr basic_string(const Type& t, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - auto sv = sview_type(t); - PLUGIFY_ASSERT(pos <= sv.length(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - auto ssv = sv.substr(pos, count); - auto len = ssv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(ssv.data(), len); + template + constexpr basic_string& append(ForwardIterator first, ForwardIterator last) { + size_type sz = size(); + size_type cap = capacity(); + size_type n = static_cast(std::distance(first, last)); + if (n == 0) { + return *this; + } + + if (string_is_trivial_iterator_v && !addr_in_range(*first)) { + if (cap - sz < n) { + grow_by_without_replace(cap, sz + n - cap, sz, sz, 0); + } + annotate_increase(n); + auto end = copy_non_overlapping_range(first, last, std::to_address(get_pointer() + sz)); + traits_type::assign(*end, value_type()); + set_size(sz + n); + return *this; + } else { + const basic_string temp(first, last, _alloc); + return append(temp.data(), temp.size()); + } } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string(const Type& t, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - sview_type sv(t); - auto len = sv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(sv.data(), len); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& append_range(Range&& range) { + insert_range(end(), std::forward(range)); + return *this; } +#endif - constexpr basic_string(basic_string&& str, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : basic_string(std::move(str), allocator) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - erase(pos, count); + constexpr basic_string& append(std::initializer_list il) { + return append(il.begin(), il.size()); } - constexpr basic_string(basic_string&& str, size_type pos, const Allocator& allocator = Allocator()) - : basic_string(std::move(str), pos, npos, allocator) {} + constexpr void push_back(value_type c); + constexpr void pop_back(); -#if __cplusplus > 202002L - basic_string(std::nullptr_t) = delete; -#endif + constexpr reference front() noexcept { + PLUGIFY_ASSERT(!empty(), "string::front(): string is empty"); + return *get_pointer(); + } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string(std::from_range_t, Range&& range, const Allocator& allocator = Allocator()) - : basic_string(std::ranges::begin(range), std::ranges::end(range), allocator) {} -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + constexpr const_reference front() const noexcept { + PLUGIFY_ASSERT(!empty(), "string::front(): string is empty"); + return *data(); + } - constexpr ~basic_string() { - deallocate(); + constexpr reference back() noexcept { + PLUGIFY_ASSERT(!empty(), "string::back(): string is empty"); + return *(get_pointer() + size() - 1); } - constexpr basic_string& operator=(const basic_string& str) { - return assign(str); + constexpr const_reference back() const noexcept { + PLUGIFY_ASSERT(!empty(), "string::back(): string is empty"); + return *(data() + size() - 1); } - constexpr basic_string& operator=(basic_string&& str) noexcept( - allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value) { - return assign(std::move(str)); + template T> + constexpr basic_string& assign(const T& t) { + self_view sv = t; + return assign(sv.data(), sv.size()); } - constexpr basic_string& operator=(const value_type* str) { - return assign(str, Traits::length(str)); + constexpr void move_assign(basic_string&& str, size_type pos, size_type len) { + // Pilfer the allocation from str. + PLUGIFY_ASSERT(_alloc == str._alloc, "move_assign called with wrong allocator"); + size_type old_sz = str.size(); + if (!str.is_long()) { + str.annotate_delete(); + } + _rep = str._rep; + str._rep = rep(); + str.annotate_new(0); + + Traits::move(data(), data() + pos, len); + set_size(len); + Traits::assign(data()[len], value_type()); + + if (!is_long()) { + annotate_new(len); + } else if (old_sz > len) { + annotate_shrink(old_sz); + } } - constexpr basic_string& operator=(value_type ch) { - return assign(std::addressof(ch), 1); + constexpr basic_string& assign(const basic_string& str) { + return *this = str; } - constexpr basic_string& operator=(std::initializer_list list) { - return assign(list.begin(), list.size()); + constexpr basic_string& + assign(basic_string&& str) noexcept(alloc_traits::propagate_on_container_move_assignment::value + ) { + *this = std::move(str); + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& operator=(const Type& t) { - sview_type sv(t); - return assign(sv); + constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); + + template T> + constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos) { + self_view sv = t; + size_type sz = sv.size(); + if (pos > sz) { + throw_out_of_range(); + } + return assign(sv.data() + pos, std::min(n, sz - pos)); } -#if __cplusplus > 202002L - constexpr basic_string& operator=(std::nullptr_t) = delete; -#endif + constexpr basic_string& assign(const value_type* s, size_type n); + constexpr basic_string& assign(const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& assign(size_type n, value_type c); - constexpr basic_string& assign(size_type count, value_type ch) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(ch, count); + template + constexpr basic_string& assign(InputIterator first, InputIterator last) { + assign_with_sentinel(first, last); return *this; } - constexpr basic_string& assign(const basic_string& str, size_type pos, size_type count = npos) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::assign(): pos out of range", std::out_of_range); - internal_assign(str.data(), std::min(count, str.size() - pos)); + template + constexpr basic_string& assign(ForwardIterator first, ForwardIterator last) { + if (string_is_trivial_iterator_v) { + size_type n = static_cast(std::distance(first, last)); + assign_trivial(first, last, n); + } else { + assign_with_sentinel(first, last); + } + return *this; } - constexpr basic_string& assign(const basic_string& str) { - if (this == &str) [[unlikely]] - return *this; +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& assign_range(Range&& range) { + if constexpr (string_is_trivial_iterator_v> + && (std::ranges::forward_range || std::ranges::sized_range) ) { + size_type n = static_cast(std::ranges::distance(range)); + assign_trivial(std::ranges::begin(range), std::ranges::end(range), n); - if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != str.get_allocator()) { - deallocate(); - short_init(); - } - } - _allocator = str._allocator; + } else { + assign_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } - internal_assign(str.data(), str.size()); return *this; } +#endif - constexpr basic_string& assign(basic_string&& str) noexcept( - allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value) { - if (this == &str) [[unlikely]] - return *this; + constexpr basic_string& assign(std::initializer_list il) { + return assign(il.begin(), il.size()); + } - if constexpr (allocator_traits::propagate_on_container_move_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != str.get_allocator()) { - deallocate(); - short_init(); - } - } - _allocator = std::move(str._allocator); + constexpr basic_string& insert(size_type pos1, const basic_string& str) { + return insert(pos1, str.data(), str.size()); + } + + template T> + constexpr basic_string& insert(size_type pos1, const T& t) { + self_view sv = t; + return insert(pos1, sv.data(), sv.size()); + } + + template T> + constexpr basic_string& + insert(size_type pos1, const T& t, size_type pos2, size_type n = npos) { + self_view sv = t; + size_type str_sz = sv.size(); + if (pos2 > str_sz) { + throw_out_of_range(); } + return insert(pos1, sv.data() + pos2, std::min(n, str_sz - pos2)); + } + + constexpr basic_string& + insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos); + constexpr basic_string& insert(size_type pos, const value_type* s, size_type n); + constexpr basic_string& insert(size_type pos, const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& insert(size_type pos, size_type n, value_type c); + constexpr iterator insert(const_iterator pos, value_type c); + +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr iterator insert_range(const_iterator position, Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + return insert_with_size(position, std::ranges::begin(range), std::ranges::end(range), n); - if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) { - deallocate(); - short_init(); - std::swap(_storage, str._storage); } else { - if (get_allocator() == str.get_allocator()) { - deallocate(); - short_init(); - std::swap(_storage, str._storage); - } else { - internal_assign(str.data(), str.size()); - } + basic_string temp(std::from_range, std::forward(range), _alloc); + return insert(position, temp.data(), temp.data() + temp.size()); } + } +#endif - return *this; + constexpr iterator insert(const_iterator pos, size_type n, value_type c) { + difference_type p = pos - begin(); + insert(static_cast(p), n, c); + return begin() + p; } - constexpr basic_string& assign(const value_type* str, size_type count) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(str, count); - return *this; + template + constexpr iterator insert(const_iterator pos, InputIterator first, InputIterator last) { + const basic_string temp(first, last, _alloc); + return insert(pos, temp.data(), temp.data() + temp.size()); } - constexpr basic_string& assign(const value_type* str) { - return assign(str, Traits::length(str)); + template + constexpr iterator insert(const_iterator pos, ForwardIterator first, ForwardIterator last) { + auto n = static_cast(std::distance(first, last)); + return insert_with_size(pos, first, last, n); } - template - constexpr basic_string& assign(InputIterator first, InputIterator last) { - if constexpr (std::contiguous_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(first), len); - } else { - if constexpr (std::random_access_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - reserve(len); - } - for (auto it = first; it != last; ++it) { - push_back(*it); - } - } - return *this; + constexpr iterator insert(const_iterator pos, std::initializer_list il) { + return insert(pos, il.begin(), il.end()); } - constexpr basic_string& assign(std::initializer_list list) { - auto len = list.size(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(list.begin()), len); - return *this; + constexpr basic_string& erase(size_type pos = 0, size_type n = npos); + constexpr iterator erase(const_iterator pos); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str) { + return replace(pos1, n1, str.data(), str.size()); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& assign(const Type& t) { - sview_type sv(t); - return assign(sv.data(), sv.length()); + template T> + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t) { + self_view sv = t; + return replace(pos1, n1, sv.data(), sv.size()); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& assign(const Type& t, size_type pos, size_type count = npos) { - auto sv = sview_type(t).substr(pos, count); - auto len = sv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - return assign(sv.data(), len); + constexpr basic_string& + replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos); + + template T> + constexpr basic_string& + replace(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) { + self_view sv = t; + size_type str_sz = sv.size(); + if (pos2 > str_sz) { + throw_out_of_range(); + } + return replace(pos1, n1, sv.data() + pos2, std::min(n2, str_sz - pos2)); } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string& assign_range(Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(str.size() <= max_size(), "plg::basic_string::assign_range(): resulted string size would exceed max_size()", std::length_error); - return assign(std::move(str)); + constexpr basic_string& + replace(size_type pos, size_type n1, const value_type* s, size_type n2); + constexpr basic_string& + replace(size_type pos, size_type n1, const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); + + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, const basic_string& str) { + return replace( + static_cast(i1 - begin()), + static_cast(i2 - i1), + str.data(), + str.size() + ); } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr allocator_type get_allocator() const noexcept { - return _allocator; + template T> + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t) { + self_view sv = t; + return replace(i1 - begin(), i2 - i1, sv); + } + + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), s, n); } - constexpr reference operator[](size_type pos) { - return data()[pos]; + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), s); } - constexpr const_reference operator[](size_type pos) const { - return data()[pos]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, size_type n, value_type c) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), n, c); } - constexpr reference at(size_type pos) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::at(): pos out of range", std::out_of_range); - return data()[pos]; + template + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2) { + const basic_string temp(j1, j2, _alloc); + return replace(i1, i2, temp); } - constexpr const_reference at(size_type pos) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::at(): pos out of range", std::out_of_range); - return data()[pos]; +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& + replace_with_range(const_iterator i1, const_iterator i2, Range&& range) { + basic_string temp(std::from_range, std::forward(range), _alloc); + return replace(i1, i2, temp); } +#endif - constexpr reference front() { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::front(): vector is empty", std::length_error); - return data()[0]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, std::initializer_list il) { + return replace(i1, i2, il.begin(), il.end()); } - constexpr const_reference front() const { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::front(): vector is empty", std::length_error); - return data()[0]; + constexpr size_type copy(value_type* s, size_type n, size_type pos = 0) const; + + constexpr basic_string substr(size_type pos = 0, size_type n = npos) const& { + return basic_string(*this, pos, n); } - constexpr reference back() { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::back(): vector is empty", std::length_error); - return data()[size() - 1]; + constexpr basic_string substr(size_type pos = 0, size_type n = npos) && { + return basic_string(std::move(*this), pos, n); } - constexpr const_reference back() const { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::back(): vector is empty", std::length_error); - return data()[size() - 1]; + constexpr void swap(basic_string& str) noexcept; + + // [string.ops] + // ------------ + + constexpr const value_type* c_str() const noexcept { + return data(); } constexpr const value_type* data() const noexcept { - return is_long() ? get_long_data() : get_short_data(); + return std::to_address(get_pointer()); } constexpr value_type* data() noexcept { - return is_long() ? get_long_data() : get_short_data(); + return std::to_address(get_pointer()); } - constexpr const value_type* c_str() const noexcept { - return data(); + constexpr allocator_type get_allocator() const noexcept { + return _alloc; } - constexpr operator sview_type() const noexcept { - return view(); + // find + + constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find(str.data(), pos, str.size()); } - constexpr iterator begin() noexcept { - return data(); + template T> + constexpr size_type find(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find(sv.data(), pos, sv.size()); } - constexpr const_iterator begin() const noexcept { - return data(); + constexpr size_type find(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find(): received nullptr"); + return operator self_view().find(s, pos, n); } - constexpr const_iterator cbegin() const noexcept { - return data(); + constexpr size_type + find(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find(): received nullptr"); + return operator self_view().find(s, pos, traits_type::length(s)); } - constexpr iterator end() noexcept { - return data() + size(); + constexpr size_type find(value_type c, size_type pos = 0) const noexcept { + return operator self_view().find(c, pos); } - constexpr const_iterator end() const noexcept { - return data() + size(); + // rfind + + constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().rfind(str.data(), pos, str.size()); } - constexpr const_iterator cend() const noexcept { - return data() + size(); + template T> + constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().rfind(sv.data(), pos, sv.size()); } - constexpr reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); + constexpr size_type rfind(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::rfind(): received nullptr"); + return operator self_view().rfind(s, pos, n); + } + + constexpr size_type + rfind(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::rfind(): received nullptr"); + return operator self_view().rfind(s, pos, traits_type::length(s)); + } + + constexpr size_type rfind(value_type c, size_type pos = npos) const noexcept { + return operator self_view().rfind(c, pos); } - constexpr const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); + // find_first_of + + constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find_first_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find_first_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_first_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_first_of(): received nullptr"); + return operator self_view().find_first_of(s, pos, n); + } + + constexpr size_type + find_first_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_first_of(): received nullptr"); + return operator self_view().find_first_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_first_of(value_type c, size_type pos = 0) const noexcept { + return find(c, pos); + } + + // find_last_of + + constexpr size_type + find_last_of(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().find_last_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_last_of(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().find_last_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_last_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_last_of(): received nullptr"); + return operator self_view().find_last_of(s, pos, n); + } + + constexpr size_type + find_last_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_last_of(): received nullptr"); + return operator self_view().find_last_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_last_of(value_type c, size_type pos = npos) const noexcept { + return rfind(c, pos); + } + + // find_first_not_of + + constexpr size_type + find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find_first_not_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find_first_not_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_first_not_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_first_not_of(): received nullptr"); + return operator self_view().find_first_not_of(s, pos, n); + } + + constexpr size_type + find_first_not_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_first_not_of(): received nullptr"); + return operator self_view().find_first_not_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept { + return operator self_view().find_first_not_of(c, pos); + } + + // find_last_not_of + + constexpr size_type + find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().find_last_not_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().find_last_not_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_last_not_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_last_not_of(): received nullptr"); + return operator self_view().find_last_not_of(s, pos, n); + } + + constexpr size_type + find_last_not_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_last_not_of(): received nullptr"); + return operator self_view().find_last_not_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept { + return operator self_view().find_last_not_of(c, pos); + } + + // compare + + constexpr int compare(const basic_string& str) const noexcept { + return compare(self_view(str)); + } + + template T> + constexpr int compare(const T& t) const noexcept { + self_view sv = t; + size_t lhs_sz = size(); + size_t rhs_sz = sv.size(); + int result = traits_type::compare(data(), sv.data(), std::min(lhs_sz, rhs_sz)); + if (result != 0) { + return result; + } + if (lhs_sz < rhs_sz) { + return -1; + } + if (lhs_sz > rhs_sz) { + return 1; + } + return 0; + } + + template T> + constexpr int compare(size_type pos1, size_type n1, const T& t) const { + self_view sv = t; + return compare(pos1, n1, sv.data(), sv.size()); + } + + constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const { + return compare(pos1, n1, str.data(), str.size()); + } + + constexpr int compare( + size_type pos1, + size_type n1, + const basic_string& str, + size_type pos2, + size_type n2 = npos + ) const { + return compare(pos1, n1, self_view(str), pos2, n2); + } + + template T> + inline constexpr int + compare(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) const { + self_view sv = t; + return self_view(*this).substr(pos1, n1).compare(sv.substr(pos2, n2)); + } + + constexpr int compare(const value_type* PLUGIFY_NO_NULL s) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::compare(): received nullptr"); + return compare(0, npos, s, traits_type::length(s)); + } + + constexpr int + compare(size_type pos1, size_type n1, const value_type* PLUGIFY_NO_NULL s) const { + PLUGIFY_ASSERT(s != nullptr, "string::compare(): received nullptr"); + return compare(pos1, n1, s, traits_type::length(s)); + } + + constexpr int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; + + // starts_with + + constexpr bool starts_with(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).starts_with(sv); + } + + constexpr bool starts_with(value_type c) const noexcept { + return !empty() && Traits::eq(front(), c); + } + + constexpr bool starts_with(const value_type* PLUGIFY_NO_NULL s) const noexcept { + return starts_with(self_view(s)); + } + + // ends_with + + constexpr bool ends_with(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).ends_with(sv); + } + + constexpr bool ends_with(value_type c) const noexcept { + return !empty() && Traits::eq(back(), c); + } + + constexpr bool ends_with(const value_type* PLUGIFY_NO_NULL s) const noexcept { + return ends_with(self_view(s)); + } + + // contains + + constexpr bool contains(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).contains(sv); + } + + constexpr bool contains(value_type c) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).contains(c); + } + + constexpr bool contains(const value_type* PLUGIFY_NO_NULL s) const { + return self_view(typename self_view::assume_valid(), data(), size()).contains(s); + } + + [[nodiscard]] constexpr bool invariants() const; + + private: + [[nodiscard]] constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS bool is_long() const noexcept { + if (std::is_constant_evaluated() && __builtin_constant_p(_rep.l._is_long)) { + return _rep.l._is_long; + } + return _rep.s._is_long; + } + + static constexpr bool fits_in_sso(size_type sz) { + return sz < min_cap; + } + + template + constexpr void assign_trivial(Iterator first, Sentinel last, size_type n); + + template + constexpr void assign_with_sentinel(Iterator first, Sentinel last); + + // Copy [first, last) into [dest, dest + (last - first)). Assumes that the ranges don't + // overlap. + template + static constexpr value_type* + copy_non_overlapping_range(ForwardIter first, Sent last, value_type* dest) { + if constexpr (std::contiguous_iterator + && std::is_same_v> + && std::is_same_v) { + PLUGIFY_ASSERT( + !is_overlapping_range(std::to_address(first), std::to_address(last), dest), + "copy_non_overlapping_range called with an overlapping range!" + ); + traits_type::copy(dest, std::to_address(first), last - first); + return dest + (last - first); + } else { + for (; first != last; ++first) { + traits_type::assign(*dest++, *first); + } + return dest; + } + } + + template + constexpr iterator + insert_from_safe_copy(size_type n, size_type ip, ForwardIterator first, Sentinel last) { + size_type sz = size(); + size_type cap = capacity(); + value_type* p; + if (cap - sz >= n) { + annotate_increase(n); + p = std::to_address(get_pointer()); + size_type n_move = sz - ip; + if (n_move != 0) { + traits_type::move(p + ip + n, p + ip, n_move); + } + } else { + grow_by_without_replace(cap, sz + n - cap, sz, ip, 0, n); + p = std::to_address(get_long_pointer()); + } + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + copy_non_overlapping_range(std::move(first), std::move(last), p + ip); + + return begin() + ip; + } + + template + constexpr iterator + insert_with_size(const_iterator pos, Iterator first, Sentinel last, size_type n); + + // internal buffer accessors + // ------------------------- + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void set_short_size(size_type s) noexcept { + PLUGIFY_ASSERT( + s < min_cap, + "s should never be greater than or equal to the short string capacity" + ); + _rep.s._spare_size = (min_cap - 1) - s; + _rep.s._is_long = false; + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS size_type get_short_size() const noexcept { + PLUGIFY_ASSERT(!_rep.s._is_long, "String has to be short when trying to get the short size"); + return (min_cap - 1) - _rep.s._spare_size; + } + + constexpr void set_long_size(size_type s) noexcept { + _rep.l._size = s; + } + + constexpr size_type get_long_size() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long size"); + return _rep.l._size; + } + + constexpr void set_size(size_type s) noexcept { + if (is_long()) { + set_long_size(s); + } else { + set_short_size(s); + } + } + + constexpr size_type get_long_cap() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long capacity"); + return _rep.l._cap * endian_factor; + } + + constexpr pointer get_long_pointer() noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long pointer"); + return PLUGIFY_ASAN_VOLATILE_WRAPPER(_rep.l._data); + } + + constexpr const_pointer get_long_pointer() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long pointer"); + return PLUGIFY_ASAN_VOLATILE_WRAPPER(_rep.l._data); + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS pointer get_short_pointer() noexcept { + return PLUGIFY_ASAN_VOLATILE_WRAPPER( + std::pointer_traits::pointer_to(_rep.s._data[0]) + ); + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS const_pointer get_short_pointer() const noexcept { + return PLUGIFY_ASAN_VOLATILE_WRAPPER( + std::pointer_traits::pointer_to(_rep.s._data[0]) + ); + } + + constexpr pointer get_pointer() noexcept { + return is_long() ? get_long_pointer() : get_short_pointer(); + } + + constexpr const_pointer get_pointer() const noexcept { + return is_long() ? get_long_pointer() : get_short_pointer(); + } + + // Internal buffer management + // -------------------------- + // + // These functions are only responsible for managing the buffer itself, not the value inside + // the buffer. As such, none of these facilities ensure that there is a null terminator at + // `data()[size()]`. + + // Allocate a buffer of capacity size with alloc and return it + static constexpr long_ allocate_long_buffer(Allocator& alloc, size_type capacity) { + auto buffer = allocate_at_least(alloc, recommend(capacity) + 1); + + if (std::is_constant_evaluated()) { + for (size_type i = 0; i != buffer.count; ++i) { + std::construct_at(std::addressof(buffer.ptr[i])); + } + } + + return long_(buffer, capacity); + } + + // Deallocate the long buffer if it exists and clear the short buffer so we are an empty + // string + constexpr void reset_internal_buffer() { + annotate_delete(); + if (is_long()) { + alloc_traits::deallocate(_alloc, get_long_pointer(), get_long_cap()); + } + _rep.s = short_(); + } + + // Replace the current buffer with alloc; the first size elements constitute a string + constexpr void replace_internal_buffer(long_ alloc) { + reset_internal_buffer(); + _rep.l = alloc; + } + + // Initialize the internal buffer to hold size elements + // The elements and null terminator have to be set by the caller + constexpr pointer init_internal_buffer(size_type size) { + if (std::is_constant_evaluated()) { + _rep = rep(); + } + + if (size > max_size()) { + throw_length_error(); + } + + if (fits_in_sso(size)) { + set_short_size(size); + annotate_new(size); + return get_short_pointer(); + } else { + _rep.l = allocate_long_buffer(_alloc, size); + annotate_new(size); + return get_long_pointer(); + } + } + + // ASan annotation helpers + // ----------------------- + + // The following functions are no-ops outside of AddressSanitizer mode. + constexpr void annotate_contiguous_container( + const void* old_mid, + const void* new_mid + ) const { + if (!is_long()) { + return; + } + + plg::annotate_contiguous_container( + data(), + data() + capacity() + 1, + old_mid, + new_mid + ); } - constexpr const_reverse_iterator crbegin() const noexcept { - return const_reverse_iterator(cend()); + constexpr void annotate_new(size_type current_size) const noexcept { + annotate_contiguous_container(data() + capacity() + 1, data() + current_size + 1); } - constexpr reverse_iterator rend() noexcept { - return reverse_iterator(begin()); + constexpr void annotate_delete() const noexcept { + annotate_contiguous_container(data() + size() + 1, data() + capacity() + 1); } - constexpr const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); + constexpr void annotate_increase(size_type n) const noexcept { + annotate_contiguous_container(data() + size() + 1, data() + size() + 1 + n); } - constexpr const_reverse_iterator crend() const noexcept { - return const_reverse_iterator(cbegin()); + constexpr void annotate_shrink(size_type old_size) const noexcept { + annotate_contiguous_container(data() + old_size + 1, data() + size() + 1); } - constexpr bool empty() const noexcept { - return size() == 0; - } + // Disable ASan annotations and enable them again when going out of scope. It is assumed + // that the string is in a valid state at that point, so `size()` can be called safely. + struct [[nodiscard]] annotation_guard { + annotation_guard(const annotation_guard&) = delete; + annotation_guard& operator=(const annotation_guard&) = delete; - constexpr size_type size() const noexcept { - return is_long() ? get_long_size() : get_short_size(); - } + constexpr annotation_guard(basic_string& str) + : str(str) { + str.annotate_delete(); + } - constexpr size_type length() const noexcept { - return size(); - } + constexpr ~annotation_guard() { + str.annotate_new(str.size()); + } - constexpr size_type max_size() const noexcept { - // const size_type alignment = 16; - // size_type m = allocator_traits::max_size(_allocator); - // if (m <= std::numeric_limits::max() / 2) - // return m - alignment; - // else - //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; - return (allocator_traits::max_size(_allocator) - 1) / 2; - } + basic_string& str; + }; - constexpr size_type capacity() const noexcept { - return is_long() ? get_long_cap() : min_cap; + template + static constexpr size_type align_it(size_type s) noexcept { + return (s + (a - 1)) & ~(a - 1); } - constexpr void reserve(size_type cap) { - PLUGIFY_ASSERT(cap <= max_size(), "plg::basic_string::reserve(): allocated memory size would exceed max_size()", std::length_error); - if (cap <= capacity()) - return; + enum { alignment = 8 }; - auto new_cap = std::max(cap, size()); - if (new_cap == capacity()) - return; + static constexpr size_type recommend(size_type s) noexcept { + if (s < min_cap) { + return min_cap - 1; + } + const size_type boundary = sizeof(value_type) < alignment ? alignment / sizeof(value_type) : endian_factor; + size_type guess = align_it(s + 1) - 1; + if (guess == min_cap) { + guess += endian_factor; + } - grow_to(new_cap); + PLUGIFY_ASSERT(guess >= s, "recommendation is below the requested size"); + return guess; + } + + inline constexpr void init(const value_type* s, size_type sz); + inline constexpr void init(size_type n, value_type c); + + // Slow path for the (inlined) copy constructor for 'long' strings. + // Always externally instantiated and not inlined. + // Requires that s is zero terminated. + // The main reason for this function to exist is because for unstable, we + // want to allow inlining of the copy constructor. However, we don't want + // to call the init() functions as those are marked as inline which may + // result in over-aggressive inlining by the compiler, where our aim is + // to only inline the fast path code directly in the ctor. + PLUGIFY_NOINLINE constexpr void init_copy_ctor_external(const value_type* s, size_type sz); + + template + inline constexpr void init(InputIterator first, InputIterator last); + + template + inline constexpr void init(ForwardIterator first, ForwardIterator last); + + template + constexpr void init_with_sentinel(InputIterator first, Sentinel last); + template + constexpr void init_with_size(InputIterator first, Sentinel last, size_type sz); + + constexpr void grow_by_without_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add = 0 + ); + constexpr void grow_by_and_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add, + const value_type* p_new_stuff + ); + + // assign_no_alias is invoked for assignment operations where we + // have proof that the input does not alias the current instance. + // For example, operator=(basic_string) performs a 'self' check. + template + PLUGIFY_NOINLINE constexpr basic_string& assign_no_alias(const value_type* s, size_type n); + + constexpr void erase_to_end(size_type pos) { + PLUGIFY_ASSERT( + pos <= capacity(), + "Trying to erase at position outside the strings capacity!" + ); + null_terminate_at(std::to_address(get_pointer()), pos); + } + + // erase_external_with_move is invoked for erase() invocations where + // `n ~= npos`, likely requiring memory moves on the string data. + PLUGIFY_NOINLINE constexpr void erase_external_with_move(size_type pos, size_type n); + + constexpr void copy_assign_alloc(const basic_string& str) { + copy_assign_alloc( + str, + std::integral_constant() + ); + } + + constexpr void copy_assign_alloc(const basic_string& str, std::true_type) { + if (_alloc == str._alloc) { + _alloc = str._alloc; + } else { + if (!str.is_long()) { + reset_internal_buffer(); + _alloc = str._alloc; + } else { + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + auto alloc = str._alloc; + replace_internal_buffer(allocate_long_buffer(alloc, str.size())); + _alloc = std::move(alloc); + } + } } - void reserve() { - shrink_to_fit(); + constexpr void copy_assign_alloc(const basic_string&, std::false_type) noexcept { } - constexpr void shrink_to_fit() { - if (is_long() == false) - return; + constexpr void + move_assign(basic_string& str, std::false_type) noexcept(alloc_traits::is_always_equal::value); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void + move_assign(basic_string& str, std::true_type) noexcept; - reallocate(size(), true); + constexpr void move_assign_alloc( + basic_string& str + ) noexcept(!alloc_traits::propagate_on_container_move_assignment::value || std::is_nothrow_move_assignable_v) { + move_assign_alloc( + str, + std::integral_constant() + ); } - constexpr void clear() noexcept { - set_size(0); + constexpr void move_assign_alloc( + basic_string& c, + std::true_type + ) noexcept(std::is_nothrow_move_assignable_v) { + _alloc = std::move(c._alloc); } - constexpr basic_string& insert(size_type pos, size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - insert(std::next(cbegin(), pos), count, ch); - return *this; + constexpr void move_assign_alloc(basic_string&, std::false_type) noexcept { } - constexpr basic_string& insert(size_type pos, const value_type* str) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - auto len = Traits::length(str); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, str, len); - return *this; - } + PLUGIFY_NOINLINE constexpr basic_string& assign_external(const value_type* s); + PLUGIFY_NOINLINE constexpr basic_string& assign_external(const value_type* s, size_type n); - constexpr basic_string& insert(size_type pos, const value_type* str, size_type count) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - internal_insert(pos, str, count); + // Assigns the value in s, guaranteed to be n < min_cap in length. + inline constexpr basic_string& assign_short(const value_type* s, size_type n) { + size_type old_size = size(); + if (n > old_size) { + annotate_increase(n - old_size); + } + pointer p; + if (is_long()) { + set_long_size(n); + p = get_long_pointer(); + } else { + set_short_size(n); + p = get_short_pointer(); + } + traits_type::move(std::to_address(p), s, n); + traits_type::assign(p[n], value_type()); + if (old_size > n) { + annotate_shrink(old_size); + } return *this; } - constexpr basic_string& insert(size_type pos, const basic_string& str) { - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - internal_insert(pos, const_pointer(str.data()), str.size()); + constexpr basic_string& null_terminate_at(value_type* p, size_type newsz) { + size_type old_size = size(); + if (newsz > old_size) { + annotate_increase(newsz - old_size); + } + set_size(newsz); + traits_type::assign(p[newsz], value_type()); + if (old_size > newsz) { + annotate_shrink(old_size); + } return *this; } - constexpr basic_string& insert(size_type pos, const basic_string& str, size_type pos_str, size_type count = npos) { - PLUGIFY_ASSERT(pos <= size() && pos_str <= str.size(), "plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range); - count = std::min(count, str.length() - pos_str); - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - return insert(pos, str.data() + pos_str, count); - } - - constexpr iterator insert(const_iterator pos, value_type ch) { - return insert(pos, 1, ch); + template + constexpr bool addr_in_range(const T& v) const { + return is_pointer_in_range(data(), data() + size() + 1, std::addressof(v)); } - constexpr iterator insert(const_iterator pos, size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - auto spos = std::distance(cbegin(), pos); - internal_insert(spos, ch, count); - return std::next(begin(), spos); + [[noreturn]] static void throw_length_error() { + PLUGIFY_THROW("constructed string size would exceed max_size()", std::length_error); } - template - constexpr iterator insert(const_iterator pos, InputIterator first, InputIterator last) { - auto spos = std::distance(cbegin(), pos); - auto len = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(spos, const_pointer(first), len); - return std::next(begin(), spos); - } - - constexpr iterator insert(const_iterator pos, std::initializer_list list) { - PLUGIFY_ASSERT(size() + list.size() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - auto spos = std::distance(cbegin(), pos); - internal_insert(spos, const_pointer(list.begin()), list.size()); - return std::next(begin(), spos); - } - - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& insert(size_type pos, const Type& t) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - sview_type sv(t); - PLUGIFY_ASSERT(size() + sv.length() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, const_pointer(sv.data()), sv.length()); - return *this; + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& insert(size_type pos, const Type& t, size_type pos_str, size_type count = npos) { - auto sv = sview_type(t); - PLUGIFY_ASSERT(pos <= size() && pos_str <= sv.length(), "plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range); - auto ssv = sv.substr(pos_str, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, const_pointer(ssv.data()), ssv.length()); - return *this; - } + friend constexpr basic_string + concatenate_strings<>(const Allocator&, std::type_identity_t, std::type_identity_t); -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr iterator insert_range(const_iterator pos, Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error); - return insert(pos - begin(), str); - } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + friend inline constexpr bool + operator==(const basic_string&, const CharT2*) noexcept; + }; - constexpr basic_string& erase(size_type pos = 0, size_type count = npos) { - auto sz = size(); - auto buffer = data(); + template < + std::input_iterator InputIterator, + class CharT = std::iter_value_t, + is_allocator Allocator = allocator> + basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string, Allocator>; + + template > + explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) + -> basic_string; + + template < + class CharT, + is_char_traits Traits, + is_allocator Allocator = allocator, + class Sz = typename std::allocator_traits::size_type> + basic_string(std::basic_string_view, Sz, Sz, const Allocator& = Allocator()) + -> basic_string; + +#if PLUGIFY_HAS_CXX23 + template < + std::ranges::input_range Range, + is_allocator Allocator = std::allocator>> + basic_string(std::from_range_t, Range&&, Allocator = Allocator()) -> basic_string< + std::ranges::range_value_t, + std::char_traits>, + Allocator>; +#endif - PLUGIFY_ASSERT(pos <= sz, "plg::basic_string::erase(): pos out of range", std::out_of_range); + template + constexpr void basic_string::init(const value_type* s, size_type sz) { + pointer p = init_internal_buffer(sz); + traits_type::copy(std::to_address(p), s, sz); + traits_type::assign(p[sz], value_type()); + } - count = std::min(count, sz - pos); + template + PLUGIFY_NOINLINE constexpr void + basic_string::init_copy_ctor_external(const value_type* s, size_type sz) { + pointer p = init_internal_buffer(sz); + traits_type::copy(std::to_address(p), s, sz + 1); + } - auto left = sz - (pos + count); - if (left != 0) - Traits::move(buffer + pos, buffer + pos + count, left); + template + constexpr void basic_string::init(size_type n, value_type c) { + pointer p = init_internal_buffer(n); + traits_type::assign(std::to_address(p), n, c); + traits_type::assign(p[n], value_type()); + } - auto new_size = pos + left; - set_size(new_size); - null_terminate(); + template + template + constexpr void + basic_string::init(InputIterator first, InputIterator last) { + init_with_sentinel(std::move(first), std::move(last)); + } - return *this; + template + template + constexpr void + basic_string::init_with_sentinel(InputIterator first, Sentinel last) { + _rep = rep(); + annotate_new(0); + +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + for (; first != last; ++first) { + push_back(*first); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + reset_internal_buffer(); + throw; } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr iterator erase(const_iterator position) { - auto pos = std::distance(cbegin(), position); - erase(pos, 1); - return begin() + pos; - } + template + template + constexpr void + basic_string::init(ForwardIterator first, ForwardIterator last) { + size_type sz = static_cast(std::distance(first, last)); + init_with_size(first, last, sz); + } - constexpr iterator erase(const_iterator first, const_iterator last) { - auto pos = std::distance(cbegin(), first); - auto len = std::distance(first, last); - erase(pos, len); - return begin() + pos; - } + template + template + constexpr void basic_string::init_with_size( + InputIterator first, + Sentinel last, + size_type sz + ) { + pointer p = init_internal_buffer(sz); + +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + auto end = copy_non_overlapping_range(std::move(first), std::move(last), std::to_address(p)); + traits_type::assign(*end, value_type()); +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + reset_internal_buffer(); + throw; + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr void push_back(value_type ch) { - PLUGIFY_ASSERT(size() + 1 <= max_size(), "plg::basic_string::push_back(): resulted string size would exceed max_size()", std::length_error); - append(1, ch); - } + template + constexpr void basic_string::grow_by_and_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add, + const value_type* p_new_stuff + ) { + size_type ms = max_size(); + if (delta_cap > ms - old_cap) { + throw_length_error(); + } + pointer old_p = get_pointer(); + size_type cap = old_cap < ms / 2 - alignment + ? recommend(std::max(old_cap + delta_cap, 2 * old_cap)) + : ms; + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + long_ buffer = allocate_long_buffer(_alloc, cap); + if (n_copy != 0) { + traits_type::copy(std::to_address(buffer._data), std::to_address(old_p), n_copy); + } + if (n_add != 0) { + traits_type::copy(std::to_address(buffer._data) + n_copy, p_new_stuff, n_add); + } + size_type sec_cp_sz = old_sz - n_del - n_copy; + if (sec_cp_sz != 0) { + traits_type::copy( + std::to_address(buffer._data) + n_copy + n_add, + std::to_address(old_p) + n_copy + n_del, + sec_cp_sz + ); + } + buffer._size = n_copy + n_add + sec_cp_sz; + traits_type::assign(buffer._data[buffer._size], value_type()); + replace_internal_buffer(buffer); + } - constexpr void pop_back() { - erase(end() - 1); - } + template + constexpr void basic_string::grow_by_without_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add + ) { + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + size_type ms = max_size(); + if (delta_cap > ms - old_cap) { + this->throw_length_error(); + } + pointer old_p = get_pointer(); + size_type cap = old_cap < ms / 2 - alignment + ? recommend(std::max(old_cap + delta_cap, 2 * old_cap)) + : ms; + long_ buffer = allocate_long_buffer(_alloc, cap); + if (n_copy != 0) { + traits_type::copy(std::to_address(buffer._data), std::to_address(old_p), n_copy); + } + size_type sec_cp_sz = old_sz - n_del - n_copy; + if (sec_cp_sz != 0) { + traits_type::copy( + std::to_address(buffer._data) + n_copy + n_add, + std::to_address(old_p) + n_copy + n_del, + sec_cp_sz + ); + } + + // This is -1 to make sure the caller sets the size properly, since old versions of this + // function didn't set the size at all. + buffer._size = npos; + replace_internal_buffer(buffer); + set_long_size(old_sz - n_del + n_add); + } - constexpr basic_string& append(size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ch, count); - return *this; - } + // assign - constexpr basic_string& append(const basic_string& str) { - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(str.data(), str.size()); + template + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_no_alias(const value_type* s, size_type n) { + const auto cap = is_short ? min_cap : get_long_cap(); + const auto size = is_short ? get_short_size() : get_long_size(); + if (n >= cap) { + grow_by_and_replace(cap - 1, n - cap + 1, size, 0, size, n, s); return *this; } - constexpr basic_string& append(const basic_string& str, size_type pos, size_type count = npos) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::append(): pos out of range", std::out_of_range); - auto ssv = sview_type(str).substr(pos, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ssv.data(), ssv.length()); - return *this; + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + pointer p; + if (is_short) { + p = get_short_pointer(); + set_short_size(n); + } else { + p = get_long_pointer(); + set_long_size(n); } + traits_type::copy(std::to_address(p), s, n); + traits_type::assign(p[n], value_type()); + return *this; + } - constexpr basic_string& append(const value_type* str, size_type count) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(str, count); + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_external(const value_type* s, size_type n) { + const auto cap = capacity(); + const auto sz = size(); + if (cap >= n) { + if (n > sz) { + annotate_increase(n - sz); + } + value_type* p = std::to_address(get_pointer()); + traits_type::move(p, s, n); + return null_terminate_at(p, n); + } else { + grow_by_and_replace(cap, n - cap, sz, 0, sz, n, s); return *this; } + } - constexpr basic_string& append(const value_type* str) { - auto len = Traits::length(str); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - return append(str, len); - } + template + constexpr basic_string& + basic_string::assign(const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::assign received nullptr"); + return (__builtin_constant_p(n) && fits_in_sso(n)) ? assign_short(s, n) + : assign_external(s, n); + } - template - constexpr basic_string& append(InputIterator first, InputIterator last) { - auto len = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(const_pointer(first), len); - return *this; - } + template + constexpr basic_string& + basic_string::assign(size_type n, value_type c) { + size_type cap = capacity(); + size_type old_size = size(); + if (cap < n) { + grow_by_without_replace(cap, n - cap, old_size, 0, old_size); + annotate_increase(n); + } else if (n > old_size) { + annotate_increase(n - old_size); + } + value_type* p = std::to_address(get_pointer()); + traits_type::assign(p, n, c); + return null_terminate_at(p, n); + } - constexpr basic_string& append(std::initializer_list list) { - PLUGIFY_ASSERT(size() + list.size() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(const_pointer(list.begin()), list.size()); - return *this; - } + template + constexpr basic_string& + basic_string::operator=(value_type c) { + size_type old_size = size(); + if (old_size == 0) { + annotate_increase(1); + } + pointer p; + if (is_long()) { + p = get_long_pointer(); + set_long_size(1); + } else { + p = get_short_pointer(); + set_short_size(1); + } + traits_type::assign(*p, c); + traits_type::assign(*++p, value_type()); + if (old_size > 1) { + annotate_shrink(old_size); + } + return *this; + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& append(const Type& t) { - sview_type sv(t); - PLUGIFY_ASSERT(size() + sv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(sv.data(), sv.size()); + template + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string& + basic_string::operator=(const basic_string& str) { + if (this == std::addressof(str)) { return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& append(const Type& t, size_type pos, size_type count = npos) { - sview_type sv(t); - PLUGIFY_ASSERT(pos <= sv.length(), "plg::basic_string::append(): pos out of range", std::out_of_range); - auto ssv = sv.substr(pos, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ssv.data(), ssv.length()); - return *this; - } + copy_assign_alloc(str); -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string& append_range(Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error); - return append(str); + if (is_long()) { + return assign_no_alias(str.data(), str.size()); } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr basic_string& operator+=(const basic_string& str) { - return append(str); + if (str.is_long()) { + return assign_no_alias(str.data(), str.size()); } - constexpr basic_string& operator+=(value_type ch) { - push_back(ch); - return *this; - } + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + _rep = str._rep; - constexpr basic_string& operator+=(const value_type* str) { - return append(str); - } + return *this; + } - constexpr basic_string& operator+=(std::initializer_list list) { - return append(list); + template + inline constexpr void + basic_string::move_assign(basic_string& str, std::false_type) noexcept( + alloc_traits::is_always_equal::value + ) { + if (_alloc != str._alloc) { + assign(str); + } else { + move_assign(str, std::true_type()); } + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& operator+=(const Type& t) { - return append(sview_type(t)); + template + inline constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void + basic_string::move_assign(basic_string& str, std::true_type) noexcept { + annotate_delete(); + if (is_long()) { + reset_internal_buffer(); + } + size_type str_old_size = str.size(); + bool str_was_short = !str.is_long(); + + move_assign_alloc(str); + _rep = str._rep; + str.set_short_size(0); + traits_type::assign(str.get_short_pointer()[0], value_type()); + + if (str_was_short && this != std::addressof(str)) { + str.annotate_shrink(str_old_size); + } else { + // ASan annotations: was long, so object memory is unpoisoned as new. + // Or is same as *this, and annotate_delete() was called. + str.annotate_new(0); + } + + // ASan annotations: Guard against `std::string s; s = std::move(s);` + // You can find more here: https://en.cppreference.com/w/cpp/utility/move + // Quote: "Unless otherwise specified, all standard library objects that have been moved + // from are placed in a "valid but unspecified state", meaning the object's class + // invariants hold (so functions without preconditions, such as the assignment operator, + // can be safely used on the object after it was moved from):" + // Quote: "v = std::move(v); // the value of v is unspecified" + if (!is_long() && std::addressof(str) != this) { + // If it is long string, delete was never called on original str's buffer. + annotate_new(get_short_size()); } + } - constexpr int compare(const basic_string& str) const noexcept { - return view().compare(str.view()); - } + template + template + constexpr void + basic_string::assign_with_sentinel(InputIterator first, Sentinel last) { + const basic_string temp(init_with_sentinel_tag(), std::move(first), std::move(last), _alloc); + assign(temp.data(), temp.size()); + } - constexpr int compare(size_type pos1, size_type count1, const basic_string& str) const { - return view().compare(pos1, count1, str.view()); + template + template + constexpr void + basic_string::assign_trivial(Iterator first, Sentinel last, size_type n) { + PLUGIFY_ASSERT( + string_is_trivial_iterator_v, + "The iterator type given to `assign_trivial` must be trivial" + ); + + size_type old_size = size(); + size_type cap = capacity(); + if (cap < n) { + // Unlike `append` functions, if the input range points into the string itself, there is + // no case that the input range could get invalidated by reallocation: + // 1. If the input range is a subset of the string itself, its size cannot exceed the + // capacity of the string, + // thus no reallocation would happen. + // 2. In the exotic case where the input range is the byte representation of the string + // itself, the string + // object itself stays valid even if reallocation happens. + size_type sz = size(); + grow_by_without_replace(cap, n - cap, sz, 0, sz); + annotate_increase(n); + } else if (n > old_size) { + annotate_increase(n - old_size); + } + pointer p = get_pointer(); + for (; first != last; ++p, (void) ++first) { + traits_type::assign(*p, *first); + } + traits_type::assign(*p, value_type()); + set_size(n); + if (n < old_size) { + annotate_shrink(old_size); } + } - constexpr int compare(size_type pos1, size_type count1, const basic_string& str, size_type pos2, size_type count2 = npos) const { - return view().compare(pos1, count1, str.view(), pos2, count2); + template + constexpr basic_string& + basic_string::assign(const basic_string& str, size_type pos, size_type n) { + size_type sz = str.size(); + if (pos > sz) { + this->throw_out_of_range(); } + return assign(str.data() + pos, std::min(n, sz - pos)); + } - constexpr int compare(const value_type* str) const { - return view().compare(str); - } + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_external(const value_type* s) { + return assign_external(s, traits_type::length(s)); + } - constexpr int compare(size_type pos1, size_type count1, const value_type* str) const { - return view().compare(pos1, count1, str); + template + constexpr basic_string& + basic_string::assign(const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::assign received nullptr"); + if (auto len = traits_type::length(s); __builtin_constant_p(len) && fits_in_sso(len)) { + return assign_short(s, len); } + return assign_external(s); + } - constexpr int compare(size_type pos1, size_type count1, const value_type* str, size_type count2) const { - return view().compare(pos1, count1, str, count2); - } + // append - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(const Type& t) const noexcept(noexcept(std::is_nothrow_convertible_v)) { - return view().compare(sview_type(t)); + template + constexpr basic_string& + basic_string::append(const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::append received nullptr"); + size_type cap = capacity(); + size_type sz = size(); + if (cap - sz < n) { + grow_by_and_replace(cap, sz + n - cap, sz, sz, 0, n, s); + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(size_type pos1, size_type count1, const Type& t) const { - return view().compare(pos1, count1, sview_type(t)); + if (n == 0) { + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(size_type pos1, size_type count1, const Type& t, size_type pos2, size_type count2 = npos) const { - return view().compare(pos1, count1, sview_type(t), pos2, count2); - } + annotate_increase(n); + value_type* p = std::to_address(get_pointer()); + traits_type::copy(p + sz, s, n); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr bool starts_with(sview_type sv) const noexcept { - return view().starts_with(sv); + template + constexpr basic_string& + basic_string::append(size_type n, value_type c) { + if (n == 0) { + return *this; } - constexpr bool starts_with(Char ch) const noexcept { - return view().starts_with(ch); + size_type cap = capacity(); + size_type sz = size(); + if (cap - sz < n) { + grow_by_without_replace(cap, sz + n - cap, sz, sz, 0); } + annotate_increase(n); + pointer p = get_pointer(); + traits_type::assign(std::to_address(p) + sz, n, c); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr bool starts_with(const Char* str) const { - return view().starts_with(str); - } + template + constexpr void basic_string::push_back(value_type c) { + bool is_short = !is_long(); + size_type cap; + size_type sz; + if (is_short) { + cap = min_cap - 1; + sz = get_short_size(); + } else { + cap = get_long_cap() - 1; + sz = get_long_size(); + } + if (sz == cap) { + grow_by_without_replace(cap, 1, sz, sz, 0); + is_short = false; // the string is always long after grow_by + } + annotate_increase(1); + pointer p; + if (is_short) { + p = get_short_pointer() + sz; + set_short_size(sz + 1); + } else { + p = get_long_pointer() + sz; + set_long_size(sz + 1); + } + traits_type::assign(*p, c); + traits_type::assign(*++p, value_type()); + } - constexpr bool ends_with(sview_type sv) const noexcept { - return view().ends_with(sv); + template + constexpr basic_string& + basic_string::append(const basic_string& str, size_type pos, size_type n) { + size_type sz = str.size(); + if (pos > sz) { + this->throw_out_of_range(); } + return append(str.data() + pos, std::min(n, sz - pos)); + } - constexpr bool ends_with(Char ch) const noexcept { - return view().ends_with(ch); - } + template + constexpr basic_string& + basic_string::append(const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::append received nullptr"); + return append(s, traits_type::length(s)); + } - constexpr bool ends_with(const Char* str) const { - return view().ends_with(str); - } + // insert - constexpr bool contains(sview_type sv) const noexcept { - return view().contains(sv); + template + constexpr basic_string& + basic_string::insert(size_type pos, const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::insert received nullptr"); + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } + size_type cap = capacity(); - constexpr bool contains(Char ch) const noexcept { - return view().contains(ch); + if (cap - sz < n) { + grow_by_and_replace(cap, sz + n - cap, sz, pos, 0, n, s); + return *this; } - constexpr bool contains(const Char* str) const { - return view().contains(str); + if (n == 0) { + return *this; } - constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - return replace(pos, count, str, 0, str.length()); + annotate_increase(n); + value_type* p = std::to_address(get_pointer()); + size_type n_move = sz - pos; + if (n_move != 0) { + if (is_pointer_in_range(p + pos, p + sz, s)) { + s += n; + } + traits_type::move(p + pos + n, p + pos, n_move); } + traits_type::move(p + pos, s, n); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const basic_string& str) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - return replace(pos, count, str, 0, str.length()); + template + constexpr basic_string& + basic_string::insert(size_type pos, size_type n, value_type c) { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } - constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2 = npos) { - PLUGIFY_ASSERT(pos <= size() && pos2 <= str.size(), "plg::basic_string::replace(): pos or pos_str out of range", std::out_of_range); - count2 = std::min(count2, str.length() - pos2); - auto ssv = sview_type(str).substr(pos2, count2); - return replace(pos, count, ssv.data(), ssv.length()); + if (n == 0) { + return *this; } - template - constexpr basic_string& replace(const_iterator first, const_iterator last, InputIterator first2, InputIterator last2) { - return replace(first, last, const_pointer(first2), std::distance(first2, last2)); - } + size_type cap = capacity(); + value_type* p; + if (cap - sz >= n) { + annotate_increase(n); + p = std::to_address(get_pointer()); + size_type n_move = sz - pos; + if (n_move != 0) { + traits_type::move(p + pos + n, p + pos, n_move); + } + } else { + grow_by_without_replace(cap, sz + n - cap, sz, pos, 0, n); + p = std::to_address(get_long_pointer()); + } + traits_type::assign(p + pos, n, c); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr basic_string& replace(size_type pos, size_type count, const value_type* str, size_type count2) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - count = std::min(count, length() - pos); - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - internal_replace(pos, const_pointer(str), count, count2); - return *this; + template + template + constexpr typename basic_string::iterator + basic_string::insert_with_size( + const_iterator pos, + Iterator first, + Sentinel last, + size_type n + ) { + size_type ip = static_cast(pos - begin()); + if (n == 0) { + return begin() + ip; + } + + if (string_is_trivial_iterator_v && !addr_in_range(*first)) { + return insert_from_safe_copy(n, ip, std::move(first), std::move(last)); + } else { + const basic_string temp(init_with_sentinel_tag(), std::move(first), std::move(last), _alloc); + return insert_from_safe_copy(n, ip, temp.begin(), temp.end()); } + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const value_type* str, size_type count2) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - return replace(pos, count, str, count2); - } + template + constexpr basic_string& basic_string::insert( + size_type pos1, + const basic_string& str, + size_type pos2, + size_type n + ) { + size_type str_sz = str.size(); + if (pos2 > str_sz) { + this->throw_out_of_range(); + } + return insert(pos1, str.data() + pos2, std::min(n, str_sz - pos2)); + } - constexpr basic_string& replace(size_type pos, size_type count, const value_type* str) { - return replace(pos, count, str, Traits::length(str)); - } + template + constexpr basic_string& + basic_string::insert(size_type pos, const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::insert received nullptr"); + return insert(pos, s, traits_type::length(s)); + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const value_type* str) { - return replace(first, last, str, Traits::length(str)); + template + constexpr typename basic_string::iterator + basic_string::insert(const_iterator pos, value_type c) { + size_type ip = static_cast(pos - begin()); + size_type sz = size(); + size_type cap = capacity(); + value_type* p; + if (cap == sz) { + grow_by_without_replace(cap, 1, sz, ip, 0, 1); + p = std::to_address(get_long_pointer()); + } else { + annotate_increase(1); + p = std::to_address(get_pointer()); + size_type n_move = sz - ip; + if (n_move != 0) { + traits_type::move(p + ip + 1, p + ip, n_move); + } } + traits_type::assign(p[ip], c); + traits_type::assign(p[++sz], value_type()); + set_size(sz); + return begin() + static_cast(ip); + } - constexpr basic_string& replace(size_type pos, size_type count, size_type count2, value_type ch) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - count = std::min(count, length() - pos); - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - internal_replace(pos, ch, count, count2); + // replace + + template + constexpr basic_string& + basic_string::replace( + size_type pos, + size_type n1, + const value_type* s, + size_type n2 + ) { + PLUGIFY_ASSERT(n2 == 0 || s != nullptr, "string::replace received nullptr"); + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); + } + n1 = std::min(n1, sz - pos); + size_type cap = capacity(); + if (cap - sz + n1 < n2) { + grow_by_and_replace(cap, sz - n1 + n2 - cap, sz, pos, n1, n2, s); return *this; } - constexpr basic_string& replace(const_iterator first, const_iterator last, size_type count2, value_type ch) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - internal_replace(pos, ch, count, count2); - return *this; + value_type* p = std::to_address(get_pointer()); + if (n1 != n2) { + if (n2 > n1) { + annotate_increase(n2 - n1); + } + size_type n_move = sz - pos - n1; + if (n_move != 0) { + if (n1 > n2) { + traits_type::move(p + pos, s, n2); + traits_type::move(p + pos + n2, p + pos + n1, n_move); + return null_terminate_at(p, sz + (n2 - n1)); + } + if (is_pointer_in_range(p + pos + 1, p + sz, s)) { + if (p + pos + n1 <= s) { + s += n2 - n1; + } else { // p + pos < s < p + pos + n1 + traits_type::move(p + pos, s, n1); + pos += n1; + s += n2; + n2 -= n1; + n1 = 0; + } + } + traits_type::move(p + pos + n2, p + pos + n1, n_move); + } } + traits_type::move(p + pos, s, n2); + return null_terminate_at(p, sz + (n2 - n1)); + } - constexpr basic_string& replace(const_iterator first, const_iterator last, std::initializer_list list) { - return replace(first, last, const_pointer(list.begin()), list.size()); + template + constexpr basic_string& + basic_string::replace(size_type pos, size_type n1, size_type n2, value_type c) { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); + } + n1 = std::min(n1, sz - pos); + size_type cap = capacity(); + value_type* p; + if (cap - sz + n1 >= n2) { + p = std::to_address(get_pointer()); + if (n1 != n2) { + if (n2 > n1) { + annotate_increase(n2 - n1); + } + size_type n_move = sz - pos - n1; + if (n_move != 0) { + traits_type::move(p + pos + n2, p + pos + n1, n_move); + } + } + } else { + grow_by_without_replace(cap, sz - n1 + n2 - cap, sz, pos, n1, n2); + p = std::to_address(get_long_pointer()); } + traits_type::assign(p + pos, n2, c); + return null_terminate_at(p, sz - (n1 - n2)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(size_type pos, size_type count, const Type& t) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - sview_type sv(t); - return replace(pos, count, sv.data(), sv.length()); - } + template + constexpr basic_string& + basic_string::replace( + size_type pos1, + size_type n1, + const basic_string& str, + size_type pos2, + size_type n2 + ) { + size_type str_sz = str.size(); + if (pos2 > str_sz) { + this->throw_out_of_range(); + } + return replace(pos1, n1, str.data() + pos2, std::min(n2, str_sz - pos2)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(const_iterator first, const_iterator last, const Type& t) { - sview_type sv(t); - return replace(first, last, sv.data(), sv.length()); - } + template + constexpr basic_string& + basic_string::replace(size_type pos, size_type n1, const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::replace received nullptr"); + return replace(pos, n1, s, traits_type::length(s)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(size_type pos, size_type count, const Type& t, size_type pos2, size_type count2 = npos) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - auto sv = sview_type(t).substr(pos2, count2); - return replace(pos, count, sv.data(), sv.length()); - } + // erase -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr iterator replace_with_range(const_iterator first, const_iterator last, Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - return replace(first, last, str);// replace checks for max_size() + // 'externally instantiated' erase() implementation, called when n != npos. + // Does not check pos against size() + template + PLUGIFY_NOINLINE constexpr void + basic_string::erase_external_with_move(size_type pos, size_type n) { + if (n == 0) { + return; } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr basic_string substr(size_type pos = 0, size_type count = npos) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::substr(): pos out of range", std::out_of_range); - return basic_string(*this, pos, count); + size_type sz = size(); + value_type* p = std::to_address(get_pointer()); + n = std::min(n, sz - pos); + size_type n_move = sz - pos - n; + if (n_move != 0) { + traits_type::move(p + pos, p + pos + n, n_move); } + null_terminate_at(p, sz - n); + } - constexpr size_type copy(value_type* str, size_type count, size_type pos = 0) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::copy(): pos out of range", std::out_of_range); - return view().copy(str, count, pos); + template + constexpr basic_string& + basic_string::erase(size_type pos, size_type n) { + if (pos > size()) { + this->throw_out_of_range(); } - - constexpr void resize(size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::resize(): resulted string size would exceed max_size()", std::length_error); - auto cap = capacity(); - auto sz = size(); - auto rsz = count + sz; - - if (sz < rsz) { - if (cap < rsz) - grow_to(rsz); - Traits::assign(data() + sz, count, ch); - } - set_size(rsz); - null_terminate(); + if (n == npos) { + erase_to_end(pos); + } else { + erase_external_with_move(pos, n); } + return *this; + } - constexpr void resize(size_type count) { - resize(count, _terminator); - } + template + inline constexpr typename basic_string::iterator + basic_string::erase(const_iterator pos) { + PLUGIFY_ASSERT(pos != end(), "string::erase(iterator) called with a non-dereferenceable iterator"); + iterator b = begin(); + size_type r = static_cast(pos - b); + erase(r, 1); + return b + static_cast(r); + } - template - constexpr void resize_and_overwrite(size_type, Operation) { - static_assert(detail::dependent_false, "plg::basic_string::resize_and_overwrite(count, op) not implemented!"); - } + template + inline constexpr typename basic_string::iterator + basic_string::erase(const_iterator first, const_iterator last) { + PLUGIFY_ASSERT(first <= last, "string::erase(first, last) called with invalid range"); + iterator b = begin(); + size_type r = static_cast(first - b); + erase(r, static_cast(last - first)); + return b + static_cast(r); + } - constexpr void swap(basic_string& other) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value) { - using std::swap; - if constexpr (allocator_traits::propagate_on_container_swap::value) { - swap(_allocator, other._allocator); - } - swap(_storage, other._storage); - } + template + inline constexpr void basic_string::pop_back() { + PLUGIFY_ASSERT(!empty(), "string::pop_back(): string is already empty"); + erase_to_end(size() - 1); + } - constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept { - return view().find(sview_type(str), pos); + template + inline constexpr void basic_string::clear() noexcept { + size_type old_size; + if (is_long()) { + old_size = get_long_size(); + traits_type::assign(*get_long_pointer(), value_type()); + set_long_size(0); + } else { + old_size = get_short_size(); + traits_type::assign(*get_short_pointer(), value_type()); + set_short_size(0); } + annotate_shrink(old_size); + } - constexpr size_type find(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find(str, pos, count); + template + constexpr void basic_string::resize(size_type n, value_type c) { + size_type sz = size(); + if (n > sz) { + append(n - sz, c); + } else { + erase_to_end(n); } + } - constexpr size_type find(const value_type* str, size_type pos = 0) const noexcept { - return view().find(str, pos); + template + constexpr void basic_string::reserve(size_type requested_capacity) { + if (requested_capacity > max_size()) { + this->throw_length_error(); } - constexpr size_type find(value_type ch, size_type pos = 0) const noexcept { - return view().find(ch, pos); + // Make sure reserve(n) never shrinks. This is technically only required in C++20 + // and later (since P0966R1), however we provide consistent behavior in all Standard + // modes because this function is instantiated in the shared library. + if (requested_capacity <= capacity()) { + return; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find(sview_type(t), pos); - } + [[maybe_unused]] annotation_guard g(*this); + long_ buffer = allocate_long_buffer(_alloc, requested_capacity); + buffer._size = size(); + traits_type::copy(std::to_address(buffer._data), data(), buffer._size + 1); + replace_internal_buffer(buffer); + } - constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept { - return view().rfind(sview_type(str), pos); + template + inline constexpr void basic_string::shrink_to_fit() noexcept { + size_type target_capacity = recommend(size()); + if (target_capacity == capacity()) { + return; } - constexpr size_type rfind(const value_type* str, size_type pos, size_type count) const noexcept { - return view().rfind(str, pos, count); - } + PLUGIFY_ASSERT(is_long(), "Trying to shrink small string"); - constexpr size_type rfind(const value_type* str, size_type pos = npos) const noexcept { - return view().rfind(str, pos); - } + // We're a long string and we're shrinking into the small buffer. + const auto ptr = get_long_pointer(); + const auto size = get_long_size(); + const auto cap = get_long_cap(); - constexpr size_type rfind(value_type ch, size_type pos = npos) const noexcept { - return view().rfind(ch, pos); + if (fits_in_sso(target_capacity)) { + [[maybe_unused]] annotation_guard g(*this); + set_short_size(size); + traits_type::copy(std::to_address(get_short_pointer()), std::to_address(ptr), size + 1); + alloc_traits::deallocate(_alloc, ptr, cap); + return; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type rfind(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().rfind(sview_type(t), pos); - } +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + [[maybe_unused]] annotation_guard g(*this); + long_ buffer = allocate_long_buffer(_alloc, size); - constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept { - return view().find_first_of(sview_type(str), pos); - } + // The Standard mandates shrink_to_fit() does not increase the capacity. + // With equal capacity keep the existing buffer. This avoids extra work + // due to swapping the elements. + if (buffer._cap * endian_factor - 1 >= capacity()) { + alloc_traits::deallocate(_alloc, buffer._data, buffer._cap * endian_factor); + return; + } - constexpr size_type find_first_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_first_of(str, pos, count); - } + traits_type::copy( + std::to_address(buffer._data), + std::to_address(get_long_pointer()), + size + 1 + ); + replace_internal_buffer(buffer); +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + return; + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr size_type find_first_of(const value_type* str, size_type pos = 0) const noexcept { - return view().find_first_of(str, pos); + template + constexpr typename basic_string::const_reference + basic_string::at(size_type n) const { + if (n >= size()) { + this->throw_out_of_range(); } + return (*this)[n]; + } - constexpr size_type find_first_of(value_type ch, size_type pos = 0) const noexcept { - return view().find_first_of(ch, pos); + template + constexpr typename basic_string::reference + basic_string::at(size_type n) { + if (n >= size()) { + this->throw_out_of_range(); } + return (*this)[n]; + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_first_of(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find_first_of(sview_type(t), pos); + template + constexpr typename basic_string::size_type + basic_string::copy(value_type* s, size_type n, size_type pos) const { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } + size_type rlen = std::min(n, sz - pos); + traits_type::copy(s, data() + pos, rlen); + return rlen; + } - constexpr size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept { - return view().find_first_not_of(sview_type(str), pos); + template + inline constexpr void basic_string::swap(basic_string& str) noexcept { + PLUGIFY_ASSERT( + alloc_traits::propagate_on_container_swap::value || alloc_traits::is_always_equal::value || _alloc == str._alloc, + "swapping non-equal allocators" + ); + if (!is_long()) { + annotate_delete(); } - - constexpr size_type find_first_not_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_first_not_of(str, pos, count); + if (this != std::addressof(str) && !str.is_long()) { + str.annotate_delete(); } - - constexpr size_type find_first_not_of(const value_type* str, size_type pos = 0) const noexcept { - return view().find_first_not_of(str, pos); + std::swap(_rep, str._rep); + swap_allocator(_alloc, str._alloc); + if (!is_long()) { + annotate_new(get_short_size()); } - - constexpr size_type find_first_not_of(value_type ch, size_type pos = 0) const noexcept { - return view().find_first_not_of(ch, pos); + if (this != std::addressof(str) && !str.is_long()) { + str.annotate_new(str.get_short_size()); } + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_first_not_of(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find_first_not_of(sview_type(t), pos); + // compare + + template + inline constexpr int basic_string::compare( + size_type pos1, + size_type n1, + const value_type* s, + size_type n2 + ) const { + PLUGIFY_ASSERT(n2 == 0 || s != nullptr, "string::compare(): received nullptr"); + size_type sz = size(); + if (pos1 > sz || n2 == npos) { + this->throw_out_of_range(); + } + size_type rlen = std::min(n1, sz - pos1); + int r = traits_type::compare(data() + pos1, s, std::min(rlen, n2)); + if (r == 0) { + if (rlen < n2) { + r = -1; + } else if (rlen > n2) { + r = 1; + } } + return r; + } - constexpr size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept { - return view().find_last_of(sview_type(str), pos); - } + // invariants - constexpr size_type find_last_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_last_of(str, pos, count); + template + inline constexpr bool basic_string::invariants() const { + if (size() > capacity()) { + return false; } - - constexpr size_type find_last_of(const value_type* str, size_type pos = npos) const noexcept { - return view().find_last_of(str, pos); + if (capacity() < min_cap - 1) { + return false; } - - constexpr size_type find_last_of(value_type ch, size_type pos = npos) const noexcept { - return view().find_last_of(ch, pos); + if (data() == nullptr) { + return false; } - - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_last_of(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().find_last_of(sview_type(t), pos); + if (!Traits::eq(data()[size()], value_type())) { + return false; } + return true; + } - constexpr size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept { - return view().find_last_not_of(sview_type(str), pos); - } + // operator== - constexpr size_type find_last_not_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_last_not_of(str, pos, count); - } + template + inline constexpr bool operator==( + const basic_string& lhs, + const basic_string& rhs + ) noexcept { + size_t lhs_sz = lhs.size(); + return lhs_sz == rhs.size() && Traits::compare(lhs.data(), rhs.data(), lhs_sz) == 0; + } - constexpr size_type find_last_not_of(const value_type* str, size_type pos = npos) const noexcept { - return view().find_last_not_of(str, pos); - } + template + inline constexpr bool operator==( + const basic_string& lhs, + const CharT* PLUGIFY_NO_NULL rhs + ) noexcept { + PLUGIFY_ASSERT(rhs != nullptr, "operator==(basic_string, char*): received nullptr"); - constexpr size_type find_last_not_of(value_type ch, size_type pos = npos) const noexcept { - return view().find_last_not_of(ch, pos); - } + using String = basic_string; - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_last_not_of(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().find_last_not_of(sview_type(t), pos); + size_t rhs_len = Traits::length(rhs); + if (__builtin_constant_p(rhs_len) && !String::fits_in_sso(rhs_len)) { + if (!lhs.is_long()) { + return false; + } } - - friend constexpr basic_string operator+(const basic_string& lhs, const basic_string& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::copy(buffer + lhs_sz, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; + if (rhs_len != lhs.size()) { + return false; } + return lhs.compare(0, String::npos, rhs, rhs_len) == 0; + } - friend constexpr basic_string operator+(basic_string&& lhs, const basic_string& rhs) { - return std::move(lhs.append(rhs)); - } + template + constexpr auto operator<=>( + const basic_string& lhs, + const basic_string& rhs + ) noexcept { + return std::basic_string_view(lhs) + <=> std::basic_string_view(rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, basic_string&& rhs) { - return std::move(rhs.insert(0, lhs)); - } + template + constexpr auto operator<=>(const basic_string& lhs, const CharT* rhs) { + return std::basic_string_view(lhs) + <=> std::basic_string_view(rhs); + } - friend constexpr basic_string operator+(basic_string&& lhs, basic_string&& rhs) { - return std::move(lhs.append(rhs)); - } + // operator + + + template + constexpr basic_string concatenate_strings( + const Allocator& alloc, + std::type_identity_t> str1, + std::type_identity_t> str2 + ) { + using String = basic_string; + String r( + uninitialized_size_tag(), + str1.size() + str2.size(), + String::alloc_traits::select_on_container_copy_construction(alloc) + ); + auto ptr = std::to_address(r.get_pointer()); + Traits::copy(ptr, str1.data(), str1.size()); + Traits::copy(ptr + str1.size(), str2.data(), str2.size()); + Traits::assign(ptr[str1.size() + str2.size()], CharT()); + return r; + } - friend constexpr basic_string operator+(const Char* lhs, const basic_string& rhs) { - auto lhs_sz = Traits::length(lhs); - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(rhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs, lhs_sz); - Traits::copy(buffer + lhs_sz, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; - } + template + constexpr basic_string operator+( + const basic_string& lhs, + const basic_string& rhs + ) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const Char* lhs, basic_string&& rhs) { - return std::move(rhs.insert(0, lhs)); - } + template + constexpr basic_string + operator+(const CharT* lhs, const basic_string& rhs) { + return concatenate_strings(rhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(Char lhs, const basic_string& rhs) { - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), rhs_sz + 1, basic_string::allocator_traits::select_on_container_copy_construction(rhs._allocator)); - auto buffer = ret.data(); - Traits::assign(buffer, 1, lhs); - Traits::copy(buffer + 1, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; - } + // extern template string operator+ , allocator >(char + // const*, string const&); + + template + constexpr basic_string + operator+(CharT lhs, const basic_string& rhs) { + return concatenate_strings( + rhs.get_allocator(), + std::basic_string_view(std::addressof(lhs), 1), + rhs + ); + } - friend constexpr basic_string operator+(Char lhs, basic_string&& rhs) { - rhs.insert(rhs.begin(), lhs); - return std::move(rhs); - } + template + constexpr basic_string + operator+(const basic_string& lhs, const CharT* rhs) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, const Char* rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = Traits::length(rhs); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::copy(buffer + lhs_sz, rhs, rhs_sz); - ret.null_terminate(); - return ret; - } + template + constexpr basic_string + operator+(const basic_string& lhs, CharT rhs) { + return concatenate_strings( + lhs.get_allocator(), + lhs, + std::basic_string_view(std::addressof(rhs), 1) + ); + } +#if PLUGIFY_HAS_CXX26 + + template + constexpr basic_string operator+( + const basic_string& lhs, + std::type_identity_t> rhs + ) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(basic_string&& lhs, const Char* rhs) { - return std::move(lhs.append(rhs)); - } + template + constexpr basic_string operator+( + std::type_identity_t> lhs, + const basic_string& rhs + ) { + return concatenate_strings(rhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, Char rhs) { - auto lhs_sz = lhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + 1, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::assign(buffer + lhs_sz, 1, rhs); - ret.null_terminate(); - return ret; - } +#endif // PLUGIFY_HAS_CXX26 - friend constexpr basic_string operator+(basic_string&& lhs, Char rhs) { - lhs.push_back(rhs); - return std::move(lhs); - } - }; + template + inline constexpr basic_string operator+( + basic_string&& lhs, + const basic_string& rhs + ) { + return std::move(lhs.append(rhs)); + } - template - constexpr bool operator==(const basic_string& lhs, const basic_string& rhs) noexcept { - return lhs.compare(rhs) == 0; + template + inline constexpr basic_string operator+( + const basic_string& lhs, + basic_string&& rhs + ) { + return std::move(rhs.insert(0, lhs)); } - template - constexpr bool operator==(const basic_string& lhs, const Char* rhs) { - return lhs.compare(rhs) == 0; + template + inline constexpr basic_string + operator+(basic_string&& lhs, basic_string&& rhs) { + return std::move(lhs.append(rhs)); } - template - constexpr std::strong_ordering operator<=>(const basic_string& lhs, const basic_string& rhs) noexcept { - return lhs.compare(rhs) <=> 0; + template + inline constexpr basic_string + operator+(const CharT* lhs, basic_string&& rhs) { + return std::move(rhs.insert(0, lhs)); } - template - constexpr std::strong_ordering operator<=>(const basic_string& lhs, const Char* rhs) { - return lhs.compare(rhs) <=> 0; + template + inline constexpr basic_string + operator+(CharT lhs, basic_string&& rhs) { + rhs.insert(rhs.begin(), lhs); + return std::move(rhs); } - // swap - template - constexpr void swap(basic_string& lhs, basic_string& rhs) noexcept(noexcept(lhs.swap(rhs))) { - lhs.swap(rhs); + template + inline constexpr basic_string + operator+(basic_string&& lhs, const CharT* rhs) { + return std::move(lhs.append(rhs)); } - // erasure - template - constexpr typename basic_string::size_type erase(basic_string& c, const U& value) { - auto it = std::remove(c.begin(), c.end(), value); - auto r = std::distance(it, c.end()); - c.erase(it, c.end()); - return r; + template + inline constexpr basic_string + operator+(basic_string&& lhs, CharT rhs) { + lhs.push_back(rhs); + return std::move(lhs); } - template - constexpr typename basic_string::size_type erase_if(basic_string& c, Pred pred) { - auto it = std::remove_if(c.begin(), c.end(), pred); - auto r = std::distance(it, c.end()); - c.erase(it, c.end()); - return r; +#if PLUGIFY_HAS_CXX26 + + template + constexpr basic_string operator+( + basic_string&& lhs, + std::type_identity_t> rhs + ) { + return std::move(lhs.append(rhs)); + } + + template + constexpr basic_string operator+( + std::type_identity_t> lhs, + basic_string&& rhs + ) { + return std::move(rhs.insert(0, lhs)); } - // deduction guides - template::value_type>> - basic_string(InputIterator, InputIterator, Allocator = Allocator()) -> basic_string::value_type, std::char_traits::value_type>, Allocator>; +#endif // PLUGIFY_HAS_CXX26 + + // swap - template> - explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) -> basic_string; + template + inline constexpr void swap( + basic_string& lhs, + basic_string& rhs + ) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); + } - template> - basic_string(std::basic_string_view, typename basic_string::size_type, typename basic_string::size_type, const Allocator& = Allocator()) -> basic_string; + template + inline constexpr typename basic_string::size_type + erase(basic_string& str, const Up& v) { + auto old_size = str.size(); + str.erase(std::remove(str.begin(), str.end(), v), str.end()); + return old_size - str.size(); + } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template>> - basic_string(std::from_range_t, Range&&, Allocator = Allocator()) -> basic_string, std::char_traits>, Allocator>; -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + inline constexpr typename basic_string::size_type + erase_if(basic_string& str, Predicate pred) { + auto old_size = str.size(); + str.erase(std::remove_if(str.begin(), str.end(), pred), str.end()); + return old_size - str.size(); + } // basic_string typedef-names using string = basic_string; @@ -1701,8 +3618,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtol(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return static_cast(ret); } @@ -1712,8 +3630,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtol(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1723,8 +3642,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoll(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1734,8 +3654,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoul(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1745,8 +3666,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoull(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1756,8 +3678,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtof(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1767,8 +3690,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtod(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1778,19 +3702,22 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtold(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } namespace detail { - template - PLUGIFY_FORCE_INLINE constexpr S to_string(V v) { + template + constexpr S to_string(V v) { // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers. // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented), // so we need +1 here. - constexpr std::size_t bufSize = std::numeric_limits::digits10 + 2; // +1 for minus, +1 for digits10 + constexpr std::size_t bufSize = std::numeric_limits::digits10 + 2; // +1 for minus, + // +1 for + // digits10 char buf[bufSize]; const auto res = std::to_chars(buf, buf + bufSize, v); return S(buf, res.ptr); @@ -1799,7 +3726,12 @@ namespace plg { typedef int (*wide_printf)(wchar_t* __restrict, std::size_t, const wchar_t* __restrict, ...); #if PLUGIFY_COMPILER_MSVC - inline int truncate_snwprintf(wchar_t* __restrict buffer, std::size_t count, const wchar_t* __restrict format, ...) { + inline int truncate_snwprintf( + wchar_t* __restrict buffer, + std::size_t count, + const wchar_t* __restrict format, + ... + ) { int r; va_list args; va_start(args, format); @@ -1809,16 +3741,19 @@ namespace plg { } #endif - PLUGIFY_FORCE_INLINE constexpr wide_printf get_swprintf() noexcept { + constexpr wide_printf get_swprintf() noexcept { #if PLUGIFY_COMPILER_MSVC - return static_cast(truncate_snwprintf); + return static_cast< + int(__cdecl*)(wchar_t* __restrict, std::size_t, const wchar_t* __restrict, ...)>( + truncate_snwprintf + ); #else return swprintf; #endif } - template - PLUGIFY_FORCE_INLINE constexpr S as_string(P sprintf_like, const typename S::value_type* fmt, V v) { + template + constexpr S as_string(P sprintf_like, const typename S::value_type* fmt, V v) { typedef typename S::size_type size_type; S s; s.resize(s.capacity()); @@ -1831,7 +3766,7 @@ namespace plg { s.resize(used); break; } - available = used; // Assume this is advice of how much space we need. + available = used; // Assume this is advice of how much space we need. } else { available = available * 2 + 1; } @@ -1839,7 +3774,7 @@ namespace plg { } return s; } - }// namespace detail + } // namespace detail inline string to_string(int val) { return detail::to_string(val); } inline string to_string(unsigned val) { return detail::to_string(val); } @@ -1860,49 +3795,61 @@ namespace plg { inline wstring to_wstring(float val) { return detail::as_string(detail::get_swprintf(), L"%f", val); } inline wstring to_wstring(double val) { return detail::as_string(detail::get_swprintf(), L"%f", val); } inline wstring to_wstring(long double val) { return detail::as_string(detail::get_swprintf(), L"%Lf", val); } -#endif // PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS +#endif // PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS #ifndef PLUGIFY_STRING_NO_STD_HASH // hash support namespace detail { - template, Allocator>> + template < + typename Char, + typename Allocator, + typename String = basic_string, Allocator> + > struct string_hash_base { constexpr std::size_t operator()(const String& str) const noexcept { - return std::hash{}(typename String::sview_type(str)); + return std::hash{}(typename String::self_view(str)); } }; - }// namespace detail -#endif // PLUGIFY_STRING_NO_STD_HASH + } // namespace detail +#endif // PLUGIFY_STRING_NO_STD_HASH #ifndef PLUGIFY_STRING_NO_STD_FORMAT // format support namespace detail { - template + template static constexpr const Char* format_string() { - if constexpr (std::is_same_v || std::is_same_v) + if constexpr (std::is_same_v || std::is_same_v) { return "{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return L"{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return u"{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return U"{}"; + } return ""; } - template, Allocator>> + template < + typename Char, + typename Allocator, + typename String = basic_string, Allocator> + > struct string_formatter_base { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } - template + template auto format(const String& str, FormatContext& ctx) const { return std::format_to(ctx.out(), format_string(), str.c_str()); } }; } -#endif // PLUGIFY_STRING_NO_STD_FORMAT +#endif // PLUGIFY_STRING_NO_STD_FORMAT inline namespace literals { inline namespace string_literals { @@ -1915,6 +3862,7 @@ namespace plg { #elif PLUGIFY_COMPILER_MSVC PLUGIFY_WARN_IGNORE(4455) #endif + // suffix for basic_string literals constexpr string operator""s(const char* str, std::size_t len) { return string{str, len}; } constexpr u8string operator""s(const char8_t* str, std::size_t len) { return u8string{str, len}; } @@ -1923,29 +3871,34 @@ namespace plg { constexpr wstring operator""s(const wchar_t* str, std::size_t len) { return wstring{str, len}; } PLUGIFY_WARN_POP() - }// namespace string_literals - }// namespace literals -}// namespace plg + } // namespace string_literals + } // namespace literals +} // namespace plg #ifndef PLUGIFY_STRING_NO_STD_HASH // hash support namespace std { - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; -}// namespace std -#endif // PLUGIFY_STRING_NO_STD_HASH + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; +} // namespace std +#endif // PLUGIFY_STRING_NO_STD_HASH #ifndef PLUGIFY_STRING_NO_STD_FORMAT // format support @@ -1954,57 +3907,56 @@ namespace fmt { #else namespace std { #endif - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; -}// namespace std -#endif // PLUGIFY_STRING_NO_STD_FORMAT + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; +} // namespace std +#endif // PLUGIFY_STRING_NO_STD_FORMAT -template +template std::ostream& operator<<(std::ostream& os, const plg::basic_string& str) { - os << str.c_str(); - return os; + os << str.c_str(); + return os; } #ifndef PLUGIFY_STRING_NO_STD_FORMAT #include namespace plg { - namespace detail { - // Concept to match string-like types including char* and const char* - template - concept is_string_like = requires(T v) { - { std::string_view(v) }; - }; - } - - template + template constexpr string join(const Range& range, std::string_view separator) { string result; auto it = range.cbegin(); auto end = range.cend(); - if (it == end) return result; + if (it == end) { + return result; + } // First pass: compute total size size_t total_size = 0; size_t count = 0; for (auto tmp = it; tmp != end; ++tmp) { - using Elem = std::decay_t; - if constexpr (detail::is_string_like) { + using elem = std::decay_t; + if constexpr (string_like) { total_size += std::string_view(*tmp).size(); } else { total_size += std::formatted_size("{}", *tmp); @@ -2019,9 +3971,7 @@ namespace plg { auto in = std::back_inserter(result); // Second pass: actual formatting - /*if (it != end)*/ { - std::format_to(in, "{}", *it++); - } + /*if (it != end)*/ { std::format_to(in, "{}", *it++); } while (it != end) { std::format_to(in, "{}{}", separator, *it++); } @@ -2029,14 +3979,16 @@ namespace plg { return result; } - template + template constexpr string join(const Range& range, Proj&& proj, std::string_view separator) { string result; auto it = range.cbegin(); auto end = range.cend(); - if (it == end) return result; + if (it == end) { + return result; + } // First pass: compute total size size_t total_size = 0; @@ -2044,9 +3996,8 @@ namespace plg { for (auto tmp = it; tmp != end; ++tmp) { auto&& projected = std::invoke(std::forward(proj), *tmp); - using Elem = std::decay_t; - - if constexpr (detail::is_string_like) { + using elem = std::decay_t; + if constexpr (string_like) { total_size += std::string_view(*projected).size(); } else { total_size += std::formatted_size("{}", projected); @@ -2072,5 +4023,5 @@ namespace plg { return result; } -} // namespace plugify -#endif // PLUGIFY_STRING_NO_STD_FORMAT \ No newline at end of file +} // namespace plugify +#endif // PLUGIFY_STRING_NO_STD_FORMAT \ No newline at end of file diff --git a/include/plg/uninitialized.hpp b/include/plg/uninitialized.hpp new file mode 100644 index 0000000..9cc3400 --- /dev/null +++ b/include/plg/uninitialized.hpp @@ -0,0 +1,157 @@ +#pragma once + +namespace plg { + template + struct has_construct_impl : std::false_type {}; + + template + struct has_construct_impl< + decltype((void) std::declval().construct(std::declval()...)), + Alloc, + Args...> : std::true_type {}; + + template + struct has_construct : has_construct_impl {}; + + // __has_destroy + template + struct has_destroy : std::false_type {}; + + template + struct has_destroy().destroy(std::declval()))> + : std::true_type {}; + + template + struct allocator_has_trivial_move_construct : std::negation> {}; + + template + struct allocator_has_trivial_move_construct, Type> : std::true_type {}; + + template + struct allocator_has_trivial_destroy : std::negation> {}; + + template + struct allocator_has_trivial_destroy, U> : std::true_type {}; + + template + struct allocator_has_trivial_copy_construct + : std::negation> {}; + + template + struct allocator_has_trivial_copy_construct, Type> : std::true_type {}; + + // Destroy all elements in [__first, __last) from left to right using allocator destruction. + template + void allocator_destroy(Alloc& alloc, Iter first, Sent last) { + for (; first != last; ++first) + std::allocator_traits::destroy(alloc, std::to_address(first)); + } + + template + class AllocatorDestroyRangeReverse { + public: + AllocatorDestroyRangeReverse(Alloc& alloc, Iter& first, Iter& last) + : _alloc(alloc), _first(first), _last(last) {} + + void operator()() const { + allocator_destroy(_alloc, std::reverse_iterator(_last), std::reverse_iterator(_first)); + } + + private: + Alloc& _alloc; + Iter& _first; + Iter& _last; + }; + + // Copy-construct [first1, last1) in [first2, first2 + N), where N is + // distance(first1, last1). + // + // The caller has to ensure that first2 can hold at least N uninitialized elements. If an + // exception is thrown the already copied elements are destroyed in reverse order of their + // construction. + template + Iter2 uninitialized_allocator_copy_impl( + Alloc& alloc, + Iter1 first1, + Sent1 last1, + Iter2 first2 + ) { + auto destruct_first = first2; + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(alloc, destruct_first, first2) + ); + while (first1 != last1) { + std::allocator_traits::construct(alloc, std::to_address(first2), *first1); + ++first1; + ++first2; + } + guard.complete(); + return first2; + } + + template < + class Alloc, + class In, + class RawTypeIn = std::remove_const_t, + class Out> + // using RawTypeIn because of the allocator extension + requires (std::is_trivially_copy_constructible_v && + std::is_trivially_copy_assignable_v && + std::is_same_v, std::remove_const_t> && + allocator_has_trivial_copy_construct::value) + Out* uninitialized_allocator_copy_impl(Alloc&, In* first1, In* last1, Out* first2) { + return std::copy(first1, last1, const_cast(first2)); + } + + template + Iter2 uninitialized_allocator_copy(Alloc& alloc, Iter1 first1, Sent1 last1, Iter2 first2) { + return uninitialized_allocator_copy_impl(alloc, std::move(first1), std::move(last1), std::move(first2)); + } + + // __uninitialized_allocator_relocate relocates the objects in [__first, __last) into + // __result. + // Relocation means that the objects in [__first, __last) are placed into __result as-if by + // move-construct and destroy, except that the move constructor and destructor may never be + // called if they are known to be equivalent to a memcpy. + // + // Preconditions: __result doesn't contain any objects and [__first, __last) contains + // objects Postconditions: __result contains the objects from [__first, __last) and + // [__first, __last) doesn't contain any objects + // + // The strong exception guarantee is provided if any of the following are true: + // - is_nothrow_move_constructible + // - is_copy_constructible + // - is_trivially_relocatable + template + void uninitialized_allocator_relocate(Alloc& alloc, T* first, T* last, T* result) { + if (std::is_constant_evaluated() || + !is_trivially_relocatable::value || + !allocator_has_trivial_move_construct::value || + !allocator_has_trivial_destroy::value + ) { + auto destruct_first = result; + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(alloc, destruct_first, result) + ); + auto iter = first; + while (iter != last) { + std::allocator_traits::construct( + alloc, + result, +#if PLUGIFY_HAS_EXCEPTIONS + std::move_if_noexcept(*iter) +#else + std::move(*iter) +#endif // PLUGIFY_HAS_EXCEPTIONS + ); + ++iter; + ++result; + } + guard.complete(); + allocator_destroy(alloc, first, last); + } else { + // Casting to void* to suppress clang complaining that this is technically UB. + std::memcpy(static_cast(result), first, sizeof(T) * static_cast(last - first)); + } + } +}; // namespace plg diff --git a/include/plg/variant.hpp b/include/plg/variant.hpp index e9ee06b..9e7ada0 100644 --- a/include/plg/variant.hpp +++ b/include/plg/variant.hpp @@ -1,11 +1,9 @@ #pragma once -#include #include #include // swap #include // used for index_type #include -#include #ifndef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE # include @@ -20,39 +18,41 @@ #define PLG_FWD(x) static_cast(x) #define PLG_MOV(x) static_cast< std::remove_reference_t&& >(x) -#include "plg/macro.hpp" +#include "plg/config.hpp" +#include "plg/concepts.hpp" // from https://github.com/groundswellaudio/swl-variant namespace plg { -#if PLUGIFY_EXCEPTIONS +#if PLUGIFY_HAS_EXCEPTIONS class bad_variant_access : public std::exception { - const char* message = ""; // llvm test requires a well formed what() on default init - public : + public: explicit bad_variant_access(const char* str) noexcept : message{str} {} bad_variant_access() noexcept = default; bad_variant_access(const bad_variant_access&) noexcept = default; bad_variant_access& operator=(const bad_variant_access&) noexcept = default; const char* what() const noexcept override { return message; } + private: + const char* message = ""; // llvm test requires a well formed what() on default init }; -#endif // PLUGIFY_EXCEPTIONS +#endif // PLUGIFY_HAS_EXCEPTIONS namespace detail { //struct variant_tag{}; struct emplacer_tag{}; - } - + } // namespace detail + template struct in_place_type_t : private detail::emplacer_tag {}; - + template struct in_place_index_t : private detail::emplacer_tag {}; - + template inline static constexpr in_place_index_t in_place_index; - + template inline static constexpr in_place_type_t in_place_type; - + namespace detail { template constexpr int find_first_true(bool (&&arr)[N]) { @@ -186,7 +186,6 @@ namespace plg { template<> struct node_trait { - template static constexpr auto elem_size = not(std::is_same_v) ? 2 : 1; @@ -343,9 +342,7 @@ namespace plg { // Ts... must be sorted in ascending size template using smallest_suitable_integer_type = - type_pack_element<(static_cast(Num > std::numeric_limits::max()) + ...), - Ts... - >; + type_pack_element<(static_cast((Num > std::numeric_limits::max())) + ...), Ts...>; // why do we need this again? i think something to do with GCC? namespace swap_trait { @@ -356,7 +353,7 @@ namespace plg { template inline constexpr bool nothrow = noexcept(swap(std::declval(), std::declval())); - } + } // namespace swap_trait #ifndef PLUGIFY_VARIANT_NO_STD_HASH template @@ -500,13 +497,13 @@ namespace plg { #undef CAT2 #undef INJECTSEQ - } // inline namespace v1 + } // namespace v1 struct variant_npos_t { template constexpr bool operator==(T idx) const noexcept { return idx == std::numeric_limits::max(); } }; - } + } // namespace detail inline static constexpr detail::variant_npos_t variant_npos; @@ -556,6 +553,8 @@ namespace plg { static constexpr bool trivial_dtor = std::is_trivially_destructible_v; public: + using trivially_relocatable = std::conditional_t...>, variant, void>; + template using alternative = std::remove_reference_t().template get())>; @@ -578,12 +577,12 @@ namespace plg { requires std::is_default_constructible_v> : _storage{in_place_index<0>}, _current{0} {} - + // copy constructor (trivial) constexpr variant(const variant&) requires trivial_copy_ctor = default; - + // note : both the copy and move constructor cannot be meaningfully constexpr without std::construct_at // copy constructor constexpr variant(const variant& o) @@ -591,7 +590,7 @@ namespace plg { : _storage{detail::dummy_type{}} { construct_from(o); } - + // move constructor (trivial) constexpr variant(variant&&) requires trivial_move_ctor @@ -636,7 +635,7 @@ namespace plg { explicit constexpr variant(in_place_index_t tag, std::initializer_list list, Args&&... args) : _storage{tag, list, PLG_FWD(args)...}, _current{Index} {} - + template requires ( detail::appears_exactly_once @@ -684,12 +683,12 @@ namespace plg { }); return *this; } - + // move assignment(trivial) constexpr variant& operator=(variant&& o) requires (trivial_move_assign and trivial_move_ctor and trivial_dtor) = default; - + // move assignment constexpr variant& operator=(variant&& o) noexcept((std::is_nothrow_move_constructible_v && ...) && (std::is_nothrow_move_assignable_v && ...)) @@ -705,7 +704,7 @@ namespace plg { }); return *this; } - + // generic assignment template requires detail::has_non_ambiguous_match @@ -714,14 +713,14 @@ namespace plg { && std::is_nothrow_constructible_v, T&&>) { using related_type = detail::best_overload_match; constexpr auto new_index = index_of; - + if (_current == new_index) unsafe_get() = PLG_FWD(t); else { constexpr bool do_simple_emplace = std::is_nothrow_constructible_v or not std::is_nothrow_move_constructible_v; - + if constexpr (do_simple_emplace) emplace(PLG_FWD(t)); else { @@ -729,12 +728,12 @@ namespace plg { emplace(PLG_MOV(tmp)); } } - + return *this; } - + // ================================== modifiers (20.7.3.5) - + template requires (std::is_constructible_v && detail::appears_exactly_once) constexpr T& emplace(Args&&... args) { @@ -789,7 +788,7 @@ namespace plg { full._current = npos; }; - switch(static_cast(index() == npos) + static_cast(o.index() == npos) * 2) { + switch (static_cast(index() == npos) + static_cast(o.index() == npos) * 2) { case 0 : break; case 1 : @@ -806,7 +805,7 @@ namespace plg { } } - assert(not(valueless_by_exception() && o.valueless_by_exception())); + PLUGIFY_ASSERT(not(valueless_by_exception() && o.valueless_by_exception()), ""); detail::visit_with_index(o, [&o, this](auto&& elem, auto index_cst) { if (index() == index_cst) { @@ -827,7 +826,7 @@ namespace plg { // we could refactor this detail::destruct>(elem); - o.template emplace_no_dtor<(unsigned)(this_index) >(PLG_MOV(tmp)); + o.template emplace_no_dtor(this_index)>(PLG_MOV(tmp)); }); }); } @@ -838,28 +837,28 @@ namespace plg { template constexpr auto& unsafe_get() & noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return _storage.template get(); } template constexpr auto&& unsafe_get() && noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return PLG_MOV(_storage.template get()); } template constexpr const auto& unsafe_get() const & noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return _storage.template get(); } template constexpr const auto&& unsafe_get() const && noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return PLG_MOV(_storage.template get()); } @@ -876,7 +875,7 @@ namespace plg { return; } } - assert(not o.valueless_by_exception()); + PLUGIFY_ASSERT(not o.valueless_by_exception(), ""); detail::visit_with_index(PLG_FWD(o), PLG_FWD(fn)); } @@ -938,7 +937,7 @@ namespace plg { // destroy the current element without checking for valueless constexpr void reset_no_check() { - assert(index() < size); + PLUGIFY_ASSERT(index() < size, ""); if constexpr (not trivial_dtor) { detail::visit_with_index(*this, [](auto& elem, auto index_cst) { detail::destruct>(elem); @@ -973,8 +972,8 @@ namespace plg { template constexpr bool holds_alternative(const variant& v) noexcept { static_assert((std::is_same_v || ...), "Requested type is not contained in the variant"); - constexpr auto Index = variant::template index_of; - return v.index() == Index; + constexpr auto index = variant::template index_of; + return v.index() == index; } // ========= get by index @@ -982,7 +981,9 @@ namespace plg { template constexpr auto& get(variant& v) { static_assert(Idx < sizeof...(Ts), "Index exceeds the variant size. "); - PLUGIFY_ASSERT(v.index() == Idx, "plg::variant:get(): Bad variant access in get.", bad_variant_access); + if (v.index() != Idx) { + PLUGIFY_THROW("bad variant access in get", bad_variant_access); + } return (v.template unsafe_get()); } @@ -1061,8 +1062,9 @@ namespace plg { template constexpr decltype(auto) visit(Fn&& fn, Vs&&... vs) { if constexpr ((std::decay_t::can_be_valueless || ...)) - PLUGIFY_ASSERT(!(vs.valueless_by_exception() || ...), "plg::variant:visit(): Bad variant access in visit.", bad_variant_access); - + if ((vs.valueless_by_exception() || ...)) { + PLUGIFY_THROW("bad variant access in visit", bad_variant_access); + } if constexpr (sizeof...(Vs) == 1) return detail::visit(PLG_FWD(fn), PLG_FWD(vs)...); else @@ -1151,10 +1153,9 @@ namespace plg { struct monostate{}; constexpr bool operator==(monostate, monostate) noexcept { return true; } - constexpr bool operator> (monostate, monostate) noexcept { return false; } - constexpr bool operator< (monostate, monostate) noexcept { return false; } - constexpr bool operator<=(monostate, monostate) noexcept { return true; } - constexpr bool operator>=(monostate, monostate) noexcept { return true; } + constexpr std::strong_ordering operator<=>(monostate, monostate) noexcept { + return std::strong_ordering::equal; + } // ===================================== specialized algorithms (20.7.10) @@ -1239,7 +1240,7 @@ namespace std { template<> struct hash { - constexpr std::size_t operator()(plg::monostate) const noexcept { return static_cast(-1); } + constexpr std::size_t operator()(plg::monostate) const noexcept { return static_cast(66740831); } }; } // namespace std #endif // PLUGIFY_VARIANT_NO_STD_HASH diff --git a/include/plg/vector.hpp b/include/plg/vector.hpp index 3ec8750..8041c26 100644 --- a/include/plg/vector.hpp +++ b/include/plg/vector.hpp @@ -1,1032 +1,1538 @@ #pragma once +#include +#include +#include +#include +#include +#include #include -#include -#include +#include #include #include -#include -#include -#include -#include #include - -#include -#include -#include - -#if PLUGIFY_VECTOR_CONTAINERS_RANGES && (__cplusplus <= 202002L || !__has_include() || !defined(__cpp_lib_containers_ranges)) -# undef PLUGIFY_VECTOR_CONTAINERS_RANGES -# define PLUGIFY_VECTOR_CONTAINERS_RANGES 0 -#endif - -#if PLUGIFY_VECTOR_CONTAINERS_RANGES -# include -#endif +#include +#include +#include #include "plg/allocator.hpp" - -namespace plg { - namespace detail { - template - concept is_alloc = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; - - struct initialized_value_tag {}; - -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template - concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; +#include "plg/guards.hpp" +#include "plg/split_buffer.hpp" +#include "plg/uninitialized.hpp" + +// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc +#if PLUGIFY_COMPILER_CLANG +# pragma clang system_header +#elif PLUGIFY_COMPILER_GCC +# pragma GCC system_header #endif - } // namespace detail - template - struct vector_iterator { - using allocator_traits = std::allocator_traits; - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename allocator_traits::value_type; - using difference_type = std::ptrdiff_t; - using pointer = typename allocator_traits::pointer; - using reference = value_type&; - protected: - pointer _current; - public: - constexpr vector_iterator() = default; - constexpr vector_iterator(const vector_iterator& other) = default; - constexpr vector_iterator(vector_iterator&& other) = default; - constexpr vector_iterator(pointer ptr) - : _current(ptr) {} - constexpr vector_iterator& operator=(const vector_iterator& other) = default; - constexpr vector_iterator& operator=(vector_iterator&& other) = default; - constexpr ~vector_iterator() = default; - public: - constexpr reference operator*() const noexcept { - return *_current; - } - constexpr pointer operator->() const noexcept { - return _current; - } - constexpr vector_iterator& operator++() noexcept { - ++_current; - return *this; - } - constexpr vector_iterator operator++(int) const noexcept { - return vector_iterator(_current++); - } - constexpr vector_iterator& operator--() noexcept { - --_current; - return *this; - } - constexpr vector_iterator operator--(int) const noexcept { - return vector_iterator(_current--); - } - constexpr vector_iterator& operator+=(const difference_type n) noexcept { - _current += n; - return *this; - } - constexpr vector_iterator operator+(const difference_type n) const noexcept { - vector_iterator temp = *this; - return temp += n; - } - constexpr vector_iterator& operator-=(const difference_type n) noexcept { - _current -= n; - return *this; - } - constexpr vector_iterator operator-(const difference_type n) const noexcept { - vector_iterator temp = *this; - return temp -= n; - } - constexpr reference operator[](const difference_type n) const noexcept { - return _current[n]; - } - template - constexpr friend typename vector_iterator::difference_type operator-(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; - operator const pointer() const noexcept { - return _current; - } -#endif // __cpp_impl_three_way_comparison - pointer base() const noexcept { - return _current; - } - }; +// from https://github.com/masahisa/rtw/ +namespace plg { + namespace detail { + template + struct temp_value { + using allocator_traits = std::allocator_traits; + + union { + T v; + }; + PLUGIFY_NO_UNIQUE_ADDRESS Alloc& a; + + constexpr T* addr() { + return std::addressof(v); + } - template - constexpr typename vector_iterator::difference_type operator-(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - using difference_type = typename vector_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } -#if __cpp_impl_three_way_comparison - template - constexpr auto operator<=>(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); - } -#endif // __cpp_impl_three_way_comparison + constexpr T& get() { + return *addr(); + } - template - struct vector_const_iterator { - using allocator_traits = std::allocator_traits; - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename allocator_traits::value_type; - using difference_type = std::ptrdiff_t; - using pointer = typename allocator_traits::const_pointer; - using reference = const value_type&; - protected: - pointer _current; - public: - constexpr vector_const_iterator() = default; - constexpr vector_const_iterator(const vector_const_iterator& other) = default; - constexpr vector_const_iterator(vector_const_iterator&& other) = default; - constexpr vector_const_iterator(pointer ptr) - : _current(ptr) {} - constexpr vector_const_iterator(const vector_iterator& other) // allow only iterator to const_iterator conversion - : _current(other.base()) {} - constexpr vector_const_iterator& operator=(const vector_const_iterator& other) = default; - constexpr vector_const_iterator& operator=(vector_const_iterator&& other) = default; - constexpr ~vector_const_iterator() = default; - public: - constexpr reference operator*() const noexcept { - return *_current; - } - constexpr pointer operator->() const noexcept { - return _current; - } - constexpr vector_const_iterator& operator++() noexcept { - ++_current; - return *this; - } - constexpr vector_const_iterator operator++(int) noexcept { - return vector_const_iterator(_current++); - } - constexpr vector_const_iterator& operator--() noexcept { - --_current; - return *this; - } - constexpr vector_const_iterator operator--(int) noexcept { - return vector_const_iterator(_current--); - } - constexpr vector_const_iterator& operator+=(const difference_type n) noexcept { - _current += n; - return *this; - } - constexpr vector_const_iterator operator+(const difference_type n) const noexcept { - vector_const_iterator temp = *this; - return temp += n; - } - constexpr vector_const_iterator& operator-=(const difference_type n) noexcept { - _current -= n; - return *this; - } - constexpr vector_const_iterator operator-(const difference_type n) const noexcept { - vector_const_iterator temp = *this; - return temp -= n; - } - constexpr reference operator[](const difference_type n) const noexcept { - return _current[n]; - } - template - constexpr friend typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; -#endif // __cpp_impl_three_way_comparison - template - constexpr friend typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; - operator const pointer() const noexcept { - return _current; - } -#endif // __cpp_impl_three_way_comparison - pointer base() const noexcept { - return _current; - } - }; + template + PLUGIFY_NO_CFI constexpr + explicit temp_value(Alloc& alloc, Args&&... args) + : a(alloc) { + allocator_traits::construct(a, addr(), std::forward(args)...); + } - template - constexpr typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - using difference_type = typename vector_const_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } - template - constexpr auto operator<=>(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); - } - template - constexpr typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - using difference_type = typename vector_const_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } - template - constexpr auto operator<=>(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); + constexpr ~temp_value() { + allocator_traits::destroy(a, addr()); + } + }; } - // vector - // based on implementations from libc++, libstdc++ and Microsoft STL - template> + template > class vector { - using allocator_traits = std::allocator_traits; + template + using split_buffer = split_buffer; public: + // + // Types + // using value_type = T; using allocator_type = Allocator; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; + using alloc_traits = std::allocator_traits; using reference = value_type&; using const_reference = const value_type&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; - using iterator = vector_iterator; - using const_iterator = vector_const_iterator; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - protected: - PLUGIFY_NO_UNIQUE_ADDRESS - allocator_type _allocator; - pointer _begin; - pointer _end; - pointer _capacity; + //static_assert(std::check_valid_allocator::value, ""); + static_assert( + std::is_same_v, + "Allocator::value_type must be same type as value_type" + ); - private: - constexpr static size_type growth_factor = 2; // When resizing, what number to scale by + // + // [vector.cons], construct/copy/destroy + // + constexpr vector() noexcept(std::is_nothrow_default_constructible_v) = default; - constexpr void copy_constructor(const vector& other) { - const size_type capacity = other.capacity(); - _begin = allocator_traits::allocate(_allocator, capacity); - std::uninitialized_copy(other.begin(), other.end(), begin()); - _end = _begin + other.size(); - _capacity = _begin + capacity; + constexpr explicit vector(const allocator_type& a) noexcept + : _alloc(a) { } - template - constexpr void range_constructor(InputIterator first, InputIterator last) { - const size_type count = static_cast(std::distance(first, last)); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_copy(first, last, _begin); - _capacity = _begin + count; - _end = _begin + count; + constexpr explicit vector(size_type n) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n); + } + guard.complete(); } - constexpr bool is_full() const { - return _end == _capacity; + constexpr + explicit vector(size_type n, const allocator_type& a) + : _alloc(a) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n); + } + guard.complete(); } - constexpr size_type calculate_new_capacity() const { - const size_type old_capacity = capacity(); - return old_capacity == 0 ? 1 : growth_factor * old_capacity; + constexpr vector(size_type n, const value_type& x) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n, x); + } + guard.complete(); } - constexpr iterator const_iterator_cast(const_iterator iter) noexcept { - return begin() + (iter - cbegin()); + constexpr + vector(size_type n, const value_type& x, const allocator_type& a) + : _alloc(a) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n, x); + } + guard.complete(); } - constexpr void reallocate(size_type new_capacity) { - reallocate(new_capacity, [](pointer const) {}); + template + constexpr + vector(InputIterator first, InputIterator last) { + init_with_sentinel(first, last); } - template - constexpr void reallocate(size_type new_capacity, const F& construct) { - const size_type old_size = size(); - const size_type old_capacity = capacity(); - PLUGIFY_ASSERT(new_capacity >= old_size, "plg::vector::reallocate(): resulted vector size would exceed size()", std::length_error); - if (new_capacity == old_capacity) - return; - - pointer const new_begin = allocator_traits::allocate(_allocator, new_capacity); - construct(new_begin); - std::uninitialized_move(_begin, _end, new_begin); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + old_size; - _capacity = _begin + new_capacity; - } + template + constexpr + vector(InputIterator first, InputIterator last, const allocator_type& a) + : _alloc(a) { + init_with_sentinel(first, last); + } + + template + constexpr + vector(ForwardIterator first, ForwardIterator last) { + size_type n = static_cast(std::distance(first, last)); + init_with_size(first, last, n); + } + + template + constexpr + vector(ForwardIterator first, ForwardIterator last, const allocator_type& a) + : _alloc(a) { + size_type n = static_cast(std::distance(first, last)); + init_with_size(first, last, n); + } + +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr vector( + std::from_range_t, + Range&& range, + const allocator_type& alloc = allocator_type() + ) : _alloc(alloc) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + init_with_size(std::ranges::begin(range), std::ranges::end(range), n); - template - constexpr void emplace_at_end(const F& construct) { - if (is_full()) { - reallocate(calculate_new_capacity(), construct); } else { - construct(_begin); + init_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } } +#endif - template - constexpr void resize_to(size_type count, const V& value) { - if (count < size()) { - std::destroy(_begin + count, _end); - _end = _begin + count; - } else if (count > size()) { - const size_type old_size = size(); - auto construct = [&](pointer const data) { - if constexpr (std::is_same_v) { - std::uninitialized_fill(data + old_size, data + count, value); - } else { - std::uninitialized_value_construct(data + old_size, data + count); - } - }; - if (count > capacity()) { - reallocate(count, construct); - } else { - construct(_begin); + private: + class destroy_vector { + public: + constexpr explicit destroy_vector(vector& vec) + : vec_(vec) { + } + + constexpr void operator()() { + if (vec_._begin != nullptr) { + vec_.clear(); + vec_.annotate_delete(); + alloc_traits::deallocate(vec_._alloc, vec_._begin, vec_.capacity()); } - _end = _begin + count; } - } - constexpr void swap_without_allocator(vector&& other) noexcept { - using std::swap; - swap(_begin, other._begin); - swap(_end, other._end); - swap(_capacity, other._capacity); - } + private: + vector& vec_; + }; public: - // constructor - constexpr vector() noexcept(std::is_nothrow_default_constructible::value) - : _allocator(Allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { + constexpr ~vector() { + destroy_vector (*this)(); } - constexpr explicit vector(const Allocator& allocator) noexcept - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { + constexpr vector(const vector& x) + : _alloc(alloc_traits::select_on_container_copy_construction(x._alloc)) { + init_with_size(x._begin, x._end, x.size()); } - constexpr vector(size_type count, const T& value, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_fill_n(_begin, count, value); - _capacity = _begin + count; - _end = _begin + count; + constexpr + vector(const vector& x, const std::type_identity_t& a) + : _alloc(a) { + init_with_size(x._begin, x._end, x.size()); } - constexpr explicit vector(size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_value_construct_n(_begin, count); - _capacity = _begin + count; - _end = _begin + count; + constexpr vector& operator=(const vector& x); + + constexpr vector(std::initializer_list il) { + init_with_size(il.begin(), il.end(), il.size()); } - template - constexpr vector(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(static_cast(std::distance(first, last)) <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - range_constructor(first, last); + constexpr + vector(std::initializer_list il, const allocator_type& a) + : _alloc(a) { + init_with_size(il.begin(), il.end(), il.size()); + } + + constexpr vector& + operator=(std::initializer_list il) { + assign(il.begin(), il.end()); + return *this; } - constexpr vector(const vector& other) - : _allocator(other.get_allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - copy_constructor(other); + constexpr vector(vector&& x) noexcept; + + constexpr + vector(vector&& x, const std::type_identity_t& a); + + constexpr vector& operator=(vector&& x) noexcept( + std::allocator_traits::propagate_on_container_move_assignment::value || + std::allocator_traits::is_always_equal::value) + { + move_assign( + x, + std::integral_constant() + ); + return *this; } - constexpr vector(const vector& other, const Allocator& allocator) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - copy_constructor(other); + template + constexpr void + assign(InputIterator first, InputIterator last) { + assign_with_sentinel(first, last); } - constexpr vector(vector&& other) noexcept(std::is_nothrow_move_constructible::value) - : _allocator(Allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - swap(other); + template + constexpr void + assign(ForwardIterator first, ForwardIterator last) { + assign_with_size(first, last, std::distance(first, last)); } - constexpr vector(vector&& other, const Allocator& allocator) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - if constexpr (allocator_traits::is_always_equal::value) { - swap_without_allocator(std::move(other)); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr void assign_range(Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + assign_with_size(std::ranges::begin(range), std::ranges::end(range), n); + } else { - if (get_allocator() == other.get_allocator()) { - swap_without_allocator(std::move(other)); - } else { - const size_type capacity = other.capacity(); - _begin = allocator_traits::allocate(_allocator, capacity); - std::uninitialized_move(other.begin(), other.end(), begin()); - _end = _begin + other.size(); - _capacity = _begin + capacity; - } + assign_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } } +#endif + + constexpr void + assign(size_type n, const_reference u); - constexpr vector(std::initializer_list list, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(list.size() <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - range_constructor(list.begin(), list.end()); + constexpr void + assign(std::initializer_list il) { + assign(il.begin(), il.end()); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr vector(std::from_range_t, Range&& range, const Allocator& alloc = Allocator()) - : vector(std::ranges::begin(range), std::ranges::end(range), alloc) {} -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES + [[nodiscard]] constexpr allocator_type + get_allocator() const noexcept { + return this->_alloc; + } - // destructor - constexpr ~vector() { - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); + // + // Iterators + // + [[nodiscard]] constexpr iterator begin() noexcept { + return make_iter(add_alignment_assumption(this->_begin)); } - // operator= - constexpr vector& operator=(const vector& other) { - if (this == &other) [[unlikely]] { - return *this; - } + [[nodiscard]] constexpr const_iterator + begin() const noexcept { + return make_iter(add_alignment_assumption(this->_begin)); + } - clear(); - if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != other.get_allocator()) { - allocator_traits::deallocate(_allocator, _begin, capacity()); - } - } - _allocator = other.get_allocator(); - } + [[nodiscard]] constexpr iterator end() noexcept { + return make_iter(add_alignment_assumption(this->_end)); + } - assign(other.begin(), other.end()); - return *this; + [[nodiscard]] constexpr const_iterator + end() const noexcept { + return make_iter(add_alignment_assumption(this->_end)); } - constexpr vector& operator=(vector&& other) noexcept( - std::allocator_traits::propagate_on_container_move_assignment::value || - std::allocator_traits::is_always_equal::value) { - if (this == &other) [[unlikely]] { - return *this; - } + [[nodiscard]] constexpr reverse_iterator + rbegin() noexcept { + return reverse_iterator(end()); + } - clear(); - if constexpr (allocator_traits::propagate_on_container_move_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != other.get_allocator()) { - allocator_traits::deallocate(_allocator, _begin, capacity()); - } - } - _allocator = other.get_allocator(); - } + [[nodiscard]] constexpr const_reverse_iterator + rbegin() const noexcept { + return const_reverse_iterator(end()); + } - if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) { - swap_without_allocator(std::move(other)); - } else { - if (get_allocator() == other.get_allocator()) { - swap_without_allocator(std::move(other)); - } else { - assign(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end())); - other.clear(); - } - } - return *this; + [[nodiscard]] constexpr reverse_iterator + rend() noexcept { + return reverse_iterator(begin()); } - constexpr vector& operator=(std::initializer_list list) { - assign(list.begin(), list.end()); - return *this; + [[nodiscard]] constexpr const_reverse_iterator + rend() const noexcept { + return const_reverse_iterator(begin()); } - // assign - constexpr void assign(size_type count, const T& value) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error); - if (count > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_fill_n(new_begin, count, value); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _capacity = _begin + count; - } else if (size() >= count) { - std::fill_n(_begin, count, value); - std::destroy(_begin + count, _end); - } else { - std::fill_n(_begin, size(), value); - std::uninitialized_fill_n(_begin + size(), count - size(), value); - } - _end = _begin + count; + [[nodiscard]] constexpr const_iterator + cbegin() const noexcept { + return begin(); } - template - constexpr void assign(InputIterator first, InputIterator last) { - const size_type count = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error); - if (count > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_copy(first, last, new_begin); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _capacity = _begin + count; - } else if (size() >= count) { - std::copy(first, last, _begin); - std::destroy(_begin + count, _end); - } else { - std::copy(first, first + size(), _begin); - std::uninitialized_copy(first + size(), last, _begin + size()); - } - _end = _begin + count; + [[nodiscard]] constexpr const_iterator + cend() const noexcept { + return end(); } - constexpr void assign(std::initializer_list list) { - assign(list.begin(), list.end()); + [[nodiscard]] constexpr const_reverse_iterator + crbegin() const noexcept { + return rbegin(); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr void assign_range(Range&& range) { - assign(std::ranges::begin(range), std::ranges::end(range)); + [[nodiscard]] constexpr const_reverse_iterator + crend() const noexcept { + return rend(); } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - // get_allocator - constexpr allocator_type get_allocator() const { - return _allocator; + // + // [vector.capacity], capacity + // + [[nodiscard]] constexpr size_type size() const noexcept { + return static_cast(this->_end - this->_begin); } - // element access - constexpr reference at(size_type position) { - PLUGIFY_ASSERT(position < size(), "plg::vector::at(): input index is out of bounds", std::out_of_range); - return *(_begin + position); + [[nodiscard]] constexpr size_type + capacity() const noexcept { + return static_cast(this->_cap - this->_begin); } - constexpr const_reference at(size_type position) const { - PLUGIFY_ASSERT(position < size(), "plg::vector::at(): input index is out of bounds", std::out_of_range); - return *(_begin + position); + [[nodiscard]] constexpr bool + empty() const noexcept { + return this->_begin == this->_end; } - constexpr reference operator[](size_type position) noexcept { - return *(_begin + position); + [[nodiscard]] constexpr size_type + max_size() const noexcept { + return std::min( + alloc_traits::max_size(this->_alloc), + std::numeric_limits::max() + ); } - constexpr const_reference operator[](size_type position) const noexcept { - return *(_begin + position); + constexpr void reserve(size_type n); + constexpr void shrink_to_fit() noexcept; + + // + // element access + // + [[nodiscard]] constexpr reference + operator[](size_type n) noexcept { + PLUGIFY_ASSERT(n < size(), "vector[] index out of bounds"); + return this->_begin[n]; } - constexpr reference front() { - PLUGIFY_ASSERT(!empty(), "plg::vector::front(): vector is empty", std::length_error); - return *_begin; + [[nodiscard]] constexpr const_reference + operator[](size_type n) const noexcept { + PLUGIFY_ASSERT(n < size(), "vector[] index out of bounds"); + return this->_begin[n]; } - constexpr const_reference front() const { - PLUGIFY_ASSERT(!empty(), "plg::vector::front(): vector is empty", std::length_error); - return *_begin; + [[nodiscard]] constexpr reference at(size_type n) { + if (n >= size()) { + this->throw_out_of_range(); + } + return this->_begin[n]; } - constexpr reference back() { - PLUGIFY_ASSERT(!empty(), "plg::vector::back(): vector is empty", std::length_error); - return *(_end - 1); + [[nodiscard]] constexpr const_reference + at(size_type n) const { + if (n >= size()) { + this->throw_out_of_range(); + } + return this->_begin[n]; } - constexpr const_reference back() const { - PLUGIFY_ASSERT(!empty(), "plg::vector::back(): vector is empty", std::length_error); - return *(_end - 1); + [[nodiscard]] constexpr reference front() noexcept { + PLUGIFY_ASSERT(!empty(), "front() called on an empty vector"); + return *this->_begin; } - constexpr T* data() noexcept { - return _begin; + [[nodiscard]] constexpr const_reference + front() const noexcept { + PLUGIFY_ASSERT(!empty(), "front() called on an empty vector"); + return *this->_begin; } - constexpr const T* data() const noexcept { - return _begin; + [[nodiscard]] constexpr reference back() noexcept { + PLUGIFY_ASSERT(!empty(), "back() called on an empty vector"); + return *(this->_end - 1); } - // iterators - constexpr iterator begin() noexcept { - return iterator(_begin); + [[nodiscard]] constexpr const_reference + back() const noexcept { + PLUGIFY_ASSERT(!empty(), "back() called on an empty vector"); + return *(this->_end - 1); } - constexpr const_iterator begin() const noexcept { - return const_iterator(_begin); + // + // [vector.data], data access + // + [[nodiscard]] constexpr value_type* + data() noexcept { + return std::to_address(this->_begin); } - constexpr const_iterator cbegin() const noexcept { - return const_iterator(_begin); + [[nodiscard]] constexpr const value_type* + data() const noexcept { + return std::to_address(this->_begin); } - constexpr iterator end() noexcept { - return iterator(_end); + // + // [vector.modifiers], modifiers + // + constexpr void push_back(const_reference x) { + emplace_back(x); } - constexpr const_iterator end() const noexcept { - return const_iterator(_end); + constexpr void push_back(value_type&& x) { + emplace_back(std::move(x)); } - constexpr const_iterator cend() const noexcept { - return const_iterator(_end); + template + constexpr + reference + emplace_back(Args&&... args); + + template + constexpr void + emplace_back_assume_capacity(Args&&... args) { + PLUGIFY_ASSERT( + size() < capacity(), + "We assume that we have enough space to insert an element at the end of the vector" + ); + ConstructTransaction tx(*this, 1); + alloc_traits::construct(this->_alloc, std::to_address(tx.pos_), std::forward(args)...); + ++tx.pos_; } - constexpr reverse_iterator rbegin() noexcept { - return reverse_iterator(_end); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr void append_range(Range&& range) { + insert_range(end(), std::forward(range)); } +#endif + + constexpr void pop_back() { + PLUGIFY_ASSERT(!empty(), "vector::pop_back called on an empty vector"); + this->destruct_at_end(this->_end - 1); + } + + constexpr iterator + insert(const_iterator position, const_reference x); + + constexpr iterator + insert(const_iterator position, value_type&& x); + template + constexpr iterator + emplace(const_iterator position, Args&&... args); - constexpr const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(_end); + constexpr iterator + insert(const_iterator position, size_type n, const_reference x); + + template + constexpr iterator + insert(const_iterator position, InputIterator first, InputIterator last) { + return insert_with_sentinel(position, first, last); } - constexpr const_reverse_iterator crbegin() const noexcept { - return const_reverse_iterator(_end); + template + constexpr iterator + insert(const_iterator position, ForwardIterator first, ForwardIterator last) { + return insert_with_size(position, first, last, std::distance(first, last)); } - constexpr reverse_iterator rend() noexcept { - return reverse_iterator(_begin); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr iterator + insert_range(const_iterator position, Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + return insert_with_size(position, std::ranges::begin(range), std::ranges::end(range), n); + + } else { + return insert_with_sentinel(position, std::ranges::begin(range), std::ranges::end(range)); + } } +#endif - constexpr const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(_begin); + constexpr iterator + insert(const_iterator position, std::initializer_list il) { + return insert(position, il.begin(), il.end()); } - constexpr const_reverse_iterator crend() const noexcept { - return const_reverse_iterator(_begin); + constexpr iterator erase(const_iterator position); + constexpr iterator + erase(const_iterator first, const_iterator last); + + constexpr void clear() noexcept { + size_type old_size = size(); + base_destruct_at_end(this->_begin); + annotate_shrink(old_size); } - // capacity - constexpr bool empty() const { - return (_begin == _end); + constexpr void resize(size_type sz); + constexpr void + resize(size_type sz, const_reference x); + + constexpr void swap(vector&) noexcept; + + constexpr bool invariants() const; + + private: + pointer _begin = nullptr; + pointer _end = nullptr; + pointer _cap = nullptr; + PLUGIFY_NO_UNIQUE_ADDRESS + allocator_type _alloc; + + // Allocate space for n objects + // throws length_error if n > max_size() + // throws (probably bad_alloc) if memory run out + // Precondition: _begin == _end == _cap == nullptr + // Precondition: n > 0 + // Postcondition: capacity() >= n + // Postcondition: size() == 0 + constexpr void vallocate(size_type n) { + if (n > max_size()) { + this->throw_length_error(); + } + auto allocation = allocate_at_least(this->_alloc, n); + _begin = allocation.ptr; + _end = allocation.ptr; + _cap = _begin + allocation.count; + annotate_new(0); + } + + constexpr void vdeallocate() noexcept; + constexpr size_type recommend(size_type new_size) const; + constexpr void construct_at_end(size_type n); + constexpr void + construct_at_end(size_type n, const_reference x); + + template + constexpr void + init_with_size(InputIterator first, Sentinel last, size_type n) { + auto guard = make_exception_guard(destroy_vector(*this)); + + if (n > 0) { + vallocate(n); + construct_at_end(std::move(first), std::move(last), n); + } + + guard.complete(); } - constexpr size_type size() const noexcept { - return static_cast(_end - _begin); + template + constexpr void + init_with_sentinel(InputIterator first, Sentinel last) { + auto guard = make_exception_guard(destroy_vector(*this)); + + for (; first != last; ++first) { + emplace_back(*first); + } + + guard.complete(); } - constexpr size_type max_size() const noexcept { - return allocator_traits::max_size(_allocator); + template + constexpr void + assign_with_sentinel(Iterator first, Sentinel last); + + // The `Iterator` in `*_with_size` functions can be input-only only if called from + // `*_range` (since C++23). Otherwise, `Iterator` is a forward iterator. + + template + constexpr void + assign_with_size(Iterator first, Sentinel last, difference_type n); + + template + requires (!std::same_as())&&, value_type&&>) + constexpr void + insert_assign_n_unchecked(Iterator first, difference_type n, pointer position) { + for (pointer end_position = position + n; position != end_position; + ++position, (void) ++first) { + detail::temp_value tmp(this->_alloc, *first); + *position = std::move(tmp.get()); + } } - constexpr void reserve(size_type new_capacity) { - PLUGIFY_ASSERT(new_capacity <= max_size(), "plg::vector::reserve(): allocated memory size would exceed max_size()", std::length_error); - if (new_capacity > capacity()) { - reallocate(new_capacity); + template + requires (std::same_as())&&, value_type&&>) + constexpr void + insert_assign_n_unchecked(Iterator first, difference_type n, pointer position) { +#if PLUGIFY_HAS_CXX23 + if constexpr (!std::forward_iterator) { + // Handles input-only sized ranges for insert_range + std::ranges::copy_n(std::move(first), n, position); + } else +#endif + { + std::copy_n(first, n, position); } } - constexpr size_type capacity() const noexcept { - return static_cast(_capacity - _begin); + template + constexpr iterator + insert_with_sentinel(const_iterator position, InputIterator first, Sentinel last); + + template + constexpr iterator + insert_with_size(const_iterator position, Iterator first, Sentinel last, difference_type n); + + template + constexpr void + construct_at_end(InputIterator first, Sentinel last, size_type n); + + constexpr void append(size_type n); + constexpr void + append(size_type n, const_reference x); + + constexpr iterator make_iter(pointer p) noexcept { + return iterator(p); } - constexpr void shrink_to_fit() { - reallocate(size()); + constexpr const_iterator make_iter(const_pointer p) const noexcept { + return const_iterator(p); } - // modifiers - constexpr void clear() noexcept { - std::destroy(_begin, _end); - _end = _begin; - } - - constexpr iterator insert(const_iterator position, const T& value) { - return emplace(position, value); - } - - constexpr iterator insert(const_iterator position, T&& value) { - return emplace(position, std::move(value)); - } - - constexpr iterator insert(const_iterator position, size_type count, const T& value) { - const size_type sz = size(); - const size_type new_size = sz + count; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::insert(): pos out of range", std::out_of_range); - if (count != 0) { - if (new_size > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, new_size); - pointer const old_position = _begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - pointer const new_position = new_begin + position_distance; - std::uninitialized_fill_n(new_position, count, value); - std::uninitialized_move(old_position, _end, new_position + count); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _end; - } else { - pointer const pointer_position = _begin + position_distance; - std::uninitialized_fill_n(_end, count, value); - _end += count; - std::rotate(pointer_position, _end - count, _end); - } - } - return begin() + position_distance; + constexpr void + swap_out_circular_buffer(split_buffer& v); + constexpr pointer + swap_out_circular_buffer(split_buffer& v, pointer p); + constexpr void + move_range(pointer from_s, pointer from_e, pointer to); + constexpr void + move_assign(vector& c, std::true_type) noexcept(std::is_nothrow_move_assignable::value); + constexpr void + move_assign(vector& c, std::false_type) noexcept(alloc_traits::is_always_equal::value); + + constexpr void + destruct_at_end(pointer new_last) noexcept { + size_type old_size = size(); + base_destruct_at_end(new_last); + annotate_shrink(old_size); } - template - constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last) { - const size_type sz = size(); - const size_type count = static_cast(std::distance(first, last)); - const size_type new_size = sz + count; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::insert(): pos out of range", std::out_of_range); - if (count != 0) { - if (new_size > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, new_size); - pointer const old_position = _begin + position_distance; - pointer const new_position = new_begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - std::uninitialized_copy(first, last, new_position); - std::uninitialized_move(old_position, _end, new_position + count); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _end; - } else { - pointer const pointer_position = _begin + position_distance; - std::uninitialized_copy(first, last, _end); - _end += count; - std::rotate(pointer_position, _end - count, _end); - } - } - return begin() + position_distance; + template + constexpr inline pointer + emplace_back_slow_path(Args&&... args); + + // The following functions are no-ops outside of AddressSanitizer mode. + // We call annotations for every allocator, unless explicitly disabled. + // + // To disable annotations for a particular allocator, change value of + // asan_annotate_container_with_allocator to false. + // For more details, see the "Using libc++" documentation page or + // the documentation for sanitizer_annotate_contiguous_container. + + constexpr void + annotate_contiguous_container( + [[maybe_unused]] const void* old_mid, + [[maybe_unused]] const void* new_mid + ) const { + plg::annotate_contiguous_container(data(), data() + capacity(), old_mid, new_mid); } - constexpr iterator insert(const_iterator position, std::initializer_list list) { - return insert(position, list.begin(), list.end()); + constexpr void + annotate_new(size_type current_size) const noexcept { + annotate_contiguous_container(data() + capacity(), data() + current_size); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr iterator insert_range(const_iterator pos, Range&& range) { - return insert(pos - begin(), std::ranges::begin(range), std::ranges::end(range)); + constexpr void annotate_delete() const noexcept { + annotate_contiguous_container(data() + size(), data() + capacity()); } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - template - iterator emplace(const_iterator position, Args&&... args) { - const size_type sz = size(); - const size_type new_size = sz + 1; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::emplace(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::emplace(): pos out of range", std::out_of_range); - if (position == cend()) { - emplace_back(std::forward(args)...); - } else { - if (is_full()) { - const size_type new_capacity = calculate_new_capacity(); - pointer const new_begin = allocator_traits::allocate(_allocator, new_capacity); - pointer const old_position = _begin + position_distance; - pointer const new_position = new_begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - std::construct_at(new_position, std::forward(args)...); - std::uninitialized_move(old_position, _end, new_position + 1); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _begin + new_capacity; - } else { - pointer const pointer_position = _begin + position_distance; - std::construct_at(_end, std::forward(args)...); - ++_end; - std::rotate(pointer_position, _end - 1, _end); - } - } - return begin() + position_distance; + constexpr void + annotate_increase(size_type n) const noexcept { + annotate_contiguous_container(data() + size(), data() + size() + n); + } + + constexpr void + annotate_shrink(size_type old_size) const noexcept { + annotate_contiguous_container(data() + old_size, data() + size()); } - constexpr iterator erase(const_iterator position) { - iterator nonconst_position = const_iterator_cast(position); - if (nonconst_position + 1 != end()) { - std::rotate(nonconst_position, nonconst_position + 1, end()); + struct ConstructTransaction { + constexpr + explicit ConstructTransaction(vector& v, size_type n) + : v_(v) + , pos_(v._end) + , new_end_(v._end + n) { + v.annotate_increase(n); } - --_end; - std::destroy_at(_end); - return nonconst_position; - } - - constexpr iterator erase(const_iterator first, const_iterator last) { - PLUGIFY_ASSERT(first <= last, "plg::vector::erase(): called with invalid range", std::out_of_range); - iterator nonconst_first = const_iterator_cast(first); - iterator nonconst_last = const_iterator_cast(last); - if (nonconst_first != nonconst_last) { - if (nonconst_last != end()) { - std::rotate(nonconst_first, nonconst_last, end()); + + constexpr ~ConstructTransaction() { + v_._end = pos_; + if (pos_ != new_end_) { + v_.annotate_shrink(new_end_ - v_._begin); } - _end = nonconst_first.base() + static_cast(end() - nonconst_last); - std::destroy(_end, _end + static_cast(std::distance(first, last))); } - return nonconst_first; - } - constexpr void push_back(const T& value) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, value); - }); - ++_end; + vector& v_; + pointer pos_; + const const_pointer new_end_; + + ConstructTransaction(const ConstructTransaction&) = delete; + ConstructTransaction& operator=(const ConstructTransaction&) = delete; + }; + + constexpr void + base_destruct_at_end(pointer new_last) noexcept { + pointer soon_to_be_end = this->_end; + while (new_last != soon_to_be_end) { + alloc_traits::destroy(this->_alloc, std::to_address(--soon_to_be_end)); + } + this->_end = new_last; } - constexpr void push_back(T&& value) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, std::move(value)); - }); - ++_end; + constexpr void copy_assign_alloc(const vector& c) { + copy_assign_alloc( + c, + std::integral_constant() + ); } - template - constexpr reference emplace_back(Args&&... args) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::emplace_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, std::forward(args)...); - }); - ++_end; - return back(); + constexpr void + move_assign_alloc(vector& c) noexcept( + !alloc_traits::propagate_on_container_move_assignment::value + || std::is_nothrow_move_assignable::value + ) { + move_assign_alloc( + c, + std::integral_constant() + ); } - constexpr void pop_back() { - PLUGIFY_ASSERT(!empty(), "plg::vector::pop_back(): vector is empty", std::length_error); - --_end; - std::destroy_at(_end); + [[noreturn]] static void throw_length_error() { + PLUGIFY_THROW("allocated memory size would exceed max_size()", std::length_error); } - constexpr void resize(size_type count) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error); - resize_to(count, detail::initialized_value_tag{}); + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); } - constexpr void resize(size_type count, const T& value) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error); - resize_to(count, value); + constexpr void + copy_assign_alloc(const vector& c, std::true_type) { + if (this->_alloc != c._alloc) { + clear(); + annotate_delete(); + alloc_traits::deallocate(this->_alloc, this->_begin, capacity()); + this->_begin = this->_end = this->_cap = nullptr; + } + this->_alloc = c._alloc; } - constexpr vector& operator+=(const T& value) { - push_back(value); - return *this; + constexpr void + copy_assign_alloc(const vector&, std::false_type) { } - constexpr vector& operator+=(T&& value) { - push_back(std::move(value)); - return *this; + constexpr void + move_assign_alloc(vector& c, std::true_type) noexcept( + std::is_nothrow_move_assignable_v + ) { + this->_alloc = std::move(c._alloc); } - constexpr vector& operator+=(const vector& other) { - insert(end(), other.begin(), other.end()); - return *this; + constexpr void + move_assign_alloc(vector&, std::false_type) noexcept { } - constexpr vector& operator+=(vector&& other) { - if (this == &other) [[unlikely]] { - return *this; + template + requires(std::is_pointer_v) + static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(Ptr p) noexcept { + if (!std::is_constant_evaluated()) { + return static_cast(std::assume_aligned(p)); } - - insert(end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end())); - return *this; + return p; } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr void append_range(Range&& range) { - return insert(end(), std::ranges::begin(range), std::ranges::end(range)); + template + requires(!std::is_pointer_v) + static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(Ptr p) noexcept { + return p; } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - constexpr void swap(vector& other) noexcept(std::allocator_traits::propagate_on_container_swap::value || std::allocator_traits::is_always_equal::value) { - using std::swap; - if constexpr (allocator_traits::propagate_on_container_swap::value) { - swap(_allocator, other._allocator); - } - swap(_begin, other._begin); - swap(_end, other._end); - swap(_capacity, other._capacity); + constexpr void + swap_layouts(split_buffer& sb) { + auto vector_begin = _begin; + auto vector_sentinel = _end; + auto vector_cap = _cap; + + auto sb_begin = sb.begin(); + auto sb_sentinel = sb.raw_sentinel(); + auto sb_cap = sb.raw_capacity(); + + // TODO: replace with set_valid_range and set_capacity when vector supports it. + _begin = sb_begin; + _end = sb_sentinel; + _cap = sb_cap; + + sb.set_valid_range(vector_begin, vector_sentinel); + sb.set_capacity(vector_cap); } + }; + + template < + std::input_iterator InputIterator, + is_allocator Alloc> + vector(InputIterator, InputIterator, Alloc = Alloc()) + -> vector, Alloc>; + +#if PLUGIFY_HAS_CXX23 + template < + std::ranges::input_range Range, + is_allocator Alloc> + vector(std::from_range_t, Range&&, Alloc = Alloc()) + -> vector, Alloc>; +#endif + + // swap_out_circular_buffer relocates the objects in [_begin, _end) into the front of v and + // swaps the buffers of *this and v. It is assumed that v provides space for exactly (_end - + // _begin) objects in the front. This function has a strong exception guarantee. + template + constexpr void + vector::swap_out_circular_buffer(split_buffer& v) { + annotate_delete(); + auto new_begin = v.begin() - size(); + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(_begin), + std::to_address(_end), + std::to_address(new_begin) + ); + v.set_valid_range(new_begin, v.end()); + _end = _begin; // All the objects have been destroyed by relocating them. + + swap_layouts(v); + v.set_data(v.begin()); + annotate_new(size()); + } + + // swap_out_circular_buffer relocates the objects in [_begin, p) into the front of v, the + // objects in [p, _end) into the back of v and swaps the buffers of *this and v. It is assumed + // that v provides space for exactly (p - _begin) objects in the front and space for at least + // (_end - p) objects in the back. This function has a strong exception guarantee if _begin == p + // || _end == p. + template + constexpr typename vector::pointer + vector::swap_out_circular_buffer( + split_buffer& v, + pointer p + ) { + annotate_delete(); + pointer ret = v.begin(); + + // Relocate [p, _end) first to avoid having a hole in [_begin, _end) + // in case something in [_begin, p) throws. + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(p), + std::to_address(_end), + std::to_address(v.end()) + ); + auto relocated_so_far = _end - p; + v.set_sentinel(v.end() + relocated_so_far); + _end = p; // The objects in [p, _end) have been destroyed by relocating them. + auto new_begin = v.begin() - (p - _begin); + + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(_begin), + std::to_address(p), + std::to_address(new_begin) + ); + v.set_valid_range(new_begin, v.end()); + _end = _begin; // All the objects have been destroyed by relocating them. + swap_layouts(v); + v.set_data(v.begin()); + annotate_new(size()); + return ret; + } - constexpr operator std::span() noexcept { - return std::span(data(), size()); + template + constexpr void vector::vdeallocate() noexcept { + if (this->_begin != nullptr) { + clear(); + annotate_delete(); + alloc_traits::deallocate(this->_alloc, this->_begin, capacity()); + this->_begin = this->_end = this->_cap = nullptr; } + } - constexpr operator std::span() const noexcept { - return std::span(data(), size()); + // Precondition: new_size > capacity() + template + constexpr inline + typename vector::size_type + vector::recommend(size_type new_size) const { + const size_type ms = max_size(); + if (new_size > ms) { + this->throw_length_error(); + } + const size_type cap = capacity(); + if (cap >= ms / 2) { + return ms; } + return std::max(2 * cap, new_size); + } - constexpr std::span span() const noexcept { - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == size() + n + template + constexpr void vector::construct_at_end(size_type n) { + ConstructTransaction tx(*this, n); + const_pointer new_end = tx.new_end_; + for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos)); } + } - constexpr std::span span() noexcept { - return std::span(data(), size()); + // Copy constructs n objects starting at _end from x + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == old size() + n + // Postcondition: [i] == x for all i in [size() - n, n) + template + constexpr inline void + vector::construct_at_end(size_type n, const_reference x) { + ConstructTransaction tx(*this, n); + const_pointer new_end = tx.new_end_; + for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos), x); } + } + + template + template + constexpr void + vector::construct_at_end(InputIterator first, Sentinel last, size_type n) { + ConstructTransaction tx(*this, n); + tx.pos_ = uninitialized_allocator_copy( + this->_alloc, + std::move(first), + std::move(last), + tx.pos_ + ); + } - template - constexpr std::span span_size() { - PLUGIFY_ASSERT(size() == Size, "plg::vector::span_size(): const_span_size argument does not match size of vector", std::length_error); - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Postcondition: size() == size() + n + // Exception safety: strong. + template + constexpr void vector::append(size_type n) { + if (static_cast(this->_cap - this->_end) >= n) { + this->construct_at_end(n); + } else { + split_buffer v(recommend(size() + n), size(), this->_alloc); + v.construct_at_end(n); + swap_out_circular_buffer(v); } + } - template - constexpr std::span const_span_size() const { - PLUGIFY_ASSERT(size() == Size, "plg::vector::const_span_size(): const_span_size argument does not match size of vector", std::length_error); - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Postcondition: size() == size() + n + // Exception safety: strong. + template + constexpr void + vector::append(size_type n, const_reference x) { + if (static_cast(this->_cap - this->_end) >= n) { + this->construct_at_end(n, x); + } else { + split_buffer v(recommend(size() + n), size(), this->_alloc); + v.construct_at_end(n, x); + swap_out_circular_buffer(v); } + } + + template + constexpr inline + vector::vector(vector&& x) noexcept + : _alloc(std::move(x._alloc)) { + this->_begin = x._begin; + this->_end = x._end; + this->_cap = x._cap; + x._begin = x._end = x._cap = nullptr; + } - constexpr std::span byte_span() const noexcept { - return std::as_bytes(span()); + template + constexpr inline + vector::vector(vector&& x, const std::type_identity_t& a) + : _alloc(a) { + if (a == x._alloc) { + this->_begin = x._begin; + this->_end = x._end; + this->_cap = x._cap; + x._begin = x._end = x._cap = nullptr; + } else { + using Ip = std::move_iterator; + init_with_size(Ip(x.begin()), Ip(x.end()), x.size()); } + } - constexpr std::span byte_span() noexcept { - return std::as_writable_bytes(span()); + template + constexpr void + vector::move_assign(vector& c, std::false_type) noexcept( + alloc_traits::is_always_equal::value + ) { + if (this->_alloc != c._alloc) { + using Ip = std::move_iterator; + assign(Ip(c.begin()), Ip(c.end())); + } else { + move_assign(c, std::true_type()); } + } - constexpr bool contains(const T& elem) const { - return std::find(begin(), end(), elem) != end(); + template + constexpr void + vector::move_assign(vector& c, std::true_type) noexcept( + std::is_nothrow_move_assignable::value + ) { + vdeallocate(); + move_assign_alloc(c); // this can throw + this->_begin = c._begin; + this->_end = c._end; + this->_cap = c._cap; + c._begin = c._end = c._cap = nullptr; + } + + template + constexpr inline vector& + vector::operator=(const vector& x) { + if (this != std::addressof(x)) { + copy_assign_alloc(x); + assign(x._begin, x._end); } + return *this; + } - template - constexpr bool contains_if(F predicate) { - return std::find_if(begin(), end(), predicate) != end(); + template + template + constexpr void + vector::assign_with_sentinel(Iterator first, Sentinel last) { + pointer cur = _begin; + for (; first != last && cur != _end; ++first, (void) ++cur) { + *cur = *first; + } + if (cur != _end) { + destruct_at_end(cur); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } } + } - constexpr auto find(const T& value) const { - return std::find(begin(), end(), value); + template + template + constexpr void + vector::assign_with_size(Iterator first, Sentinel last, difference_type n) { + size_type new_size = static_cast(n); + if (new_size <= capacity()) { + if (new_size > size()) { +#if PLUGIFY_HAS_CXX23 + auto mid = std::ranges::copy_n(std::move(first), size(), this->_begin).in; + construct_at_end(std::move(mid), std::move(last), new_size - size()); +#else + Iterator mid = std::next(first, size()); + std::copy(first, mid, this->_begin); + construct_at_end(mid, last, new_size - size()); +#endif + } else { + pointer m = std::copy(std::move(first), last, this->_begin); + this->destruct_at_end(m); + } + } else { + vdeallocate(); + vallocate(recommend(new_size)); + construct_at_end(std::move(first), std::move(last), new_size); } + } - constexpr auto find(const T& value) { - return std::find(begin(), end(), value); + template + constexpr void + vector::assign(size_type n, const_reference u) { + if (n <= capacity()) { + size_type s = size(); + std::fill_n(this->_begin, std::min(n, s), u); + if (n > s) { + construct_at_end(n - s, u); + } else { + this->destruct_at_end(this->_begin + n); + } + } else { + vdeallocate(); + vallocate(recommend(static_cast(n))); + construct_at_end(n, u); } + } - template - constexpr auto find_if(F predicate) const { - return std::find_if(begin(), end(), predicate); + template + constexpr void vector::reserve(size_type n) { + if (n > capacity()) { + if (n > max_size()) { + this->throw_length_error(); + } + split_buffer v(n, size(), this->_alloc); + swap_out_circular_buffer(v); } + } - template - constexpr auto find_if(F predicate) { - return std::find_if(begin(), end(), predicate); + template + constexpr void vector::shrink_to_fit() noexcept { + if (capacity() > size()) { +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + split_buffer v(size(), size(), this->_alloc); + // The Standard mandates shrink_to_fit() does not increase the capacity. + // With equal capacity keep the existing buffer. This avoids extra work + // due to swapping the elements. + if (v.capacity() < capacity()) { + swap_out_circular_buffer(v); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + } +#endif // PLUGIFY_HAS_EXCEPTIONS } + } - constexpr std::optional find_index(const T& value) { - const auto iter = std::find(begin(), end(), value); - if (iter == end()) { - return {}; + template + template + constexpr typename vector::pointer + vector::emplace_back_slow_path(Args&&... args) { + split_buffer v(recommend(size() + 1), size(), this->_alloc); + // v.emplace_back(std::forward(args)...); + pointer end = v.end(); + alloc_traits::construct(this->_alloc, std::to_address(end), std::forward(args)...); + v.set_sentinel(++end); + swap_out_circular_buffer(v); + return this->_end; + } + + // This makes the compiler inline `else()` if `cond` is known to be false. Currently LLVM + // doesn't do that without the `builtin_constant_p`, since it considers `else` unlikely even + // through it's known to be run. See https://llvm.org/PR154292 + template + constexpr void + if_likely_else(bool cond, If _if, Else _else) { + if (__builtin_constant_p(cond)) { + if (cond) { + _if(); + } else { + _else(); + } + } else { + if (cond) [[likely]] { + _if(); } else { - return iter - begin(); + _else(); } } + } - constexpr std::optional find_index(const T& value) const { - const auto iter = std::find(begin(), end(), value); - if (iter == end()) { - return {}; - } else { - return iter - begin(); + template + template + constexpr inline + typename vector::reference + vector::emplace_back(Args&&... args) { + pointer end = this->_end; + if_likely_else( + end < this->_cap, + [&] { + emplace_back_assume_capacity(std::forward(args)...); + ++end; + }, + [&] { end = emplace_back_slow_path(std::forward(args)...); } + ); + + this->_end = end; + return *(end - 1); + } + + template + constexpr inline + typename vector::iterator + vector::erase(const_iterator position) { + PLUGIFY_ASSERT( + position != end(), + "vector::erase(iterator) called with a non-dereferenceable iterator" + ); + difference_type ps = position - cbegin(); + pointer p = this->_begin + ps; + this->destruct_at_end(std::move(p + 1, this->_end, p)); + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::erase(const_iterator first, const_iterator last) { + PLUGIFY_ASSERT( + first <= last, + "vector::erase(first, last) called with invalid range" + ); + pointer p = this->_begin + (first - begin()); + if (first != last) { + this->destruct_at_end(std::move(p + (last - first), this->_end, p)); + } + return make_iter(p); + } + + template + constexpr void + vector::move_range(pointer from_s, pointer from_e, pointer to) { + pointer old_last = this->_end; + difference_type n = old_last - to; + { + pointer i = from_s + n; + ConstructTransaction tx(*this, from_e - i); + for (pointer pos = tx.pos_; i < from_e; ++i, (void) ++pos, tx.pos_ = pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos), std::move(*i)); } } + std::move_backward(from_s, from_s + n, old_last); + } - template - constexpr std::optional find_index_if(F predicate) { - const auto iter = std::find_if(begin(), end(), predicate); - if (iter == end()) { - return {}; + template + constexpr typename vector::iterator + vector::insert(const_iterator position, const_reference x) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(x); } else { - return iter - begin(); + move_range(p, this->_end, p + 1); + const_pointer xr = std::pointer_traits::pointer_to(x); + if (is_pointer_in_range( + std::to_address(p), + std::to_address(_end), + std::addressof(x) + )) { + ++xr; + } + *p = *xr; + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(x); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::insert(const_iterator position, value_type&& x) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(std::move(x)); + } else { + move_range(p, this->_end, p + 1); + *p = std::move(x); + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(std::move(x)); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + template + constexpr typename vector::iterator + vector::emplace(const_iterator position, Args&&... args) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(std::forward(args)...); + } else { + detail::temp_value tmp(this->_alloc, std::forward(args)...); + move_range(p, this->_end, p + 1); + *p = std::move(tmp.get()); + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(std::forward(args)...); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::insert(const_iterator position, size_type n, const_reference x) { + pointer p = this->_begin + (position - begin()); + if (n > 0) { + if (n <= static_cast(this->_cap - this->_end)) { + size_type old_n = n; + pointer old_last = this->_end; + if (n > static_cast(this->_end - p)) { + size_type cx = n - (this->_end - p); + construct_at_end(cx, x); + n -= cx; + } + if (n > 0) { + move_range(p, old_last, p + old_n); + const_pointer xr = std::pointer_traits::pointer_to(x); + if (is_pointer_in_range( + std::to_address(p), + std::to_address(_end), + std::addressof(x) + )) { + xr += old_n; + } + std::fill_n(p, n, *xr); + } + } else { + split_buffer v( + recommend(size() + n), + p - this->_begin, + this->_alloc + ); + v.construct_at_end(n, x); + p = swap_out_circular_buffer(v, p); } } + return make_iter(p); + } + + template + template + constexpr typename vector::iterator + vector::insert_with_sentinel( + const_iterator position, + InputIterator first, + Sentinel last + ) { + difference_type off = position - begin(); + pointer p = this->_begin + off; + pointer old_last = this->_end; + for (; this->_end != this->_cap && first != last; ++first) { + emplace_back_assume_capacity(*first); + } + + if (first == last) { + (void) std::rotate(p, old_last, this->_end); + } else { + split_buffer v(_alloc); + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(_alloc, old_last, this->_end) + ); + v.construct_at_end_with_sentinel(std::move(first), std::move(last)); + split_buffer merged( + recommend(size() + v.size()), + off, + _alloc + ); // has `off` positions available at the front + uninitialized_allocator_relocate( + _alloc, + std::to_address(old_last), + std::to_address(this->_end), + std::to_address(merged.end()) + ); + guard.complete(); // Release the guard once objects in [old_last_, _end) have been + // successfully relocated. + merged.set_sentinel(merged.end() + (this->_end - old_last)); + this->_end = old_last; + uninitialized_allocator_relocate( + _alloc, + std::to_address(v.begin()), + std::to_address(v.end()), + std::to_address(merged.end()) + ); + merged.set_sentinel(merged.size() + v.size()); + v.set_sentinel(v.begin()); + p = swap_out_circular_buffer(merged, p); + } + return make_iter(p); + } - template - constexpr std::optional find_index_if(F predicate) const { - const auto iter = std::find_if(begin(), end(), predicate); - if (iter == end()) { - return {}; + template + template + constexpr typename vector::iterator + vector::insert_with_size( + const_iterator position, + Iterator first, + Sentinel last, + difference_type n + ) { + pointer p = this->_begin + (position - begin()); + if (n > 0) { + if (n <= this->_cap - this->_end) { + pointer old_last = this->_end; + difference_type dx = this->_end - p; + if (n > dx) { +#if PLUGIFY_HAS_CXX23 + if constexpr (!std::forward_iterator) { + construct_at_end(std::move(first), std::move(last), n); + std::rotate(p, old_last, this->_end); + } else +#endif + { + Iterator m = std::next(first, dx); + construct_at_end(m, last, n - dx); + if (dx > 0) { + move_range(p, old_last, p + n); + insert_assign_n_unchecked(first, dx, p); + } + } + } else { + move_range(p, old_last, p + n); + insert_assign_n_unchecked(std::move(first), n, p); + } } else { - return iter - begin(); + split_buffer v( + recommend(size() + n), + p - this->_begin, + this->_alloc + ); + v.construct_at_end_with_size(std::move(first), n); + p = swap_out_circular_buffer(v, p); } } - }; + return make_iter(p); + } + + template + constexpr void vector::resize(size_type sz) { + size_type cs = size(); + if (cs < sz) { + this->append(sz - cs); + } else if (cs > sz) { + this->destruct_at_end(this->_begin + sz); + } + } + + template + constexpr void + vector::resize(size_type sz, const_reference x) { + size_type cs = size(); + if (cs < sz) { + this->append(sz - cs, x); + } else if (cs > sz) { + this->destruct_at_end(this->_begin + sz); + } + } + + template + constexpr void vector::swap(vector& x) + noexcept + { + PLUGIFY_ASSERT( + alloc_traits::propagate_on_container_swap::value || this->_alloc == x._alloc, + "vector::swap: Either propagate_on_container_swap must be true" + " or the allocators must compare equal" + ); + std::swap(this->_begin, x._begin); + std::swap(this->_end, x._end); + std::swap(this->_cap, x._cap); + swap_allocator(this->_alloc, x._alloc); + } + + template + constexpr bool vector::invariants() const { + if (this->_begin == nullptr) { + if (this->_end != nullptr || this->_cap != nullptr) { + return false; + } + } else { + if (this->_begin > this->_end) { + return false; + } + if (this->_begin == this->_cap) { + return false; + } + if (this->_end > this->_cap) { + return false; + } + } + return true; + } // comparisons template @@ -1046,7 +1552,7 @@ namespace plg { } template - constexpr typename vector::size_type erase(vector& c, const U& value) { + constexpr vector::size_type erase(vector& c, const U& value) { auto it = std::remove(c.begin(), c.end(), value); auto r = std::distance(it, c.end()); c.erase(it, c.end()); @@ -1054,20 +1560,15 @@ namespace plg { } template - constexpr typename vector::size_type erase_if(vector& c, Pred pred) { + constexpr vector::size_type erase_if(vector& c, Pred pred) { auto it = std::remove_if(c.begin(), c.end(), pred); auto r = std::distance(it, c.end()); c.erase(it, c.end()); return r; } - // deduction guides - template::value_type>> - vector(InputIterator, InputIterator, Allocator = Allocator()) -> vector::value_type, Allocator>; - namespace pmr { template using vector = ::plg::vector>; } // namespace pmr - } // namespace plg diff --git a/include/plg/version.hpp b/include/plg/version.hpp index b12ac87..b8e8c00 100644 --- a/include/plg/version.hpp +++ b/include/plg/version.hpp @@ -13,1033 +13,1012 @@ #include #endif -#ifndef PLUGIFY_VECTOR_NO_STD_FORMAT -#include "plg/format.hpp" -#endif - +#include "plg/config.hpp" #include "plg/hash.hpp" -#include "plg/macro.hpp" #include "plg/string.hpp" #include "plg/vector.hpp" +#ifndef PLUGIFY_VECTOR_NO_STD_FORMAT +#include "plg/format.hpp" +#endif + // from https://github.com/Neargye/semver namespace plg { - namespace detail { - template - struct resize_uninitialized { - constexpr static auto resize(T& str, std::size_t size) -> std::void_t { - str.resize(size); - } - }; - - template - struct resize_uninitialized().__resize_default_init(42))>> { - constexpr static void resize(T& str, std::size_t size) { - str.__resize_default_init(size); - } - }; - - template - constexpr std::size_t length(Int n) noexcept { - std::size_t digits = 0; - do { - digits++; - n /= 10; - } while (n != 0); - return digits; - } - - template - constexpr OutputIt to_chars(OutputIt dest, Int n) noexcept { - do { - *(--dest) = static_cast('0' + (n % 10)); - n /= 10; - } while (n != 0); - return dest; - } - - enum struct prerelease_identifier_type { - numeric, - alphanumeric - }; - - struct prerelease_identifier { - prerelease_identifier_type type; - string identifier; - }; - - class version_parser; - class prerelease_comparator; - } - - template - class version { - friend class detail::version_parser; - friend class detail::prerelease_comparator; - - public: - constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase - constexpr version(const version&) = default; - constexpr version(version&&) = default; - constexpr ~version() = default; - - constexpr version& operator=(const version&) = default; - constexpr version& operator=(version&&) = default; - - constexpr I1 major() const noexcept { return major_; } - constexpr I2 minor() const noexcept { return minor_; } - constexpr I3 patch() const noexcept { return patch_; } - - constexpr const string& prerelease_tag() const { return prerelease_tag_; } - constexpr const string& build_metadata() const { return build_metadata_; } - - constexpr string to_string() const; - - private: - I1 major_ = 0; - I2 minor_ = 1; - I3 patch_ = 0; - string prerelease_tag_; - string build_metadata_; - - vector prerelease_identifiers; - - constexpr std::size_t length() const noexcept { - return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 - + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) - + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); - } - - constexpr void clear() noexcept { - major_ = 0; - minor_ = 1; - patch_ = 0; - - prerelease_tag_.clear(); - prerelease_identifiers.clear(); - build_metadata_.clear(); - } - }; - - template - constexpr string version::to_string() const { - string result; - detail::resize_uninitialized{}.resize(result, length()); - - auto it = result.end(); - if (!build_metadata_.empty()) { - it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); - *(--it) = '+'; - } - - if (!prerelease_tag_.empty()) { - it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); - *(--it) = '-'; - } - - it = detail::to_chars(it, patch_); - *(--it) = '.'; - - it = detail::to_chars(it, minor_); - *(--it) = '.'; - - it = detail::to_chars(it, major_); - - return result; - } + namespace detail { + template + struct resize_uninitialized { + constexpr static auto resize(T& str, std::size_t size) -> std::void_t { + str.resize(size); + } + }; + + template + struct resize_uninitialized().__resize_default_init(42))>> { + constexpr static void resize(T& str, std::size_t size) { + str.__resize_default_init(size); + } + }; + + template + constexpr std::size_t length(Int n) noexcept { + std::size_t digits = 0; + do { + digits++; + n /= 10; + } while (n != 0); + return digits; + } + + template + constexpr OutputIt to_chars(OutputIt dest, Int n) noexcept { + do { + *(--dest) = static_cast('0' + (n % 10)); + n /= 10; + } while (n != 0); + return dest; + } + + enum struct prerelease_identifier_type { + numeric, + alphanumeric + }; + + struct prerelease_identifier { + prerelease_identifier_type type; + string identifier; + }; + + class version_parser; + class prerelease_comparator; + } // namespace detail + + template + class version { + friend class detail::version_parser; + friend class detail::prerelease_comparator; + + public: + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value && + is_trivially_relocatable::value, version, void>; + + constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase + constexpr version(const version&) = default; + constexpr version(version&&) = default; + constexpr ~version() = default; + + constexpr version& operator=(const version&) = default; + constexpr version& operator=(version&&) = default; + + constexpr I1 major() const noexcept { return _major; } + constexpr I2 minor() const noexcept { return _minor; } + constexpr I3 patch() const noexcept { return _patch; } + + constexpr const string& prerelease_tag() const { return _prerelease_tag; } + constexpr const string& build_metadata() const { return _build_metadata; } + + constexpr string to_string() const; + + private: + I1 _major = 0; + I2 _minor = 1; + I3 _patch = 0; + string _prerelease_tag; + string _build_metadata; + + vector _prerelease_identifiers; + + constexpr std::size_t length() const noexcept { + return detail::length(_major) + detail::length(_minor) + detail::length(_patch) + 2 + + (_prerelease_tag.empty() ? 0 : _prerelease_tag.length() + 1) + + (_build_metadata.empty() ? 0 : _build_metadata.length() + 1); + } + + constexpr void clear() noexcept { + _major = 0; + _minor = 1; + _patch = 0; + + _prerelease_tag.clear(); + _prerelease_identifiers.clear(); + _build_metadata.clear(); + } + }; + + template + constexpr string version::to_string() const { + string result; + detail::resize_uninitialized{}.resize(result, length()); + + auto* it = result.end(); + if (!_build_metadata.empty()) { + it = std::copy_backward(_build_metadata.begin(), _build_metadata.end(), it); + *(--it) = '+'; + } + + if (!_prerelease_tag.empty()) { + it = std::copy_backward(_prerelease_tag.begin(), _prerelease_tag.end(), it); + *(--it) = '-'; + } + + it = detail::to_chars(it, _patch); + *(--it) = '.'; + + it = detail::to_chars(it, _minor); + *(--it) = '.'; + + it = detail::to_chars(it, _major); + + return result; + } #if __has_include() - struct from_chars_result : std::from_chars_result { - [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } - }; + struct from_chars_result : std::from_chars_result { + [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } + }; #else - struct from_chars_result { - const char* ptr; - std::errc ec; + struct from_chars_result { + const char* ptr; + std::errc ec; - [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } - }; -#endif - - enum class version_compare_option : std::uint8_t { - exclude_prerelease, - include_prerelease - }; - - namespace detail { - constexpr from_chars_result success(const char* ptr) noexcept { - return from_chars_result{ ptr, std::errc{} }; - } - - constexpr from_chars_result failure(const char* ptr, std::errc error_code = std::errc::invalid_argument) noexcept { - return from_chars_result{ ptr, error_code }; - } - - constexpr bool is_digit(char c) noexcept { - return c >= '0' && c <= '9'; - } - - constexpr bool is_letter(char c) noexcept { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); - } - - constexpr std::uint8_t to_digit(char c) noexcept { - return static_cast(c - '0'); - } - - constexpr char to_char(int i) noexcept { - return '0' + (char)i; - } - - template - constexpr bool cmp_less(T t, U u) noexcept - { - if constexpr (std::is_signed_v == std::is_signed_v) - return t < u; - else if constexpr (std::is_signed_v) - return t < 0 || std::make_unsigned_t(t) < u; - else - return u >= 0 && t < std::make_unsigned_t(u); -} - - template - constexpr bool cmp_less_equal(T t, U u) noexcept - { - return !cmp_less(u, t); - } - - template - constexpr bool cmp_greater_equal(T t, U u) noexcept - { - return !cmp_less(t, u); - } - - template - constexpr bool number_in_range(T t) noexcept { - return cmp_greater_equal(t, std::numeric_limits::min()) && cmp_less_equal(t, std::numeric_limits::max()); - } - - constexpr int compare(std::string_view lhs, std::string_view rhs) { -#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) - // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html - // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html - constexpr bool workaround = true; -#else - constexpr bool workaround = false; + [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } + }; #endif - if constexpr (workaround) { - const auto size = std::min(lhs.size(), rhs.size()); - for (std::size_t i = 0; i < size; ++i) { - if (lhs[i] < rhs[i]) { - return -1; - } else if (lhs[i] > rhs[i]) { - return 1; - } - } - - return static_cast(lhs.size() - rhs.size()); - } else { - return lhs.compare(rhs); - } - } - - constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { - // assume that strings don't have leading zeros (we've already checked it at parsing stage). - - if (lhs.size() != rhs.size()) { - return static_cast(lhs.size() - rhs.size()); - } - - for (std::size_t i = 0; i < lhs.size(); ++i) { - int a = lhs[i] - '0'; - int b = rhs[i] - '0'; - if (a != b) { - return a - b; - } - } - - return 0; - } - - enum class token_type : std::uint8_t { - eol, - space, - dot, - plus, - hyphen, - letter, - digit, - range_operator, - logical_or - }; - - enum class range_operator : std::uint8_t { - less, - less_or_equal, - greater, - greater_or_equal, - equal - }; - - struct token { - using value_t = std::variant; - token_type type; - value_t value; - const char* lexeme; - }; - - class token_stream { - public: - constexpr token_stream() = default; - constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} - - constexpr void push(const token& token) noexcept { - tokens_.push_back(token); - } - - constexpr token advance() noexcept { - const token token = get(current_); - ++current_; - return token; - } - - constexpr token peek(std::size_t k = 0) const noexcept { - return get(current_ + k); - } - - constexpr token previous() const noexcept { - return get(current_ - 1); - } - - constexpr bool advanceIfMatch(token& token, token_type type) noexcept { - if (get(current_).type != type) { - return false; - } - - token = advance(); - return true; - } - - constexpr bool advanceIfMatch(token_type type) noexcept { - token token; - return advanceIfMatch(token, type); - } - - constexpr bool consume(token_type type) noexcept { - return advance().type == type; - } - - constexpr bool check(token_type type) const noexcept { - return peek().type == type; - } - - private: - std::size_t current_ = 0; - vector tokens_; - - constexpr token get(std::size_t i) const noexcept { - return tokens_[i]; - } - }; - - class lexer { - public: - explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} - - constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { - from_chars_result result{ text_.data(), std::errc{} }; - - while (!is_eol()) { - result = scan_token(token_stream); - if (!result) { - return result; - } - } - - token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); - - return result; - } - - private: - std::string_view text_; - std::size_t current_pos_; - - constexpr from_chars_result scan_token(token_stream& stream) noexcept { - const char c = advance(); - - switch (c) { - case ' ': - add_token(stream, token_type::space); - break; - case '.': - add_token(stream, token_type::dot); - break; - case '-': - add_token(stream, token_type::hyphen); - break; - case '+': - add_token(stream, token_type::plus); - break; - case '|': - if (advanceIfMatch('|')) { - add_token(stream, token_type::logical_or); - break; - } - return failure(get_prev_symbol()); - case '<': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); - break; - case '>': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); - break; - case '=': - add_token(stream, token_type::range_operator, range_operator::equal); - break; - default: - if (is_digit(c)) { - add_token(stream, token_type::digit, to_digit(c)); - break; - } - else if (is_letter(c)) { - add_token(stream, token_type::letter, c); - break; - } - return failure(get_prev_symbol()); - } - - return success(get_prev_symbol()); - } - - constexpr void add_token(token_stream& stream, token_type type, token::value_t value = {}) noexcept { - const char* lexeme = get_prev_symbol(); - stream.push({ type, value, lexeme}); - } - - constexpr char advance() noexcept { - char c = text_[current_pos_]; - current_pos_ += 1; - return c; - } - - constexpr bool advanceIfMatch(char c) noexcept { - if (is_eol()) { - return false; - } - - if (text_[current_pos_] != c) { - return false; - } - - current_pos_ += 1; - - return true; - } - - constexpr const char* get_prev_symbol() const noexcept { - return text_.data() + current_pos_ - 1; - } - - constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } - }; - - class prerelease_comparator { - public: - template - [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { - if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { - return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); - } - - const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); - - for (std::size_t i = 0; i < count; ++i) { - const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); - if (compare_result != 0) { - return compare_result; - } - } - - return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); - } - - private: - [[nodiscard]] constexpr int compare_identifier(const prerelease_identifier& lhs, const prerelease_identifier& rhs) const noexcept { - if (lhs.type == prerelease_identifier_type::numeric && rhs.type == prerelease_identifier_type::numeric) { - return compare_numerically(lhs.identifier, rhs.identifier); - } else if (lhs.type == prerelease_identifier_type::alphanumeric && rhs.type == prerelease_identifier_type::alphanumeric) { - return detail::compare(lhs.identifier, rhs.identifier); - } - - return lhs.type == prerelease_identifier_type::alphanumeric ? 1 : -1; - } - }; - - class version_parser { - public: - constexpr explicit version_parser(token_stream& stream) : stream_{stream} { - } - - template - constexpr from_chars_result parse(version& out) noexcept { - out.clear(); - - from_chars_result result = parse_number(out.major_); - if (!result) { - return result; - } - - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); - } - - result = parse_number(out.minor_); - if (!result) { - return result; - } - - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); - } - - result = parse_number(out.patch_); - if (!result) { - return result; - } - - if (stream_.advanceIfMatch(token_type::hyphen)) { - result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); - if (!result) { - return result; - } - } - - if (stream_.advanceIfMatch(token_type::plus)) { - result = parse_build_metadata(out.build_metadata_); - if (!result) { - return result; - } - } - - return result; - } - - - private: - token_stream& stream_; - - template - constexpr from_chars_result parse_number(Int& out) { - token token = stream_.advance(); - - if (!is_digit(token)) { - return failure(token.lexeme); - } - - const auto first_digit = std::get(token.value); - std::uint64_t result = first_digit; - - if (first_digit == 0) { - out = static_cast(result); - return success(stream_.peek().lexeme); - } - - while (stream_.advanceIfMatch(token, token_type::digit)) { - result = result * 10 + std::get(token.value); - } - - if (detail::number_in_range(result)) { - out = static_cast(result); - return success(stream_.peek().lexeme); - } - - return failure(token.lexeme, std::errc::result_out_of_range); - } - - constexpr from_chars_result parse_prerelease_tag(string& out, vector& out_identifiers) { - string result; - - do { - if (!result.empty()) { - result.push_back('.'); - } - - string identifier; - if (const auto res = parse_prerelease_identifier(identifier); !res) { - return res; - } - - result.append(identifier); - out_identifiers.push_back(make_prerelease_identifier(identifier)); - - } while (stream_.advanceIfMatch(token_type::dot)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr from_chars_result parse_build_metadata(string& out) { - string result; - - do { - if (!result.empty()) { - result.push_back('.'); - } - - string identifier; - if (const auto res = parse_build_identifier(identifier); !res) { - return res; - } - - result.append(identifier); - } while (stream_.advanceIfMatch(token_type::dot)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr from_chars_result parse_prerelease_identifier(string& out) { - string result; - token token = stream_.advance(); - - do { - switch (token.type) { - case token_type::hyphen: - result.push_back('-'); - break; - case token_type::letter: - result.push_back(std::get(token.value)); - break; - case token_type::digit: - { - const auto digit = std::get(token.value); - - // numerical prerelease identifier doesn't allow leading zero - // 1.2.3-1.alpha is valid, - // 1.2.3-01b is valid as well, but - // 1.2.3-01.alpha is not valid - - // Only check for leading zero when digit is the first character of the - // prerelease identifier. - if (result.empty() && is_leading_zero(digit)) { - return failure(token.lexeme); - } - - result.push_back(to_char(digit)); - break; - } - default: - return failure(token.lexeme); - } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { - auto type = detail::prerelease_identifier_type::numeric; - for (char c : identifier) { - if (c == '-' || detail::is_letter(c)) { - type = detail::prerelease_identifier_type::alphanumeric; - break; - } - } - return detail::prerelease_identifier{ type, identifier }; - } - - constexpr from_chars_result parse_build_identifier(string& out) { - string result; - token token = stream_.advance(); - - do { - switch (token.type) { - case token_type::hyphen: - result.push_back('-'); - break; - case token_type::letter: - result.push_back(std::get(token.value)); - break; - case token_type::digit: - { - const auto digit = std::get(token.value); - result.push_back(to_char(digit)); - break; - } - default: - return failure(token.lexeme); - } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); - - out = result; - return success(stream_.peek().lexeme); - } - - constexpr bool is_leading_zero(int digit) noexcept { - if (digit != 0) { - return false; - } - - size_t k = 0; - int alpha_numerics = 0; - int digits = 0; - - while (true) { - const token token = stream_.peek(k); - - if (!is_alphanumeric(token)) { - break; - } - - ++alpha_numerics; - - if (is_digit(token)) { - ++digits; - } - - ++k; - } - - return digits > 0 && digits == alpha_numerics; - } - - constexpr bool is_digit(const token& token) const noexcept { - return token.type == token_type::digit; - } - - constexpr bool is_eol(const token& token) const noexcept { - return token.type == token_type::eol; - } - - constexpr bool is_alphanumeric(const token& token) const noexcept { - return token.type == token_type::hyphen || token.type == token_type::letter || token.type == token_type::digit; - } - }; - - template - constexpr int compare_prerelease(const version& lhs, const version& rhs) noexcept { - return prerelease_comparator{}.compare(lhs, rhs); - } - - template - constexpr int compare_parsed(const version& lhs, const version& rhs, version_compare_option compare_option) { - int result = lhs.major() - rhs.major(); - if (result != 0) { - return result; - } - - result = lhs.minor() - rhs.minor(); - if (result != 0) { - return result; - } - - result = lhs.patch() - rhs.patch(); - if (result != 0) { - return result; - } - - if (compare_option == version_compare_option::include_prerelease) { - result = detail::compare_prerelease(lhs, rhs); - } - - return result; - } - - template - constexpr from_chars_result parse(std::string_view str, version& out) { - token_stream token_stream; - from_chars_result result = lexer{ str }.scan_tokens(token_stream); - if (!result) { - return result; - } - - result = version_parser{ token_stream }.parse(out); - if (!result) { - return result; - } - - if (!token_stream.consume(token_type::eol)) { - return failure(token_stream.previous().lexeme); - } - - return success(token_stream.previous().lexeme); - } - - } // namespace semver::detail - - template - [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) == 0; - } - - template - [[nodiscard]] constexpr bool operator!=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) != 0; - } - - template - [[nodiscard]] constexpr bool operator>(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) > 0; - } - - template - [[nodiscard]] constexpr bool operator>=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) >= 0; - } - - template - [[nodiscard]] constexpr bool operator<(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) < 0; - } - - template - [[nodiscard]] constexpr bool operator<=(const version& lhs, const version& rhs) noexcept { - return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; - } - -#if __cpp_impl_three_way_comparison >= 201907L - template - [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { - int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); - if (compare == 0) - return std::strong_ordering::equal; - if (compare > 0) - return std::strong_ordering::greater; - return std::strong_ordering::less; - } -#endif + enum class version_compare_option : std::uint8_t { + exclude_prerelease, + include_prerelease + }; + + namespace detail { + constexpr from_chars_result success(const char* ptr) noexcept { + return from_chars_result{ ptr, std::errc{} }; + } + + constexpr from_chars_result failure(const char* ptr, std::errc error_code = std::errc::invalid_argument) noexcept { + return from_chars_result{ ptr, error_code }; + } + + constexpr bool is_digit(char c) noexcept { + return c >= '0' && c <= '9'; + } + + constexpr bool is_letter(char c) noexcept { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + + constexpr std::uint8_t to_digit(char c) noexcept { + return static_cast(c - '0'); + } + + constexpr char to_char(int i) noexcept { + return '0' + (char)i; + } + + template + constexpr bool cmp_less(T t, U u) noexcept { + if constexpr (std::is_signed_v == std::is_signed_v) + return t < u; + else if constexpr (std::is_signed_v) + return t < 0 || std::make_unsigned_t(t) < u; + else + return u >= 0 && t < std::make_unsigned_t(u); + } + + template + constexpr bool cmp_less_equal(T t, U u) noexcept { + return !cmp_less(u, t); + } + + template + constexpr bool cmp_greater_equal(T t, U u) noexcept { + return !cmp_less(t, u); + } - template - constexpr from_chars_result parse(std::string_view str, version& output) { - return detail::parse(str, output); - } - - constexpr bool valid(std::string_view str) { - version v{}; - return detail::parse(str, v); - } - - namespace detail { - template - class range_comparator { - public: - constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} - - constexpr bool contains(const version& other) const noexcept { - switch (op_) { - case range_operator::less: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; - case range_operator::less_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; - case range_operator::greater: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; - case range_operator::greater_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; - case range_operator::equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; - } - return false; - } - - constexpr const version& get_version() const noexcept { return v_; } - - constexpr range_operator get_operator() const noexcept { return op_; } - - constexpr string to_string() const { - string result; - switch (op_) { - case range_operator::less: result += "<"; break; - case range_operator::less_or_equal: result += "<="; break; - case range_operator::greater: result += ">"; break; - case range_operator::greater_or_equal: result += ">="; break; - case range_operator::equal: result += "="; break; - } - result += v_.to_string(); - return result; - } - - private: - version v_; - range_operator op_; - }; - - class range_parser; - - template - class range { - public: - friend class detail::range_parser; - - constexpr bool contains(const version& v, version_compare_option option) const noexcept { - if (option == version_compare_option::exclude_prerelease) { - if (!match_at_least_one_comparator_with_prerelease(v)) { - return false; - } - } - - return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { - return ranges_comparator.contains(v); - }); - } - - constexpr auto begin() const noexcept { - return ranges_comparators_.begin(); - } - - constexpr auto end() const noexcept { - return ranges_comparators_.end(); - } - - constexpr std::size_t size() const noexcept { - return ranges_comparators_.size(); - } - - constexpr bool empty() const noexcept { - return ranges_comparators_.empty(); - } - - constexpr string to_string() const { - return join(ranges_comparators_, " "); - } - - private: - vector> ranges_comparators_; - - constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { - if (v.prerelease_tag().empty()) { - return true; - } - - return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { - const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); - const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; - return has_prerelease && equal_without_prerelease; - }); - } - }; - } - - template - class range_set { - public: - friend class detail::range_parser; - - constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { - return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { - return range.contains(v, option); - }); - } - - constexpr auto begin() const noexcept { - return ranges_.begin(); - } - - constexpr auto end() const noexcept { - return ranges_.end(); - } - - constexpr std::size_t size() const noexcept { - return ranges_.size(); - } - - constexpr bool empty() const noexcept { - return ranges_.empty(); - } - - constexpr string to_string() const { - return join(ranges_, " "); - } - - private: - vector> ranges_; - }; - - namespace detail { - class range_parser { - public: - constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} - - template - constexpr from_chars_result parse(range_set& out) noexcept { - vector> ranges; - - do { - - detail::range range; - if (const auto res = parse_range(range); !res) { - return res; - } - - ranges.push_back(range); - skip_whitespaces(); - - } while (stream_.advanceIfMatch(token_type::logical_or)); - - out.ranges_ = std::move(ranges); - - return success(stream_.peek().lexeme); - } - - private: - token_stream stream_; - - template - constexpr from_chars_result parse_range(detail::range& out) noexcept { - do { - skip_whitespaces(); - - if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { - return res; - } - - skip_whitespaces(); - - } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); - - return success(stream_.peek().lexeme); - } - - template - constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { - range_operator op = range_operator::equal; - token token; - if (stream_.advanceIfMatch(token, token_type::range_operator)) { - op = std::get(token.value); - } - - skip_whitespaces(); - - version ver; - version_parser parser{ stream_ }; - if (const auto res = parser.parse(ver); !res) { - return res; - } - - out.emplace_back(ver, op); - return success(stream_.peek().lexeme); - } - - constexpr void skip_whitespaces() noexcept { - while (stream_.advanceIfMatch(token_type::space)) { - ; - } - } - }; - } // namespace semver::detail - - - template - constexpr from_chars_result parse(std::string_view str, range_set& out) { - detail::token_stream token_stream; - const from_chars_result result = detail::lexer{ str }.scan_tokens(token_stream); - if (!result) { - return result; - } - - return detail::range_parser{ std::move(token_stream) }.parse(out); - } -} // namespace semver + template + constexpr bool number_in_range(T t) noexcept { + return cmp_greater_equal(t, std::numeric_limits::min()) && cmp_less_equal(t, std::numeric_limits::max()); + } + + constexpr int compare(std::string_view lhs, std::string_view rhs) { + return lhs.compare(rhs); + } + + constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { + // assume that strings don't have leading zeros (we've already checked it at parsing stage). + + if (lhs.size() != rhs.size()) { + return static_cast(lhs.size() - rhs.size()); + } + + for (std::size_t i = 0; i < lhs.size(); ++i) { + int a = lhs[i] - '0'; + int b = rhs[i] - '0'; + if (a != b) { + return a - b; + } + } + + return 0; + } + + enum class token_type : std::uint8_t { + eol, + space, + dot, + plus, + hyphen, + letter, + digit, + range_operator, + logical_or + }; + + enum class range_operator : std::uint8_t { + less, + less_or_equal, + greater, + greater_or_equal, + equal + }; + + struct token { + using value_t = std::variant; + token_type type; + value_t value; + const char* lexeme; + }; + + class token_stream { + public: + constexpr token_stream() = default; + constexpr explicit token_stream(vector tokens) noexcept : _tokens(std::move(tokens)) {} + + constexpr void push(const token& token) noexcept { + _tokens.push_back(token); + } + + constexpr token advance() noexcept { + const token token = get(_current); + ++_current; + return token; + } + + constexpr token peek(std::size_t k = 0) const noexcept { + return get(_current + k); + } + + constexpr token previous() const noexcept { + return get(_current - 1); + } + + constexpr bool advance_if_match(token& token, token_type type) noexcept { + if (get(_current).type != type) { + return false; + } + + token = advance(); + return true; + } + + constexpr bool advance_if_match(token_type type) noexcept { + token token; + return advance_if_match(token, type); + } + + constexpr bool consume(token_type type) noexcept { + return advance().type == type; + } + + constexpr bool check(token_type type) const noexcept { + return peek().type == type; + } + + private: + std::size_t _current = 0; + vector _tokens; + + constexpr token get(std::size_t i) const noexcept { + return _tokens[i]; + } + }; + + class lexer { + public: + explicit constexpr lexer(std::string_view text) noexcept : _text{text}, _current_pos{0} {} + + constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { + from_chars_result result{ _text.data(), std::errc{} }; + + while (!is_eol()) { + result = scan_token(token_stream); + if (!result) { + return result; + } + } + + token_stream.push({ token_type::eol, {}, _text.data() + _text.size() }); + + return result; + } + + private: + std::string_view _text; + std::size_t _current_pos; + + constexpr from_chars_result scan_token(token_stream& stream) noexcept { + const char c = advance(); + + switch (c) { + case ' ': + add_token(stream, token_type::space); + break; + case '.': + add_token(stream, token_type::dot); + break; + case '-': + add_token(stream, token_type::hyphen); + break; + case '+': + add_token(stream, token_type::plus); + break; + case '|': + if (advance_if_match('|')) { + add_token(stream, token_type::logical_or); + break; + } + return failure(get_prev_symbol()); + case '<': + add_token(stream, token_type::range_operator, advance_if_match('=') ? range_operator::less_or_equal : range_operator::less); + break; + case '>': + add_token(stream, token_type::range_operator, advance_if_match('=') ? range_operator::greater_or_equal : range_operator::greater); + break; + case '=': + add_token(stream, token_type::range_operator, range_operator::equal); + break; + default: + if (is_digit(c)) { + add_token(stream, token_type::digit, to_digit(c)); + break; + } + else if (is_letter(c)) { + add_token(stream, token_type::letter, c); + break; + } + return failure(get_prev_symbol()); + } + + return success(get_prev_symbol()); + } + + constexpr void add_token(token_stream& stream, token_type type, token::value_t value = {}) noexcept { + const char* lexeme = get_prev_symbol(); + stream.push({ type, value, lexeme}); + } + + constexpr char advance() noexcept { + char c = _text[_current_pos]; + _current_pos += 1; + return c; + } + + constexpr bool advance_if_match(char c) noexcept { + if (is_eol()) { + return false; + } + + if (_text[_current_pos] != c) { + return false; + } + + _current_pos += 1; + + return true; + } + + constexpr const char* get_prev_symbol() const noexcept { + return _text.data() + _current_pos - 1; + } + + constexpr bool is_eol() const noexcept { return _current_pos >= _text.size(); } + }; + + class prerelease_comparator { + public: + template + [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { + if (lhs._prerelease_identifiers.empty() != rhs._prerelease_identifiers.empty()) { + return static_cast(rhs._prerelease_identifiers.size()) - static_cast(lhs._prerelease_identifiers.size()); + } + + const std::size_t count = std::min(lhs._prerelease_identifiers.size(), rhs._prerelease_identifiers.size()); + + for (std::size_t i = 0; i < count; ++i) { + const int compare_result = compare_identifier(lhs._prerelease_identifiers[i], rhs._prerelease_identifiers[i]); + if (compare_result != 0) { + return compare_result; + } + } + + return static_cast(lhs._prerelease_identifiers.size()) - static_cast(rhs._prerelease_identifiers.size()); + } + + private: + [[nodiscard]] constexpr int compare_identifier(const prerelease_identifier& lhs, const prerelease_identifier& rhs) const noexcept { + if (lhs.type == prerelease_identifier_type::numeric && rhs.type == prerelease_identifier_type::numeric) { + return compare_numerically(lhs.identifier, rhs.identifier); + } else if (lhs.type == prerelease_identifier_type::alphanumeric && rhs.type == prerelease_identifier_type::alphanumeric) { + return detail::compare(lhs.identifier, rhs.identifier); + } + + return lhs.type == prerelease_identifier_type::alphanumeric ? 1 : -1; + } + }; + + class version_parser { + public: + constexpr explicit version_parser(token_stream& stream) : _stream{stream} { + } + + template + constexpr from_chars_result parse(version& out) noexcept { + out.clear(); + + from_chars_result result = parse_number(out._major); + if (!result) { + return result; + } + + if (!_stream.consume(token_type::dot)) { + return failure(_stream.previous().lexeme); + } + + result = parse_number(out._minor); + if (!result) { + return result; + } + + if (!_stream.consume(token_type::dot)) { + return failure(_stream.previous().lexeme); + } + + result = parse_number(out._patch); + if (!result) { + return result; + } + + if (_stream.advance_if_match(token_type::hyphen)) { + result = parse_prerelease_tag(out._prerelease_tag, out._prerelease_identifiers); + if (!result) { + return result; + } + } + + if (_stream.advance_if_match(token_type::plus)) { + result = parse_build_metadata(out._build_metadata); + if (!result) { + return result; + } + } + + return result; + } + + + private: + token_stream& _stream; + + template + constexpr from_chars_result parse_number(Int& out) { + token token = _stream.advance(); + + if (!is_digit(token)) { + return failure(token.lexeme); + } + + const auto first_digit = std::get(token.value); + std::uint64_t result = first_digit; + + if (first_digit == 0) { + out = static_cast(result); + return success(_stream.peek().lexeme); + } + + while (_stream.advance_if_match(token, token_type::digit)) { + result = result * 10 + std::get(token.value); + } + + if (detail::number_in_range(result)) { + out = static_cast(result); + return success(_stream.peek().lexeme); + } + + return failure(token.lexeme, std::errc::result_out_of_range); + } + + constexpr from_chars_result parse_prerelease_tag(string& out, vector& out_identifiers) { + string result; + + do { + if (!result.empty()) { + result.push_back('.'); + } + + string identifier; + if (const auto res = parse_prerelease_identifier(identifier); !res) { + return res; + } + + result.append(identifier); + out_identifiers.push_back(make_prerelease_identifier(identifier)); + + } while (_stream.advance_if_match(token_type::dot)); + + out = result; + return success(_stream.peek().lexeme); + } + + constexpr from_chars_result parse_build_metadata(string& out) { + string result; + + do { + if (!result.empty()) { + result.push_back('.'); + } + + string identifier; + if (const auto res = parse_build_identifier(identifier); !res) { + return res; + } + + result.append(identifier); + } while (_stream.advance_if_match(token_type::dot)); + + out = result; + return success(_stream.peek().lexeme); + } + + constexpr from_chars_result parse_prerelease_identifier(string& out) { + string result; + token token = _stream.advance(); + + do { + switch (token.type) { + case token_type::hyphen: + result.push_back('-'); + break; + case token_type::letter: + result.push_back(std::get(token.value)); + break; + case token_type::digit: + { + const auto digit = std::get(token.value); + + // numerical prerelease identifier doesn't allow leading zero + // 1.2.3-1.alpha is valid, + // 1.2.3-01b is valid as well, but + // 1.2.3-01.alpha is not valid + + // Only check for leading zero when digit is the first character of the + // prerelease identifier. + if (result.empty() && is_leading_zero(digit)) { + return failure(token.lexeme); + } + + result.push_back(to_char(digit)); + break; + } + default: + return failure(token.lexeme); + } + } while (_stream.advance_if_match(token, token_type::hyphen) || _stream.advance_if_match(token, token_type::letter) || _stream.advance_if_match(token, token_type::digit)); + + out = result; + return success(_stream.peek().lexeme); + } + + constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { + auto type = detail::prerelease_identifier_type::numeric; + for (char c : identifier) { + if (c == '-' || detail::is_letter(c)) { + type = detail::prerelease_identifier_type::alphanumeric; + break; + } + } + return detail::prerelease_identifier{ type, identifier }; + } + + constexpr from_chars_result parse_build_identifier(string& out) { + string result; + token token = _stream.advance(); + + do { + switch (token.type) { + case token_type::hyphen: + result.push_back('-'); + break; + case token_type::letter: + result.push_back(std::get(token.value)); + break; + case token_type::digit: + { + const auto digit = std::get(token.value); + result.push_back(to_char(digit)); + break; + } + default: + return failure(token.lexeme); + } + } while (_stream.advance_if_match(token, token_type::hyphen) || _stream.advance_if_match(token, token_type::letter) || _stream.advance_if_match(token, token_type::digit)); + + out = result; + return success(_stream.peek().lexeme); + } + + constexpr bool is_leading_zero(int digit) noexcept { + if (digit != 0) { + return false; + } + + size_t k = 0; + int alpha_numerics = 0; + int digits = 0; + + while (true) { + const token token = _stream.peek(k); + + if (!is_alphanumeric(token)) { + break; + } + + ++alpha_numerics; + + if (is_digit(token)) { + ++digits; + } + + ++k; + } + + return digits > 0 && digits == alpha_numerics; + } + + constexpr bool is_digit(const token& token) const noexcept { + return token.type == token_type::digit; + } + + constexpr bool is_eol(const token& token) const noexcept { + return token.type == token_type::eol; + } + + constexpr bool is_alphanumeric(const token& token) const noexcept { + return token.type == token_type::hyphen || token.type == token_type::letter || token.type == token_type::digit; + } + }; + + template + constexpr int compare_prerelease(const version& lhs, const version& rhs) noexcept { + return prerelease_comparator{}.compare(lhs, rhs); + } + + template + constexpr int compare_parsed(const version& lhs, const version& rhs, version_compare_option compare_option) { + int result = lhs.major() - rhs.major(); + if (result != 0) { + return result; + } + + result = lhs.minor() - rhs.minor(); + if (result != 0) { + return result; + } + + result = lhs.patch() - rhs.patch(); + if (result != 0) { + return result; + } + + if (compare_option == version_compare_option::include_prerelease) { + result = detail::compare_prerelease(lhs, rhs); + } + + return result; + } + + template + constexpr from_chars_result parse(std::string_view str, version& out) { + token_stream token_stream; + from_chars_result result = lexer{ str }.scan_tokens(token_stream); + if (!result) { + return result; + } + + result = version_parser{ token_stream }.parse(out); + if (!result) { + return result; + } + + if (!token_stream.consume(token_type::eol)) { + return failure(token_stream.previous().lexeme); + } + + return success(token_stream.previous().lexeme); + } + + } // namespace detail + + template + [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) == 0; + } + + template + [[nodiscard]] constexpr bool operator!=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) != 0; + } + + template + [[nodiscard]] constexpr bool operator>(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) > 0; + } + + template + [[nodiscard]] constexpr bool operator>=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) >= 0; + } + + template + [[nodiscard]] constexpr bool operator<(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) < 0; + } + + template + [[nodiscard]] constexpr bool operator<=(const version& lhs, const version& rhs) noexcept { + return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; + } + + template + [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { + int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); + if (compare == 0) + return std::strong_ordering::equal; + if (compare > 0) + return std::strong_ordering::greater; + return std::strong_ordering::less; + } + + template + constexpr from_chars_result parse(std::string_view str, version& output) { + return detail::parse(str, output); + } + + constexpr bool valid(std::string_view str) { + version v{}; + return detail::parse(str, v); + } + + namespace detail { + template + class range_comparator { + public: + constexpr range_comparator(const version& v, range_operator op) noexcept : _v(v), _op(op) {} + + constexpr bool contains(const version& other) const noexcept { + switch (_op) { + case range_operator::less: + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) < 0; + case range_operator::less_or_equal: + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) <= 0; + case range_operator::greater: + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) > 0; + case range_operator::greater_or_equal: + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) >= 0; + case range_operator::equal: + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) == 0; + } + return false; + } + + constexpr const version& get_version() const noexcept { return _v; } + + constexpr range_operator get_operator() const noexcept { return _op; } + + constexpr string to_string() const { + string result; + switch (_op) { + case range_operator::less: result += "<"; break; + case range_operator::less_or_equal: result += "<="; break; + case range_operator::greater: result += ">"; break; + case range_operator::greater_or_equal: result += ">="; break; + case range_operator::equal: result += "="; break; + } + result += _v.to_string(); + return result; + } + + private: + version _v; + range_operator _op; + }; + + class range_parser; + + template + class range { + public: + friend class detail::range_parser; + + constexpr bool contains(const version& v, version_compare_option option) const noexcept { + if (option == version_compare_option::exclude_prerelease) { + if (!match_at_least_one_comparator_with_prerelease(v)) { + return false; + } + } + + return std::all_of(_ranges_comparators.begin(), _ranges_comparators.end(), [&](const auto& ranges_comparator) { + return ranges_comparator.contains(v); + }); + } + + constexpr auto begin() const noexcept { + return _ranges_comparators.begin(); + } + + constexpr auto end() const noexcept { + return _ranges_comparators.end(); + } + + constexpr std::size_t size() const noexcept { + return _ranges_comparators.size(); + } + + constexpr bool empty() const noexcept { + return _ranges_comparators.empty(); + } + + constexpr string to_string() const { + return join(_ranges_comparators, " "); + } + + private: + vector> _ranges_comparators; + + constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { + if (v.prerelease_tag().empty()) { + return true; + } + + return std::any_of(_ranges_comparators.begin(), _ranges_comparators.end(), [&](const auto& ranges_comparator) { + const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); + const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; + return has_prerelease && equal_without_prerelease; + }); + } + }; + } + + template + class range_set { + public: + friend class detail::range_parser; + + constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { + return std::any_of(_ranges.begin(), _ranges.end(), [&](const auto& range) { + return range.contains(v, option); + }); + } + + constexpr auto begin() const noexcept { + return _ranges.begin(); + } + + constexpr auto end() const noexcept { + return _ranges.end(); + } + + constexpr std::size_t size() const noexcept { + return _ranges.size(); + } + + constexpr bool empty() const noexcept { + return _ranges.empty(); + } + + constexpr string to_string() const { + return join(_ranges, " "); + } + + private: + vector> _ranges; + }; + + namespace detail { + class range_parser { + public: + constexpr explicit range_parser(token_stream stream) noexcept : _stream(std::move(stream)) {} + + template + constexpr from_chars_result parse(range_set& out) noexcept { + vector> ranges; + + do { + + detail::range range; + if (const auto res = parse_range(range); !res) { + return res; + } + + ranges.push_back(range); + skip_whitespaces(); + + } while (_stream.advance_if_match(token_type::logical_or)); + + out._ranges = std::move(ranges); + + return success(_stream.peek().lexeme); + } + + private: + token_stream _stream; + + template + constexpr from_chars_result parse_range(detail::range& out) noexcept { + do { + skip_whitespaces(); + + if (const auto res = parse_range_comparator(out._ranges_comparators); !res) { + return res; + } + + skip_whitespaces(); + + } while (_stream.check(token_type::range_operator) || _stream.check(token_type::digit)); + + return success(_stream.peek().lexeme); + } + + template + constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { + range_operator op = range_operator::equal; + token token; + if (_stream.advance_if_match(token, token_type::range_operator)) { + op = std::get(token.value); + } + + skip_whitespaces(); + + version ver; + version_parser parser{ _stream }; + if (const auto res = parser.parse(ver); !res) { + return res; + } + + out.emplace_back(ver, op); + return success(_stream.peek().lexeme); + } + + constexpr void skip_whitespaces() noexcept { + while (_stream.advance_if_match(token_type::space)) { + ; + } + } + }; + } // namespace detail + + + template + constexpr from_chars_result parse(std::string_view str, range_set& out) { + detail::token_stream token_stream; + const from_chars_result result = detail::lexer{ str }.scan_tokens(token_stream); + if (!result) { + return result; + } + + return detail::range_parser{ std::move(token_stream) }.parse(out); + } +} // namespace plg #ifndef PLUGIFY_VECTOR_NO_STD_HASH // hash support @@ -1078,7 +1057,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); @@ -1089,7 +1068,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); @@ -1100,7 +1079,7 @@ namespace std { return std::format_to(ctx.out(), "{}", ver.to_string()); } }; - template + template struct formatter> { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); diff --git a/test/cross_call_master/CMakeLists.txt b/test/cross_call_master/CMakeLists.txt index 6b45aae..c6ca410 100644 --- a/test/cross_call_master/CMakeLists.txt +++ b/test/cross_call_master/CMakeLists.txt @@ -42,8 +42,10 @@ else() endif() if(LINUX) - target_compile_definitions(${PROJECT_NAME} PRIVATE _GLIBCXX_USE_CXX11_ABI=0) + target_compile_definitions(${PROJECT_NAME} PRIVATE _GLIBCXX_USE_CXX11_ABI=1) target_link_libraries(${PROJECT_NAME} PRIVATE -static-libstdc++ -static-libgcc) + #target_compile_options(${PROJECT_NAME} PRIVATE $<$: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) + #target_link_libraries(${PROJECT_NAME} PRIVATE $<$: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) endif() include(GenerateExportHeader) diff --git a/test/cross_call_master/external/plugify/include/plg/allocator.hpp b/test/cross_call_master/external/plugify/include/plg/allocator.hpp index 3c01cd5..3cc57b2 100644 --- a/test/cross_call_master/external/plugify/include/plg/allocator.hpp +++ b/test/cross_call_master/external/plugify/include/plg/allocator.hpp @@ -1,85 +1,59 @@ #pragma once -#include // for std::size_t, std::ptrdiff_t -#include // for std::malloc, std::free, std::aligned_alloc -#include // for std::is_constant_evaluated -#include // for ::operator new, ::operator delete +#include // for std::size_t, std::ptrdiff_t +#include // for std::malloc, std::free, std::aligned_alloc +#include // for ::operator new, ::operator delete +#include // for std::is_constant_evaluated -#include "plg/macro.hpp" +#include "plg/config.hpp" namespace plg { - // Forward declaration for allocator template class allocator; - // Specialization for `void`, but we no longer need to define `pointer` and `const_pointer` template<> class allocator { public: using value_type = void; - // Rebind struct template struct rebind { using other = allocator; }; }; - // Define the custom allocator inheriting from std::allocator template class allocator { + static_assert(!std::is_const_v, "plg::allocator does not support const types"); + static_assert(!std::is_volatile_v, "plg::allocator does not support volatile types"); public: using value_type = T; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - // Default constructor constexpr allocator() noexcept = default; - // Copy constructor template constexpr allocator(const allocator&) noexcept {} - // Rebind struct template struct rebind { using other = allocator; }; - // Override allocate method to use custom allocation function - constexpr pointer allocate(size_type n, [[maybe_unused]] const_pointer hint = nullptr) { + [[nodiscard]] constexpr T* allocate(size_type n) { static_assert(sizeof(T) != 0, "cannot allocate incomplete types"); static_assert((alignof(T) & (alignof(T) - 1)) == 0, "alignof(T) must be a power of 2"); - if (n > max_size()) [[unlikely]] { - if (n > static_cast(-1) / sizeof(T)) { - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): bad array new length", std::bad_array_new_length); - } - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): too big", std::bad_alloc); + if (n > std::allocator_traits::max_size(*this)) { + throw_bad_array_new_length(); } - pointer ret; size_type size = n * sizeof(T); if (std::is_constant_evaluated()) { - ret = static_cast(::operator new(size)); + return static_cast(::operator new(size)); } else { - if constexpr (alignof(T) > alignof(std::max_align_t)) { - size_type aligned_size = (size + (alignof(T) - 1)) & ~(alignof(T) - 1); - ret = static_cast(aligned_allocate(alignof(T), aligned_size)); - } else { - ret = static_cast(std::malloc(size)); - } - - if (!ret) { - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): bad allocation", std::bad_alloc); - } + return malloc_allocate(size); } - - return ret; } - // Override deallocate method to use custom deallocation function - constexpr void deallocate(pointer p, [[maybe_unused]] size_type n) { + constexpr void deallocate(T* p, [[maybe_unused]] size_type n) { if (std::is_constant_evaluated()) { ::operator delete(p); } else { @@ -88,28 +62,114 @@ namespace plg { } private: - constexpr size_type max_size() noexcept { -#if __PTRDIFF_MAX__ < __SIZE_MAX__ - return static_cast(__PTRDIFF_MAX__) / sizeof(T); -#else - return static_cast(-1) / sizeof(T); -#endif // __PTRDIFF_MAX__ + static T* malloc_allocate(size_type size) { + T* ret; + if constexpr (alignof(T) > alignof(std::max_align_t)) { + size_type aligned_size = (size + (alignof(T) - 1)) & ~(alignof(T) - 1); + ret = static_cast(aligned_allocate(alignof(T), aligned_size)); + } else { + ret = static_cast(std::malloc(size)); + } + if (!ret) { + throw_bad_alloc(); + } + return ret; + } + + [[noreturn]] static void throw_bad_array_new_length() { + PLUGIFY_THROW("bad array new length", std::bad_array_new_length); } - void* aligned_allocate(size_type alignment, size_type size) { -#if _WIN32 + [[noreturn]] static void throw_bad_alloc() { + PLUGIFY_THROW("bad allocation", std::bad_alloc); + } + + static void* aligned_allocate(size_type alignment, size_type size) { +#if PLUGIFY_PLATFORM_WINDOWS return _aligned_malloc(size, alignment); #else return std::aligned_alloc(alignment, size); -#endif // _WIN32 +#endif // PLUGIFY_PLATFORM_WINDOWS } }; - // Comparison operators for compatibility template constexpr bool operator==(const allocator&, const allocator) { return true; } template constexpr bool operator!=(const allocator&, const allocator) { return false; } + template + void swap_allocator(Alloc& a1, Alloc& a2, std::true_type) { + using std::swap; + swap(a1, a2); + } + + template + void swap_allocator(Alloc&, Alloc&, std::false_type) noexcept {} + + template + void swap_allocator(Alloc& a1, Alloc& a2) { + swap_allocator(a1, a2, std::integral_constant::propagate_on_container_swap::value>()); + } + + template + struct allocation_result { + Pointer ptr; + Size count; + }; + + template + [[nodiscard]] allocation_result::pointer> + allocate_at_least(Alloc& alloc, size_t n) { + return { alloc.allocate(n), n }; + } + + template + constexpr bool is_pointer_in_range(const T* begin, const T* end, const U* ptr) { + if (std::is_constant_evaluated()) + return false; + return reinterpret_cast(begin) <= reinterpret_cast(ptr) && + reinterpret_cast(ptr) < reinterpret_cast(end); + } + + template + constexpr bool is_overlapping_range(const T* begin, const T* end, const U* begin2) { + auto size = end - begin; + auto end2 = begin2 + size; + return is_pointer_in_range(begin, end, begin2) || is_pointer_in_range(begin2, end2, begin); + } + + // asan_annotate_container_with_allocator determines whether containers with custom allocators are annotated. This is + // a public customization point to disable annotations if the custom allocator assumes that the memory isn't poisoned. + // See the https://libcxx.llvm.org/UsingLibcxx.html#turning-off-asan-annotation-in-containers for more information. +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + template + struct asan_annotate_container_with_allocator : std::true_type {}; +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + + // Annotate a contiguous range. + // [__first_storage, __last_storage) is the allocated memory region, + // __old_last_contained is the previously last allowed (unpoisoned) element, and + // __new_last_contained is the new last allowed (unpoisoned) element. + template + void annotate_contiguous_container( + [[maybe_unused]] const void* first_storage, + [[maybe_unused]] const void* last_storage, + [[maybe_unused]] const void* old_last_contained, + [[maybe_unused]] const void* new_last_contained + ) { +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + if (!std::is_constant_evaluated() + && asan_annotate_container_with_allocator::value + && first_storage != nullptr) { + __sanitizer_annotate_contiguous_container( + first_storage, + last_storage, + old_last_contained, + new_last_contained + ); + } +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + } } // namespace plg diff --git a/test/cross_call_master/external/plugify/include/plg/concepts.hpp b/test/cross_call_master/external/plugify/include/plg/concepts.hpp new file mode 100644 index 0000000..398018b --- /dev/null +++ b/test/cross_call_master/external/plugify/include/plg/concepts.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include +#include + +#if PLUGIFY_HAS_CXX23 +# include +#endif + +namespace plg { +#if PLUGIFY_HAS_CXX23 + template + concept container_compatible_range = std::ranges::input_range && std::convertible_to, Type>; +#endif + + template + concept is_allocator = + // basic nested types (via allocator_traits) + requires { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::void_pointer; + typename std::allocator_traits::const_void_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; + } && + // required expressions / member calls (use allocator_traits helpers where appropriate) + requires( + Alloc& a, + typename std::allocator_traits::size_type n, + typename std::allocator_traits::pointer p, + typename std::allocator_traits::value_type& v, + const typename std::allocator_traits::value_type& cv + ) { + // allocation / deallocation + { a.allocate(n) } -> std::same_as::pointer>; + { a.deallocate(p, n) } -> std::same_as; + + // max_size: prefer allocator_traits::max_size (calls member or fallback) + { std::allocator_traits::max_size(a) } -> std::convertible_to::size_type>; + + // construct / destroy (via allocator_traits helpers; these must be well-formed) + { std::allocator_traits::construct(a, p, cv) } -> std::same_as; + { std::allocator_traits::destroy(a, p) } -> std::same_as; + + // optional helpful factory used by containers when copying them + { std::allocator_traits::select_on_container_copy_construction(a) } -> std::convertible_to; + }; + + template + concept is_char_traits = requires { + // Required type definitions + typename Traits::char_type; + typename Traits::int_type; + typename Traits::off_type; + typename Traits::pos_type; + typename Traits::state_type; + } && requires( + typename Traits::char_type c1, + typename Traits::char_type c2, + typename Traits::char_type& cr, + const typename Traits::char_type& ccr, + typename Traits::char_type* p, + const typename Traits::char_type* cp, + typename Traits::int_type i1, + typename Traits::int_type i2, + std::size_t n + ) { + // Character operations + { Traits::assign(cr, ccr) } -> std::same_as; + { Traits::eq(ccr, ccr) } -> std::convertible_to; + { Traits::lt(ccr, ccr) } -> std::convertible_to; + + // String operations + { Traits::compare(cp, cp, n) } -> std::convertible_to; + { Traits::length(cp) } -> std::convertible_to; + { Traits::find(cp, n, ccr) } -> std::convertible_to; + + // Memory operations + { Traits::move(p, cp, n) } -> std::same_as; + { Traits::copy(p, cp, n) } -> std::same_as; + { Traits::assign(p, n, c1) } -> std::same_as; + + // int_type operations + { Traits::not_eof(i1) } -> std::same_as; + { Traits::to_char_type(i1) } -> std::same_as; + { Traits::to_int_type(c1) } -> std::same_as; + { Traits::eq_int_type(i1, i2) } -> std::convertible_to; + { Traits::eof() } -> std::same_as; + }; + + // A type is trivially relocatable if a move construct + destroy of the original object is equivalent to + // `memcpy(dst, src, sizeof(T))`. + // + // Note that we don't use the __cpp_lib_trivially_relocatable Clang builtin right now because it does not + // implement the semantics of any current or future trivial relocation proposal and it can lead to + // incorrect optimizations on some platforms (Windows) and supported compilers (AppleClang). +#if __has_builtin(__cpp_lib_trivially_relocatable) + template + struct is_trivially_relocatable : std::integral_constant {}; +#else + template + struct is_trivially_relocatable : std::is_trivially_copyable {}; +#endif + + template requires(std::is_same_v) + struct is_trivially_relocatable : std::true_type {}; +} diff --git a/include/plg/macro.hpp b/test/cross_call_master/external/plugify/include/plg/config.hpp similarity index 75% rename from include/plg/macro.hpp rename to test/cross_call_master/external/plugify/include/plg/config.hpp index a072fec..05db47f 100644 --- a/include/plg/macro.hpp +++ b/test/cross_call_master/external/plugify/include/plg/config.hpp @@ -16,57 +16,47 @@ # define __has_builtin(x) 0 #endif -#include - -#define PLUGIFY_HAS_EXCEPTIONS (__cpp_exceptions || __EXCEPTIONS || _HAS_EXCEPTIONS) - -#ifndef PLUGIFY_EXCEPTIONS -# if PLUGIFY_HAS_EXCEPTIONS -# define PLUGIFY_EXCEPTIONS 1 -# else -# define PLUGIFY_EXCEPTIONS 0 -# endif -#endif - -#if PLUGIFY_EXCEPTIONS && (!PLUGIFY_HAS_EXCEPTIONS || !__has_include()) -# undef PLUGIFY_EXCEPTIONS -# define PLUGIFY_EXCEPTIONS 0 -#endif - -#ifndef PLUGIFY_FALLBACK_ASSERT -# define PLUGIFY_FALLBACK_ASSERT 1 +#ifndef __builtin_constant_p +# define __builtin_constant_p(x) std::is_constant_evaluated() #endif -#if PLUGIFY_FALLBACK_ASSERT && !__has_include() -# undef PLUGIFY_FALLBACK_ASSERT -# define PLUGIFY_FALLBACK_ASSERT 0 +#if __has_include() +# include #endif -#ifndef PLUGIFY_FALLBACK_ABORT -# define PLUGIFY_FALLBACK_ABORT 1 -#endif - -#if PLUGIFY_FALLBACK_ABORT && !__has_include() -# undef PLUGIFY_FALLBACK_ABORT -# define PLUGIFY_FALLBACK_ABORT 0 -#endif - -#ifndef PLUGIFY_FALLBACK_ABORT_FUNCTION -# define PLUGIFY_FALLBACK_ABORT_FUNCTION [] (auto) { } +#if __has_include() +# include +# define PLUGIFY_ASSERT(cond, mesg) assert((cond) && (mesg)) #endif -#if PLUGIFY_EXCEPTIONS +#define PLUGIFY_HAS_EXCEPTIONS __cpp_exceptions || _CPPUNWIND || __EXCEPTIONS +#if PLUGIFY_HAS_EXCEPTIONS # include # include -# define PLUGIFY_ASSERT(x, str, e) do { if (!(x)) [[unlikely]] plugify_throw(str); } while (0) -#elif PLUGIFY_FALLBACK_ASSERT -# include -# define PLUGIFY_ASSERT(x, str, ...) assert((x) && (str)) -#elif PLUGIFY_FALLBACK_ABORT +namespace plg { + template + [[noreturn]] constexpr void throw_exception(const char* msg, Args...args) { + if constexpr (std::is_constructible_v) { + throw E(msg); + } else { + throw E(std::forward(args)...); + } + } +} // namespace plg +# define PLUGIFY_THROW(str, exp, ...) ::plg::throw_exception(str, ##__VA_ARGS__); +#else # include -# define PLUGIFY_ASSERT(x, ...) do { if (!(x)) [[unlikely]] { std::abort(); } } while (0) +# include +# define PLUGIFY_THROW(str, ...) \ + std::fputs(str "\n", stderr); \ + std::abort(); +#endif + +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define PLUGIFY_INSTRUMENTED_WITH_ASAN 1 +# include #else -# define PLUGIFY_ASSERT(x, str, ...) do { if (!(x)) [[unlikely]] { PLUGIFY_FALLBACK_ABORT_FUNCTION (str); { while (true) { [] { } (); } } } } while (0) +# define PLUGIFY_INSTRUMENTED_WITH_ASAN 0 #endif # define PLUGIFY_COMPILER_MAKE_VERSION2(version, sp) ((version) * 100 + (sp)) @@ -258,12 +248,24 @@ #elif PLUGIFY_COMPILER_MSVC # pragma warning(error: 4714) # define PLUGIFY_FORCE_INLINE [[msvc::forceinline]] -# define PLUGIFY_NOINLINE __declspec(noinline) +# define PLUGIFY_NOINLINE [[msvc::noinline]] #else # define PLUGIFY_FORCE_INLINE inline # define PLUGIFY_NOINLINE #endif +#if __has_feature(nullability) +# define PLUGIFY_NO_NULL _Nonnull +#else +# define PLUGIFY_NO_NULL +#endif + +#if __has_cpp_attribute(__no_sanitize__) +# define PLUGIFY_NO_CFI __attribute__((__no_sanitize__("cfi"))) +#else +# define PLUGIFY_NO_CFI +#endif + #if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG # define PLUGIFY_RESTRICT __restrict__ #elif PLUGIFY_COMPILER_MSVC @@ -272,13 +274,68 @@ # define PLUGIFY_RESTRICT #endif -#if PLUGIFY_EXCEPTIONS -template -[[noreturn]] PLUGIFY_FORCE_INLINE constexpr void plugify_throw(const char* msg) { - if constexpr (std::is_constructible_v) { - throw E(msg); - } else { - throw E(); - } -} -#endif \ No newline at end of file +#ifndef PLUGIFY_PLATFORM_WINDOWS +# if defined(_WIN32) || defined(_WIN64) +# define PLUGIFY_PLATFORM_WINDOWS 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_APPLE +# if defined(__APPLE__) && defined(__MACH__) +# define PLUGIFY_PLATFORM_APPLE 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_LINUX +# if defined(__linux__) +# define PLUGIFY_PLATFORM_LINUX 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_ANDROID +# if defined(__ANDROID__) +# define PLUGIFY_PLATFORM_ANDROID 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_ORBIS +# if defined(__ORBIS__) +# define PLUGIFY_PLATFORM_ORBIS 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_PROSPERO +# if defined(__PROSPERO__) +# define PLUGIFY_PLATFORM_PROSPERO 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_SWITCH +# if defined(__NX__) +# define PLUGIFY_PLATFORM_SWITCH 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_BSD +# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +# define PLUGIFY_PLATFORM_BSD 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_UNIX +# if defined(__unix__) || defined(__unix) || defined(unix) || defined(__APPLE__) +# define PLUGIFY_PLATFORM_UNIX 1 +# endif +#endif + +#if !defined(PLUGIFY_PLATFORM_WINDOWS) && \ + !defined(PLUGIFY_PLATFORM_APPLE) && \ + !defined(PLUGIFY_PLATFORM_LINUX) && \ + !defined(PLUGIFY_PLATFORM_ANDROID) && \ + !defined(PLUGIFY_PLATFORM_ORBIS) && \ + !defined(PLUGIFY_PLATFORM_PROSPERO)&& \ + !defined(PLUGIFY_PLATFORM_SWITCH) && \ + !defined(PLUGIFY_PLATFORM_BSD) && \ + !defined(PLUGIFY_PLATFORM_UNIX) +# error "Unsupported platform! Please extend macro.hpp" +#endif diff --git a/test/cross_call_master/external/plugify/include/plg/debugging.hpp b/test/cross_call_master/external/plugify/include/plg/debugging.hpp index b52ec8c..0326fe7 100644 --- a/test/cross_call_master/external/plugify/include/plg/debugging.hpp +++ b/test/cross_call_master/external/plugify/include/plg/debugging.hpp @@ -1,13 +1,19 @@ #pragma once -#include "plg/macro.hpp" - -#ifdef __cpp_lib_debugging +#include "plg/config.hpp" +#if __has_include() #include +#if defined(__cpp_lib_debugging) && __cpp_lib_debugging >= 202403L +#define PLUGIFY_HAS_STD_DEBUGGING 1 +#else +#define PLUGIFY_HAS_STD_DEBUGGING 0 +#endif +#else +#define PLUGIFY_HAS_STD_DEBUGGING 0 +#endif -#else //def __cpp_lib_debugging - +#if !PLUGIFY_HAS_STD_DEBUGGING #if PLUGIFY_PLATFORM_WINDOWS #include #include @@ -25,16 +31,7 @@ #include #endif -#endif //def __cpp_lib_debugging - namespace plg { -#ifdef __cpp_lib_debugging - - using std::breakpoint; - using std::breakpoint_if_debugging; - using std::is_debugger_present; - -#else //def __cpp_lib_debugging #if PLUGIFY_PLATFORM_WINDOWS @@ -178,7 +175,7 @@ namespace plg { } // namespace debugging } // namespace detail - PLUGIFY_NOINLINE inline bool is_debugger_present() noexcept { + inline bool is_debugger_present() noexcept { return plg::detail::debugging::parse_proc_status(); } @@ -190,7 +187,7 @@ namespace plg { #endif - PLUGIFY_FORCE_INLINE void breakpoint() noexcept { + inline void breakpoint() noexcept { #if PLUGIFY_COMPILER_MSVC __debugbreak(); #elif PLUGIFY_COMPILER_CLANG @@ -202,11 +199,17 @@ namespace plg { #endif } - PLUGIFY_FORCE_INLINE void breakpoint_if_debugging() noexcept { + inline void breakpoint_if_debugging() noexcept { if (plg::is_debugger_present()) { plg::breakpoint(); } } - -#endif //def __cpp_lib_debugging } // namespace plg + +namespace std { + using plg::breakpoint; + using plg::breakpoint_if_debugging; + using plg::is_debugger_present; +} // namespace std + +#endif // !PLUGIFY_HAS_STD_DEBUGGING diff --git a/test/cross_call_master/external/plugify/include/plg/enum.hpp b/test/cross_call_master/external/plugify/include/plg/enum.hpp index f8780e1..802b7c1 100644 --- a/test/cross_call_master/external/plugify/include/plg/enum.hpp +++ b/test/cross_call_master/external/plugify/include/plg/enum.hpp @@ -6,7 +6,7 @@ #include #include -#include "plg/macro.hpp" +#include "plg/config.hpp" // from // https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ @@ -17,15 +17,15 @@ namespace plg { template struct static_string { constexpr static_string(std::string_view sv) noexcept { - std::copy(sv.begin(), sv.end(), content.begin()); + std::copy(sv.begin(), sv.end(), _content.begin()); } constexpr operator std::string_view() const noexcept { - return { content.data(), N }; + return { _content.data(), N }; } private: - std::array content{}; + std::array _content{}; }; constexpr auto is_pretty(char ch) noexcept { diff --git a/test/cross_call_master/external/plugify/include/plg/expected.hpp b/test/cross_call_master/external/plugify/include/plg/expected.hpp index d6bc137..f35fea5 100644 --- a/test/cross_call_master/external/plugify/include/plg/expected.hpp +++ b/test/cross_call_master/external/plugify/include/plg/expected.hpp @@ -1,14 +1,19 @@ #pragma once -#include "plg/macro.hpp" +#include "plg/config.hpp" -#ifdef __cpp_lib_expected +#if __has_include() #include -namespace plg { - using std::expected; - using std::unexpected; -} +#if defined(__cpp_lib_expected) && __cpp_lib_expected >= 202202L +#define PLUGIFY_HAS_STD_EXPECTED 1 +#else +#define PLUGIFY_HAS_STD_EXPECTED 0 +#endif #else +#define PLUGIFY_HAS_STD_EXPECTED 0 +#endif + +#if !PLUGIFY_HAS_STD_EXPECTED #include #include #include @@ -524,27 +529,39 @@ namespace plg { // precondition: has_value() = true constexpr auto operator->() const noexcept -> T const* { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::addressof(this->val); } // precondition: has_value() = true constexpr auto operator->() noexcept -> T* { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::addressof(this->val); } // precondition: has_value() = true - constexpr auto operator*() const& noexcept -> T const& { return this->val; } + constexpr auto operator*() const& noexcept -> T const& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return this->val; + } // precondition: has_value() = true - constexpr auto operator*() & noexcept -> T& { return this->val; } + constexpr auto operator*() & noexcept -> T& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return this->val; + } // precondition: has_value() = true constexpr auto operator*() const&& noexcept -> T const&& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::move(this->val); } // precondition: has_value() = true - constexpr auto operator*() && noexcept -> T&& { return std::move(this->val); } + constexpr auto operator*() && noexcept -> T&& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return std::move(this->val); + } constexpr explicit operator bool() const noexcept { return has_val; } @@ -553,44 +570,56 @@ namespace plg { } constexpr auto value() const& -> T const& { - if (has_value()) { - return this->val; + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } - throw bad_expected_access(error()); + return this->val; } constexpr auto value() & -> T& { - if (has_value()) { - return this->val; + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } - throw bad_expected_access(error()); + return this->val; } constexpr auto value() const&& -> T const&& { - if (has_value()) { - return std::move(this->val); + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } - throw bad_expected_access(std::move(error())); + return std::move(this->val); } constexpr auto value() && -> T&& { - if (has_value()) { - return std::move(this->val); + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } - throw bad_expected_access(std::move(error())); + return std::move(this->val); } // precondition: has_value() = false - constexpr auto error() const& -> E const& { return this->unex; } + constexpr auto error() const& -> E const& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() & -> E& { return this->unex; } + constexpr auto error() & -> E& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() const&& -> E const&& { return std::move(this->unex); } + constexpr auto error() const&& -> E const&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // precondition: has_value() = false - constexpr auto error() && -> E&& { return std::move(this->unex); } + constexpr auto error() && -> E&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } template requires std::is_copy_constructible_v && std::is_convertible_v @@ -1126,27 +1155,39 @@ namespace plg { constexpr void value() const& { if (!has_value()) { - throw bad_expected_access(error()); + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } } constexpr void value() && { if (!has_value()) { - throw bad_expected_access(std::move(error())); + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } } // precondition: has_value() = false - constexpr auto error() const& -> E const& { return this->unex; } + constexpr auto error() const& -> E const& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() & -> E& { return this->unex; } + constexpr auto error() & -> E& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() const&& -> E const&& { return std::move(this->unex); } + constexpr auto error() const&& -> E const&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // precondition: has_value() = false - constexpr auto error() && -> E&& { return std::move(this->unex); } + constexpr auto error() && -> E&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // monadic template>> @@ -1426,5 +1467,27 @@ namespace plg { }; }; -}// namespace plg -#endif \ No newline at end of file +} // namespace plg + +namespace std { + template + using expected = plg::expected; + + template + concept is_expected = std::same_as, expected >; + +#if PLUGIFY_COMPILER_CLANG + template + struct unexpected : public plg::unexpected { + using plg::unexpected::unexpected; + }; + template + unexpected(U) -> unexpected; +#else + template + using unexpected = plg::unexpected; +#endif + +} // namespace std + +#endif // !PLUGIFY_HAS_STD_EXPECTED \ No newline at end of file diff --git a/test/cross_call_master/external/plugify/include/plg/flat_map.hpp b/test/cross_call_master/external/plugify/include/plg/flat_map.hpp deleted file mode 100644 index 7b5f7b7..0000000 --- a/test/cross_call_master/external/plugify/include/plg/flat_map.hpp +++ /dev/null @@ -1,780 +0,0 @@ -#pragma once - -#include "plg/macro.hpp" - -#ifdef __cpp_lib_flat_map -#include -namespace plg { - template> - using flat_map = std::flat_map; -} -#else -#include "plg/vector.hpp" - -namespace plg { - namespace detail { - template < typename T, typename U, typename = void > - struct is_transparent - : std::false_type {}; - - template < typename T, typename U > - struct is_transparent> - : std::true_type {}; - - template < typename T, typename U > - inline constexpr bool is_transparent_v = is_transparent::value; - - template - constexpr bool is_sorted(Iter first, Iter last, Compare comp) { - if (first != last) { - Iter next = first; - while (++next != last) { - if (comp(*next, *first)) { - return false; - } - ++first; - } - } - return true; - } - - template - constexpr bool is_sorted_unique(Iter first, Iter last, Compare comp) { - if (first != last) { - Iter next = first; - while (++next != last) { - if (!comp(*first, *next)) { - return false; - } - ++first; - } - } - return true; - } - - template - struct pair_compare : public Compare { - pair_compare() = default; - - explicit pair_compare(const Compare& compare) - : Compare(compare) {} - - bool operator()( - const typename Pair::first_type& l, - const typename Pair::first_type& r) const { - return Compare::operator()(l, r); - } - - bool operator()(const Pair& l, const Pair& r) const { - return Compare::operator()(l.first, r.first); - } - - bool operator()( - const typename Pair::first_type& l, - const Pair& r) const { - return Compare::operator()(l, r.first); - } - - bool operator()( - const Pair& l, - const typename Pair::first_type& r) const { - return Compare::operator()(l.first, r); - } - - template - requires (is_transparent_v) - bool operator()(const K& l, const Pair& r) const { - return Compare::operator()(l, r.first); - } - - template - requires (is_transparent_v) - bool operator()(const Pair& l, const K& r) const { - return Compare::operator()(l.first, r); - } - }; - - template - struct eq_compare : public Compare { - eq_compare() = default; - - explicit eq_compare(const Compare& compare) - : Compare(compare) {} - - template - bool operator()(const L& l, const R& r) const { - return !Compare::operator()(l, r) && !Compare::operator()(r, l); - } - }; - } // namespace detail - - struct sorted_range_t {}; - inline constexpr sorted_range_t sorted_range = sorted_range_t(); - - struct sorted_unique_range_t : public sorted_range_t {}; - inline constexpr sorted_unique_range_t sorted_unique_range = sorted_unique_range_t(); - - template, typename Container = std::vector>> - class flat_map { - public: - using key_type = Key; - using mapped_type = Value; - using value_type = typename Container::value_type; - - using size_type = typename Container::size_type; - using difference_type = typename Container::difference_type; - - using key_compare = Compare; - using container_type = Container; - - using reference = typename Container::reference; - using const_reference = typename Container::const_reference; - using pointer = typename Container::pointer; - using const_pointer = typename Container::const_pointer; - - using iterator = typename Container::iterator; - using const_iterator = typename Container::const_iterator; - using reverse_iterator = typename Container::reverse_iterator; - using const_reverse_iterator = typename Container::const_reverse_iterator; - - struct value_compare : private key_compare { - value_compare() = default; - - explicit value_compare(key_compare compare) - : key_compare(std::move(compare)) {} - - bool operator()(const value_type& l, const value_type& r) const { - return key_compare::operator()(l.first, r.first); - } - }; - - public: - flat_map() = default; - ~flat_map() = default; - - explicit flat_map(const Compare& c) - : _compare(c) {} - - template - explicit flat_map(const Allocator& a) - : _data(a) {} - - template - flat_map(const Compare& c, const Allocator& a) - : _compare(c), _data(a) {} - - template - flat_map(Iterator first, Iterator last) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_unique_range, first, last); - } - - flat_map(std::initializer_list list) { - from_range(list.begin(), list.end()); - } - - flat_map(sorted_range_t, std::initializer_list list) { - from_range(sorted_range, list.begin(), list.end()); - } - - flat_map(sorted_unique_range_t, std::initializer_list list) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - flat_map(std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(list.begin(), list.end()); - } - - flat_map(sorted_range_t, std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(sorted_range, list.begin(), list.end()); - } - - flat_map(sorted_unique_range_t, std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(list.begin(), list.end()); - } - - template - flat_map(sorted_range_t, std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(sorted_range, list.begin(), list.end()); - } - - template - flat_map(sorted_unique_range_t, std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(list.begin(), list.end()); - } - - template - flat_map(sorted_range_t, std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_range, list.begin(), list.end()); - } - - template - flat_map(sorted_unique_range_t, std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(flat_map&& other, const Allocator& a) - : _compare(std::move(other._compare)), _data(std::move(other._data), a) {} - - template - flat_map(const flat_map& other, const Allocator& a) - : _compare(other._compare), _data(other._data, a) {} - - flat_map(flat_map&& other) noexcept = default; - flat_map(const flat_map& other) = default; - - flat_map& operator=(flat_map&& other) noexcept = default; - flat_map& operator=(const flat_map& other) = default; - - flat_map& operator=(std::initializer_list list) { - flat_map(list).swap(*this); - return *this; - } - - iterator begin() noexcept(noexcept(std::declval().begin())) { - return _data.begin(); - } - - const_iterator begin() const - noexcept(noexcept(std::declval().begin())) { - return _data.begin(); - } - - const_iterator cbegin() const - noexcept(noexcept(std::declval().cbegin())) { - return _data.cbegin(); - } - - iterator end() noexcept(noexcept(std::declval().end())) { - return _data.end(); - } - - const_iterator end() const - noexcept(noexcept(std::declval().end())) { - return _data.end(); - } - - const_iterator cend() const - noexcept(noexcept(std::declval().cend())) { - return _data.cend(); - } - - reverse_iterator rbegin() noexcept(noexcept(std::declval().rbegin())) { - return _data.rbegin(); - } - - const_reverse_iterator rbegin() const - noexcept(noexcept(std::declval().rbegin())) { - return _data.rbegin(); - } - - const_reverse_iterator crbegin() const - noexcept(noexcept(std::declval().crbegin())) { - return _data.crbegin(); - } - - reverse_iterator rend() noexcept(noexcept(std::declval().rend())) { - return _data.rend(); - } - - const_reverse_iterator rend() const - noexcept(noexcept(std::declval().rend())) { - return _data.rend(); - } - - const_reverse_iterator crend() const - noexcept(noexcept(std::declval().crend())) { - return _data.crend(); - } - - bool empty() const - noexcept(noexcept(std::declval().empty())) { - return _data.empty(); - } - - size_type size() const - noexcept(noexcept(std::declval().size())) { - return _data.size(); - } - - size_type max_size() const - noexcept(noexcept(std::declval().max_size())) { - return _data.max_size(); - } - - size_type capacity() const - noexcept(noexcept(std::declval().capacity())) { - return _data.capacity(); - } - - void reserve(size_type capacity) { - _data.reserve(capacity); - } - - void shrink_to_fit() { - _data.shrink_to_fit(); - } - - mapped_type& operator[](key_type&& key) { - const iterator iter = find(key); - return iter != end() - ? iter->second - : emplace(std::move(key), mapped_type()).first->second; - } - - mapped_type& operator[](const key_type& key) { - const iterator iter = find(key); - return iter != end() - ? iter->second - : emplace(key, mapped_type()).first->second; - } - - mapped_type& at(const key_type& key) { - const iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - const mapped_type& at(const key_type& key) const { - const const_iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - template - requires (detail::is_transparent_v) - mapped_type& at(const K& key) { - const iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - template - requires (detail::is_transparent_v) - const mapped_type& at(const K& key) const { - const const_iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - std::pair insert(value_type&& value) { - const iterator iter = lower_bound(value.first); - return iter == end() || _compare(value, *iter) - ? std::make_pair(_data.insert(iter, std::move(value)), true) - : std::make_pair(iter, false); - } - - std::pair insert(const value_type& value) { - const iterator iter = lower_bound(value.first); - return iter == end() || _compare(value, *iter) - ? std::make_pair(_data.insert(iter, value), true) - : std::make_pair(iter, false); - } - - iterator insert(const_iterator hint, value_type&& value) { - return (hint == begin() || _compare(*(hint - 1), value)) && (hint == end() || _compare(value, *hint)) - ? _data.insert(hint, std::move(value)) - : insert(std::move(value)).first; - } - - iterator insert(const_iterator hint, const value_type& value) { - return (hint == begin() || _compare(*(hint - 1), value)) && (hint == end() || _compare(value, *hint)) - ? _data.insert(hint, value) - : insert(value).first; - } - - template - std::pair insert_or_assign(key_type&& key, V&& value) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, std::move(key), std::forward(value)); - return {iter, true}; - } - (*iter).second = std::forward(value); - return {iter, false}; - } - - template - std::pair insert_or_assign(const key_type& key, V&& value) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, key, std::forward(value)); - return {iter, true}; - } - (*iter).second = std::forward(value); - return {iter, false}; - } - - template - void insert(Iterator first, Iterator last) { - insert_range(first, last); - } - - template - void insert(sorted_range_t, Iterator first, Iterator last) { - insert_range(sorted_range, first, last); - } - - void insert(std::initializer_list list) { - insert_range(list.begin(), list.end()); - } - - void insert(sorted_range_t, std::initializer_list list) { - insert_range(sorted_range, list.begin(), list.end()); - } - - template - std::pair emplace(Args&&... args) { - return insert(value_type(std::forward(args)...)); - } - - template - iterator emplace_hint(const_iterator hint, Args&&... args) { - return insert(hint, value_type(std::forward(args)...)); - } - - template - std::pair try_emplace(key_type&& key, Args&&... args) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, std::move(key), std::forward(args)...); - return {iter, true}; - } - return {iter, false}; - } - - template - std::pair try_emplace(const key_type& key, Args&&... args) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, key, std::forward(args)...); - return {iter, true}; - } - return {iter, false}; - } - - void clear() noexcept(noexcept(std::declval().clear())) { - _data.clear(); - } - - iterator erase(const_iterator iter) { - return _data.erase(iter); - } - - iterator erase(const_iterator first, const_iterator last) { - return _data.erase(first, last); - } - - size_type erase(const key_type& key) { - const const_iterator iter = find(key); - return iter != end() - ? (erase(iter), 1) - : 0; - } - - void swap(flat_map& other) noexcept(std::is_nothrow_swappable_v && std::is_nothrow_swappable_v) { - using std::swap; - swap(_compare, other._compare); - swap(_data, other._data); - } - - size_type count(const key_type& key) const { - const const_iterator iter = find(key); - return iter != end() ? 1 : 0; - } - - template - requires (detail::is_transparent_v) - size_type count(const K& key) const { - const const_iterator iter = find(key); - return iter != end() ? 1 : 0; - } - - iterator find(const key_type& key) { - const iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - const_iterator find(const key_type& key) const { - const const_iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - template - requires (detail::is_transparent_v) - iterator find(const K& key) { - const iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - template - requires (detail::is_transparent_v) - const_iterator find(const K& key) const { - const const_iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - bool contains(const key_type& key) const { - return find(key) != end(); - } - - template - requires (detail::is_transparent_v) - bool contains(const K& key) const { - return find(key) != end(); - } - - std::pair equal_range(const key_type& key) { - return std::equal_range(begin(), end(), key, _compare); - } - - std::pair equal_range(const key_type& key) const { - return std::equal_range(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - std::pair equal_range(const K& key) { - return std::equal_range(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - std::pair equal_range(const K& key) const { - return std::equal_range(begin(), end(), key, _compare); - } - - iterator lower_bound(const key_type& key) { - return std::lower_bound(begin(), end(), key, _compare); - } - - const_iterator lower_bound(const key_type& key) const { - return std::lower_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - iterator lower_bound(const K& key) { - return std::lower_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - const_iterator lower_bound(const K& key) const { - return std::lower_bound(begin(), end(), key, _compare); - } - - iterator upper_bound(const key_type& key) { - return std::upper_bound(begin(), end(), key, _compare); - } - - const_iterator upper_bound(const key_type& key) const { - return std::upper_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - iterator upper_bound(const K& key) { - return std::upper_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - const_iterator upper_bound(const K& key) const { - return std::upper_bound(begin(), end(), key, _compare); - } - - key_compare key_comp() const { - return _compare; - } - - value_compare value_comp() const { - return value_compare(key_comp()); - } - - private: - template - void from_range(Iter first, Iter last) { - assert(_data.empty()); - _data.insert(_data.end(), first, last); - std::sort(_data.begin(), _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void from_range(sorted_range_t, Iter first, Iter last) { - assert(_data.empty()); - assert(detail::is_sorted(first, last, value_comp())); - _data.insert(_data.end(), first, last); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void from_range(sorted_unique_range_t, Iter first, Iter last) { - assert(_data.empty()); - assert(detail::is_sorted_unique(first, last, value_comp())); - _data.insert(_data.end(), first, last); - } - - private: - template - void insert_range(Iter first, Iter last) { - const auto mid_iter = _data.insert(_data.end(), first, last); - std::sort(mid_iter, _data.end(), value_comp()); - std::inplace_merge(_data.begin(), mid_iter, _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void insert_range(sorted_range_t, Iter first, Iter last) { - assert(detail::is_sorted(first, last, value_comp())); - const auto mid_iter = _data.insert(_data.end(), first, last); - std::inplace_merge(_data.begin(), mid_iter, _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - private: - PLUGIFY_NO_UNIQUE_ADDRESS - detail::pair_compare _compare; - container_type _data; - }; - - template - void swap( - flat_map& l, - flat_map& r) noexcept(noexcept(l.swap(r))) { - l.swap(r); - } - - template - bool operator==( - const flat_map& l, - const flat_map& r) { - return l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin()); - } - - template - auto operator<=>( - const flat_map& l, - const flat_map& r) { - if (l.size() < r.size()) { - return std::partial_ordering::less; - } else if (l.size() > r.size()) { - return std::partial_ordering::greater; - } else { - if (std::lexicographical_compare(l.cbegin(), l.cend(), r.cbegin(), r.cend())) { - return std::partial_ordering::less; - } else { - return std::partial_ordering::greater; - } - } - } - - template, typename Container = plg::vector>> - using map = flat_map; - -}// namespace plg -#endif \ No newline at end of file diff --git a/test/cross_call_master/external/plugify/include/plg/format.hpp b/test/cross_call_master/external/plugify/include/plg/format.hpp index 94e5bdb..9abb9fe 100644 --- a/test/cross_call_master/external/plugify/include/plg/format.hpp +++ b/test/cross_call_master/external/plugify/include/plg/format.hpp @@ -1,12 +1,19 @@ #pragma once -#include "plg/macro.hpp" - -#ifdef __cpp_lib_format +#include "plg/config.hpp" +#if __has_include() #include +#if defined(__cpp_lib_format) && __cpp_lib_format >= 201907L +#define PLUGIFY_HAS_STD_FORMAT 1 +#else +#define PLUGIFY_HAS_STD_FORMAT 0 +#endif +#else +#define PLUGIFY_HAS_STD_FORMAT 0 +#endif -#else // __cpp_lib_format +#if !PLUGIFY_HAS_STD_FORMAT // Define FMT_FORMAT_H externally to force a difference location for {fmt} #ifndef FMT_FORMAT_H @@ -21,6 +28,6 @@ namespace std { using namespace fmt; using namespace fmt::detail; -} +} // namespace std -#endif // __cpp_lib_format +#endif // !PLUGIFY_HAS_STD_FORMAT diff --git a/test/cross_call_master/external/plugify/include/plg/guards.hpp b/test/cross_call_master/external/plugify/include/plg/guards.hpp new file mode 100644 index 0000000..4691341 --- /dev/null +++ b/test/cross_call_master/external/plugify/include/plg/guards.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include "plg/config.hpp" + +namespace plg { +#if PLUGIFY_HAS_EXCEPTIONS + template + struct exception_guard_exceptions { + exception_guard_exceptions() = delete; + + constexpr explicit exception_guard_exceptions(Rollback rollback) + : _rollback(std::move(rollback)) + , _completed(false) { + } + + constexpr exception_guard_exceptions( + exception_guard_exceptions&& other + ) noexcept(std::is_nothrow_move_constructible_v) + : _rollback(std::move(other._rollback)) + , _completed(other._completed) { + other._completed = true; + } + + exception_guard_exceptions(const exception_guard_exceptions&) = delete; + exception_guard_exceptions& operator=(const exception_guard_exceptions&) = delete; + exception_guard_exceptions& operator=(exception_guard_exceptions&&) = delete; + + constexpr void complete() noexcept { + _completed = true; + } + + constexpr ~exception_guard_exceptions() { + if (!_completed) { + _rollback(); + } + } + + private: + PLUGIFY_NO_UNIQUE_ADDRESS Rollback _rollback; + bool _completed; + }; + + template + using exception_guard = exception_guard_exceptions; +#else + template + struct exception_guard_noexceptions { + exception_guard_noexceptions() = delete; + + constexpr explicit exception_guard_noexceptions(Rollback) { + } + + constexpr exception_guard_noexceptions( + exception_guard_noexceptions&& other + ) noexcept(std::is_nothrow_move_constructible_v) + : _completed(other._completed) { + other._completed = true; + } + + exception_guard_noexceptions(const exception_guard_noexceptions&) = delete; + exception_guard_noexceptions& operator=(const exception_guard_noexceptions&) = delete; + exception_guard_noexceptions& operator=(exception_guard_noexceptions&&) = delete; + + constexpr void complete() noexcept { + _completed = true; + } + + constexpr ~exception_guard_noexceptions() { + PLUGIFY_ASSERT(_completed, "exception_guard not completed with exceptions disabled"); + } + + private: + bool _completed = false; + }; + + template + using exception_guard = exception_guard_noexceptions; +#endif + + template + constexpr exception_guard make_exception_guard(Rollback rollback) { + return exception_guard(std::move(rollback)); + } + + template + class scope_guard { + PLUGIFY_NO_UNIQUE_ADDRESS Func _func; + + public: + constexpr explicit scope_guard(Func func) + : _func(std::move(func)) { + } + + constexpr ~scope_guard() { + _func(); + } + + scope_guard(const scope_guard&) = delete; + scope_guard& operator=(const scope_guard&) = delete; + scope_guard& operator=(scope_guard&&) = delete; + scope_guard(scope_guard&&) = delete; + }; + + template + constexpr scope_guard make_scope_guard(Func func) { + return scope_guard(std::move(func)); + } +} diff --git a/test/cross_call_master/external/plugify/include/plg/hash.hpp b/test/cross_call_master/external/plugify/include/plg/hash.hpp index 296436a..4028e57 100644 --- a/test/cross_call_master/external/plugify/include/plg/hash.hpp +++ b/test/cross_call_master/external/plugify/include/plg/hash.hpp @@ -34,16 +34,36 @@ namespace plg { } }; + // --- Hash traits depending on pointer size --- + template + struct hash_traits; + + template <> + struct hash_traits<4> { // 32-bit + static constexpr std::size_t fnv_basis = 0x811C9DC5u; + static constexpr std::size_t fnv_prime = 0x01000193u; + static constexpr std::size_t golden_ratio = 0x9e3779b9u; + }; + + template <> + struct hash_traits<8> { // 64-bit + static constexpr std::size_t fnv_basis = 0xcbf29ce484222325ULL; + static constexpr std::size_t fnv_prime = 0x100000001b3ULL; + static constexpr std::size_t golden_ratio = 0x9e3779b97f4a7c15ULL; + }; + + using active_hash_traits = hash_traits; + struct case_insensitive_hash { using is_transparent = void; // Enables heterogeneous lookup template auto operator()(const T& str_like) const noexcept { std::string_view str = str_like; - std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis - for (char c : str) { + std::size_t hash = active_hash_traits::fnv_basis; // FNV-1a + for (const char& c : str) { hash ^= static_cast(std::tolower(static_cast(c))); - hash *= 0x100000001b3; + hash *= active_hash_traits::fnv_prime; } return hash; } @@ -77,8 +97,7 @@ namespace plg { template inline void hash_combine(std::size_t& seed, const T& v) { std::hash hasher; - // 0x9e3779b97f4a7c15 is 64-bit golden ratio constant - seed ^= hasher(v) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2); + seed ^= hasher(v) + active_hash_traits::golden_ratio + (seed << 6) + (seed >> 2); } template @@ -94,5 +113,4 @@ namespace plg { return hash_combine_all(p.first, p.second); } }; - } diff --git a/test/cross_call_master/external/plugify/include/plg/inplace_vector.hpp b/test/cross_call_master/external/plugify/include/plg/inplace_vector.hpp new file mode 100644 index 0000000..71292c8 --- /dev/null +++ b/test/cross_call_master/external/plugify/include/plg/inplace_vector.hpp @@ -0,0 +1,772 @@ +#pragma once + +#include "plg/config.hpp" + +#if __has_include() +#include +#if defined(__cpp_lib_inplace_vector) && __cpp_lib_inplace_vector >= 202406L +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 1 +#else +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 0 +#endif +#else +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 0 +#endif + +#if !PLUGIFY_HAS_STD_INPLACE_VECTOR +#include +#include +#include +#include +#include +#include + +#if PLUGIFY_CPP_VERSION >= 202002L +#include +#include +#endif + +#ifndef PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF +#if defined(__cpp_impl_trivially_relocatable) && defined(__cpp_lib_trivially_relocatable) +#define PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(x) [[trivially_relocatable(x)]] +#else +#define PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(x) +#endif // __cpp_impl_trivially_relocatable +#endif // PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF + +// from https://github.com/Quuxplusone/SG14 +namespace plg { + namespace detail { + + template && std::is_copy_assignable_v), + bool = (std::is_move_constructible_v && std::is_move_assignable_v)> + struct ipvbase_assignable { + // Base for copyable types + }; + + template + struct ipvbase_assignable { + // Base for immobile types like std::mutex + explicit ipvbase_assignable() = default; + ipvbase_assignable(ipvbase_assignable&&) = delete; + ipvbase_assignable(const ipvbase_assignable&) = delete; + void operator=(ipvbase_assignable&&) = delete; + void operator=(const ipvbase_assignable&) = delete; + ~ipvbase_assignable() = default; + }; + + template + struct ipvbase_assignable { + explicit ipvbase_assignable() = default; + ipvbase_assignable(const ipvbase_assignable&) = delete; + ipvbase_assignable(ipvbase_assignable&&) = default; + void operator=(const ipvbase_assignable&) = delete; + ipvbase_assignable& operator=(ipvbase_assignable&&) = default; + ~ipvbase_assignable() = default; + }; + + template + struct PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(std::is_trivially_relocatable_v) ipvbase + { + size_t _size = 0; + union { + [[maybe_unused]] char _dummy; + T _data[N]; + }; + + constexpr T *base_data() { return _data; } + constexpr const T *base_data() const { return _data; } + constexpr void set_size(size_t n) { _size = n; } + + constexpr explicit ipvbase() noexcept {} + ipvbase(const ipvbase& rhs) + noexcept(std::is_nothrow_copy_constructible_v) + { + if constexpr (std::is_trivially_copy_constructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else { + std::uninitialized_copy_n(rhs._data, rhs._size, _data); + _size = rhs._size; + } + } + ipvbase(ipvbase&& rhs) + noexcept(std::is_nothrow_move_constructible_v +#if defined(__cpp_lib_trivially_relocatable) + || std::is_trivially_relocatable_v +#endif // __cpp_lib_trivially_relocatable + ) + { + if constexpr (std::is_trivially_move_constructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); +#if defined(__cpp_lib_trivially_relocatable) + } else if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_n(rhs._data, rhs._size, _data); + _size = rhs._size; + rhs._size = 0; +#endif // __cpp_lib_trivially_relocatable + } else { + std::uninitialized_move_n(rhs._data, rhs._size, _data); + _size = rhs._size; + } + } + void operator=(const ipvbase& rhs) + noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_copy_assignable_v) + { + if constexpr (std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v && std::is_trivially_destructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else if (this == std::addressof(rhs)) { + // do nothing + } else if (rhs._size <= _size) { + std::copy(rhs._data, rhs._data + rhs._size, _data); + std::destroy(_data + rhs._size, _data + _size); + _size = rhs._size; + } else { + std::copy(rhs._data, rhs._data + _size, _data); + std::uninitialized_copy(rhs._data + _size, rhs._data + rhs._size, _data + _size); + _size = rhs._size; + } + } + void operator=(ipvbase&& rhs) + noexcept(std::is_nothrow_move_constructible_v && std::is_nothrow_move_assignable_v) + { + if constexpr (std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v && std::is_trivially_destructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else if (this == std::addressof(rhs)) { + // do nothing + } else if (rhs._size <= _size) { + std::move(rhs._data, rhs._data + rhs._size, _data); + std::destroy(_data + rhs._size, _data + _size); + _size = rhs._size; + } else { + std::move(rhs._data, rhs._data + _size, _data); +#if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate(rhs._data + _size, rhs._data + rhs._size, _data + _size); + std::swap(rhs._size, _size); + return; + } +#endif // __cpp_lib_trivially_relocatable + std::uninitialized_move(rhs._data + _size, rhs._data + rhs._size, _data + _size); + _size = rhs._size; + } + } + +#if __cpp_concepts >= 202002L + ipvbase(const ipvbase&) requires std::is_trivially_copy_constructible_v = default; + ipvbase(ipvbase&&) requires std::is_trivially_move_constructible_v = default; + ipvbase& operator=(const ipvbase&) requires std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v && std::is_trivially_destructible_v = default; + ipvbase& operator=(ipvbase&&) requires std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v && std::is_trivially_destructible_v = default; + ~ipvbase() requires std::is_trivially_destructible_v = default; +#endif // __cpp_concepts >= 202002L + +#if PLUGIFY_CPP_VERSION >= 202002L + constexpr +#endif // PLUGIFY_CPP_VERSION >= 202002L + ~ipvbase() { + std::destroy(_data, _data + _size); + } + }; + + template + struct ipvbase_zero { + static constexpr size_t _size = 0; + constexpr T *base_data() { return nullptr; } + constexpr const T *base_data() const { return nullptr; } + constexpr void set_size(size_t) { } + }; + + template + struct ipvbase_trivial { + size_t _size = 0; + union { + [[maybe_unused]] char _dummy; + T _data[N]; + }; + constexpr explicit ipvbase_trivial() {} + constexpr T *base_data() { return _data; } + constexpr const T *base_data() const { return _data; } + constexpr void set_size(size_t n) { _size = n; } + }; + + template + using ipvbase_t = std::conditional_t< + N == 0, + ipvbase_zero, + std::conditional_t< + std::is_trivially_copyable_v, + ipvbase_trivial, + ipvbase + > + >; + } // namespace detail + + template + class inplace_vector : detail::ipvbase_assignable, detail::ipvbase_t { + using detail::ipvbase_t::_size; + using detail::ipvbase_t::set_size; + public: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = T*; + using const_iterator = const T*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // [inplace.vector.cons] + + inplace_vector() = default; + inplace_vector(inplace_vector&&) = default; + inplace_vector(const inplace_vector&) = default; + inplace_vector& operator=(inplace_vector&&) = default; + inplace_vector& operator=(const inplace_vector&) = default; + inplace_vector& operator=(std::initializer_list il) + requires std::is_copy_constructible_v + { + assign(il.begin(), il.end()); + return *this; + } + + constexpr inplace_vector(std::initializer_list il) + requires std::copy_constructible : inplace_vector(il.begin(), il.end()) { } + constexpr explicit inplace_vector(size_t n) + requires std::default_initializable + { + if (n > N) { + throw_bad_alloc(); + } + std::uninitialized_value_construct_n(data(), n); + set_size(n); + } + constexpr explicit inplace_vector(size_t n, const value_type& value) + requires std::copy_constructible + { + assign(n, value); + } + + template + requires std::constructible_from::value_type> + constexpr explicit inplace_vector(InputIterator first, InputIterator last) + { + if constexpr (std::random_access_iterator) { + size_t n = static_cast(std::distance(first, last)); + if (n > N) { + throw_bad_alloc(); + } + std::uninitialized_copy_n(first, n, data()); + set_size(n); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } + } + } + + constexpr void assign(std::initializer_list il) + requires std::is_copy_constructible_v + { + assign(il.begin(), il.end()); + } + + constexpr void assign(size_t n, const value_type& value) + requires std::is_copy_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::fill_n(data(), n, value); + std::destroy(data() + n, data() + _size); + } else { + std::fill_n(data(), _size, value); + std::uninitialized_fill_n(data() + _size, n - _size, value); + } + set_size(n); + } + + template + requires std::is_constructible_v::value_type> + constexpr void assign(InputIterator first, InputIterator last) { + const size_type n = static_cast(std::distance(first, last)); + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::copy(first, last, data()); + std::destroy(data() + n, data() + _size); + } else { + std::copy(first, first + _size, data()); + std::uninitialized_copy(first + _size, last, data() + _size); + } + set_size(n); + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + constexpr explicit inplace_vector(std::from_range_t, R&& rg) { + if constexpr (std::ranges::sized_range) { + size_t n = std::ranges::size(rg); + if (n > N) { + throw_bad_alloc(); + } + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, data(), std::unreachable_sentinel); + set_size(n); + } else { + for (auto&& e : rg) { + emplace_back(decltype(e)(e)); + } + } + } + + template + requires std::convertible_to, value_type> + constexpr void assign_range(R&& rg) { + auto first = std::ranges::begin(rg); + auto last = std::ranges::end(rg); + size_t n = std::ranges::size(rg); + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::ranges::copy(first, last, data()); + std::destroy(data() + n, data() + _size); + } else { + auto mid = std::ranges::next(first, _size, last); + std::ranges::copy(first, mid, data()); + std::ranges::uninitialized_copy(mid, last, data() + _size); + } + set_size(n); + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + // iterators + + constexpr iterator begin() noexcept { return data(); } + constexpr iterator end() noexcept { return data() + _size; } + constexpr const_iterator begin() const noexcept { return data(); } + constexpr const_iterator end() const noexcept { return data() + _size; } + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + constexpr const_iterator cbegin() const noexcept { return data(); } + constexpr const_iterator cend() const noexcept { return data() + _size; } + constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + constexpr void resize(size_type n) + requires std::is_default_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (n < _size) { + std::destroy(data() + n, data() + _size); + set_size(n); + } else { + std::uninitialized_value_construct(data() + _size, data() + n); + set_size(_size + n); + } + } + + constexpr void resize(size_type n, const value_type& value) + requires std::is_copy_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (n < _size) { + std::destroy(data() + n, data() + _size); + set_size(n); + } else { + std::uninitialized_fill(data() + _size, data() + n, value); + set_size(_size + n); + } + } + + static constexpr void reserve(size_type n) { + if (n > N) { + throw_bad_alloc(); + } + } + static constexpr void shrink_to_fit() noexcept {} + + // element access + + constexpr reference operator[](size_type pos) { + PLUGIFY_ASSERT(pos < size(), "index out of bounds"); + return data()[pos]; + } + constexpr reference front() { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[0]; + } + constexpr reference back() { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[_size - 1]; + } + + constexpr const_reference operator[](size_type pos) const { + PLUGIFY_ASSERT(pos < size(), "index out of bounds"); + return data()[pos]; + } + constexpr const_reference front() const { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[0]; + } + constexpr const_reference back() const { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[_size - 1]; + } + + constexpr reference at(size_type i) { + if (i >= _size) { + throw_out_of_range(); + } + return data()[i]; + } + constexpr const_reference at(size_type i) const { + if (i >= _size) { + throw_out_of_range(); + } + return data()[i]; + } + + // [inplace.vector.data] + + constexpr T* data() noexcept { return this->base_data(); } + constexpr const T* data() const noexcept { return this->base_data(); } + constexpr size_type size() const noexcept { return _size; } + static constexpr size_type max_size() noexcept { return N; } + static constexpr size_type capacity() noexcept { return N; } + [[nodiscard]] constexpr bool empty() const noexcept { return _size == 0; }; + + // [inplace.vector.modifiers] + + template + requires std::is_constructible_v + value_type& unchecked_emplace_back(Args&&... args) { + // Precondition: (_size < N) + value_type* p = data() + _size; + p = std::construct_at(p, std::forward(args)...); + set_size(_size + 1); + return *p; + } + value_type& unchecked_push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return unchecked_emplace_back(value); + } + value_type& unchecked_push_back(value_type&& value) + requires std::is_move_constructible_v + { + return unchecked_emplace_back(static_cast(value)); + } + + template + requires std::is_constructible_v + constexpr value_type* try_emplace_back(Args&&... args) { + if (_size == N) { + return nullptr; + } + return std::addressof(unchecked_emplace_back(static_cast(args)...)); + } + constexpr value_type* try_push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return try_emplace_back(value); + } + constexpr value_type* try_push_back(value_type&& value) + requires std::is_move_constructible_v + { + return try_emplace_back(static_cast(value)); + } + + template + requires std::is_constructible_v + value_type& emplace_back(Args&&... args) { + if (_size == N) { + throw_bad_alloc(); + } + return unchecked_emplace_back(static_cast(args)...); + } + value_type& push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return emplace_back(value); + } + value_type& push_back(value_type&& value) + requires std::is_move_constructible_v + { + return emplace_back(static_cast(value)); + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + constexpr void append_range(R&& rg) { + for (auto&& e : rg) { + emplace_back(static_cast(e)); + } + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + void pop_back() { + std::destroy_at(data() + _size - 1); + set_size(_size - 1); + } + + template + requires std::is_constructible_v + iterator emplace(const_iterator pos, Args&&... args) { + auto it = iterator(pos); + emplace_back(static_cast(args)...); + std::rotate(it, end() - 1, end()); + return it; + } + iterator insert(const_iterator pos, const value_type& value) + requires std::is_copy_constructible_v + { + return emplace(pos, value); + } + iterator insert(const_iterator pos, value_type&& value) + requires std::is_move_constructible_v + { + return emplace(pos, static_cast(value)); + } + + iterator insert(const_iterator pos, size_type n, const value_type& value) + requires std::is_copy_constructible_v + { + if (N - _size < n) { + throw_bad_alloc(); + } + auto it = iterator(pos); + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::uninitialized_fill_n(it, n, value); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::uninitialized_fill_n(oldend, n, value); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + return it; + } + + template + requires (std::is_constructible_v::value_type> && !std::is_const_v) + iterator insert(const_iterator pos, InputIterator first, InputIterator last) { + auto it = iterator(pos); + auto oldend = end(); + if constexpr (std::random_access_iterator) { + size_type n = static_cast(std::distance(first, last)); + if (N - _size < n) { + throw_bad_alloc(); + } + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::uninitialized_copy_n(first, n, it); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::uninitialized_copy_n(first, n, oldend); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } + std::rotate(it, oldend, end()); + } + return it; + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + iterator insert_range(const_iterator pos, R&& rg) { + auto it = iterator(pos); + auto oldend = end(); + if constexpr (std::ranges::sized_range) { + size_type n = std::ranges::size(rg); + if (N - _size < n) { + throw_bad_alloc(); + } + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, it, std::unreachable_sentinel); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, oldend, std::unreachable_sentinel); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + } else { + auto [rgend, newend] = std::ranges::uninitialized_copy(rg, std::ranges::subrange(oldend, data() + N)); + if (rgend != std::ranges::end(rg)) { + std::destroy(oldend, newend); + throw_bad_alloc(); + } else { + set_size(newend - data()); + std::rotate(it, oldend, newend); + } + } + return it; + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + iterator insert(const_iterator pos, std::initializer_list il) + requires (std::is_copy_constructible_v && !std::is_const_v) + { + return insert(pos, il.begin(), il.end()); + } + + iterator erase(const_iterator pos) + requires (!std::is_const_v) + { + auto it = iterator(pos); + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::destroy_at(it); + std::uninitialized_relocate(it + 1, oldend, it); + set_size(_size - 1); + return it; + } + #endif + std::move(it + 1, oldend, it); + std::destroy_at(oldend - 1); + set_size(_size - 1); + return it; + } + + iterator erase(const_iterator first, const_iterator last) + requires (!std::is_const_v) + { + auto ifirst = iterator(first); + auto ilast = iterator(last); + auto n = static_cast(std::distance(ifirst, ilast)); + if (n != 0) { + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::destroy(ifirst, ilast); + std::uninitialized_relocate(ilast, oldend, ifirst); + set_size(_size - n); + return ifirst; + } + #endif // __cpp_lib_trivially_relocatable + std::destroy(std::move(ilast, oldend, ifirst), oldend); + set_size(_size - n); + } + return ifirst; + } + + constexpr void clear() noexcept { + std::destroy(data(), data() + _size); + set_size(0); + } + + constexpr void swap(inplace_vector& b) + noexcept(N == 0 || (std::is_nothrow_swappable_v && std::is_nothrow_move_constructible_v)) + requires (!std::is_const_v) + { + auto& a = *this; + if (a._size < b._size) { + b.swap(a); + } else { + std::swap_ranges(a.data(), a.data() + b._size, b.data()); + #if defined(__cpp_lib_trivially_relocatable) + size_t n = a._size; + a.set_size(b._size); + std::uninitialized_relocate(a.data() + b._size, a.data() + n, b.data() + b._size); + b.set_size(n); + #else + std::uninitialized_move(a.data() + b._size, a.data() + a._size, b.data() + b._size); + std::destroy(a.data() + b._size, a.data() + a._size); + if constexpr (N != 0) { + std::swap(a._size, b._size); + } + #endif + } + } + + friend constexpr void swap(inplace_vector& a, inplace_vector& b) noexcept(noexcept(a.swap(b))) { + a.swap(b); + } + + constexpr friend bool operator==(const inplace_vector& lhs, const inplace_vector& rhs) { + if (lhs.size() != rhs.size()) return false; + return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + } + + #if __cpp_impl_three_way_comparison >= 201907L + constexpr friend auto operator<=>(const inplace_vector& lhs, const inplace_vector& rhs) { + return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + #else + constexpr friend bool operator<(const inplace_vector& a, const inplace_vector& b) { + const T* adata = a.data(); + const T* bdata = b.data(); + size_t n = (a._size < b._size) ? a._size : b._size; + for (size_t i = 0; i < n; ++i) { + if (adata[i] < bdata[i]) { + return true; + } else if (bdata[i] < adata[i]) { + return false; + } + } + return (a._size < b._size); + } + constexpr friend bool operator>(const inplace_vector& a, const inplace_vector& b) { return (b < a); } + constexpr friend bool operator<=(const inplace_vector& a, const inplace_vector& b) { return !(b < a); } + constexpr friend bool operator>=(const inplace_vector& a, const inplace_vector& b) { return !(a < b); } + constexpr friend bool operator!=(const inplace_vector& a, const inplace_vector& b) { return !(a == b); } + #endif + + private: + [[noreturn]] static void throw_bad_alloc() { + PLUGIFY_THROW("memory size would exceed capacity()", std::bad_alloc); + } + + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); + } + }; +} // namespace plg + +namespace std { + template + using inplace_vector = plg::inplace_vector; +} // namespace std + +#endif \ No newline at end of file diff --git a/test/cross_call_master/external/plugify/include/plg/numerics.hpp b/test/cross_call_master/external/plugify/include/plg/numerics.hpp index 9dd82f3..f975f3d 100644 --- a/test/cross_call_master/external/plugify/include/plg/numerics.hpp +++ b/test/cross_call_master/external/plugify/include/plg/numerics.hpp @@ -1,7 +1,6 @@ #pragma once -#include "plg/string.hpp" -#include "plg/vector.hpp" +#include "plg/config.hpp" namespace plg { PLUGIFY_WARN_PUSH() diff --git a/test/cross_call_master/external/plugify/include/plg/path.hpp b/test/cross_call_master/external/plugify/include/plg/path.hpp index afc3d6e..7c44925 100644 --- a/test/cross_call_master/external/plugify/include/plg/path.hpp +++ b/test/cross_call_master/external/plugify/include/plg/path.hpp @@ -4,13 +4,15 @@ #include #include +#include "plg/config.hpp" + namespace plg { using path_view = std::basic_string_view; using path_string = std::filesystem::path::string_type; using path_char = path_string::value_type; using path_diff_t = path_string::difference_type; -#if _WIN32 +#if PLUGIFY_PLATFORM_WINDOWS #define PLUGIFY_PATH_LITERAL(x) L##x #else #define PLUGIFY_PATH_LITERAL(x) x @@ -19,15 +21,14 @@ namespace plg { template bool insensitive_equals(const path_char lhs, const path_char rhs) { if constexpr (std::is_same_v) { - return std::towlower(lhs) == rhs; // NOLINT + return std::towlower(static_cast(lhs)) == std::towlower(static_cast(rhs)); } else { - return std::tolower(lhs) == rhs; + return std::tolower(static_cast(lhs)) == std::tolower(static_cast(rhs)); } } inline bool insensitive_equals(const path_view lhs, const path_view rhs) { - return lhs.size() == rhs.size() - && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); + return lhs.size() == rhs.size() && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); } inline path_view extension_view(const std::filesystem::path& path, size_t extension_size) { @@ -47,7 +48,7 @@ namespace plg { } inline auto as_string(const std::filesystem::path& p) { -#if _WIN32 +#if PLUGIFY_PLATFORM_WINDOWS return p.string(); // returns std::string by value #else return p.native(); // returns const std::string& diff --git a/test/cross_call_master/external/plugify/include/plg/plugin.hpp b/test/cross_call_master/external/plugify/include/plg/plugin.hpp index 76f2286..550b623 100644 --- a/test/cross_call_master/external/plugify/include/plg/plugin.hpp +++ b/test/cross_call_master/external/plugify/include/plg/plugin.hpp @@ -181,15 +181,15 @@ namespace plg { namespace plg { namespace raw { struct vector { - [[maybe_unused]] uint8_t padding[sizeof(plg::vector)]{}; + uint8_t pad[sizeof(plg::vector)]{}; }; struct string { - [[maybe_unused]] uint8_t padding[sizeof(plg::string)]{}; + uint8_t pad[sizeof(plg::string)]{}; }; struct variant { - [[maybe_unused]] uint8_t padding[sizeof(plg::any)]{}; + uint8_t pad[sizeof(plg::any)]{}; }; } // namespace raw diff --git a/test/cross_call_master/external/plugify/include/plg/split_buffer.hpp b/test/cross_call_master/external/plugify/include/plg/split_buffer.hpp new file mode 100644 index 0000000..0568d15 --- /dev/null +++ b/test/cross_call_master/external/plugify/include/plg/split_buffer.hpp @@ -0,0 +1,907 @@ +#pragma once + +#include "plg/config.hpp" +#include "plg/concepts.hpp" + +namespace plg { + template class Layout> + class split_buffer; + + template + class split_buffer_pointer_layout { + protected: + using value_type = T; + using allocator_type = Allocator; + using alloc_rr = std::remove_reference_t; + using alloc_traits = std::allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using constIterator = const_pointer; + using sentinel_type = pointer; + + public: + constexpr split_buffer_pointer_layout() + : _back_cap(nullptr) { + } + + constexpr explicit split_buffer_pointer_layout(const allocator_type& alloc) + : _back_cap(nullptr) + , _alloc(alloc) { + } + + constexpr pointer front_cap() noexcept { + return _front_cap; + } + + constexpr const_pointer front_cap() const noexcept { + return _front_cap; + } + + constexpr pointer begin() noexcept { + return _begin; + } + + constexpr const_pointer begin() const noexcept { + return _begin; + } + + constexpr pointer end() noexcept { + return _end; + } + + constexpr pointer end() const noexcept { + return _end; + } + + constexpr size_type size() const noexcept { + return static_cast(_end - _begin); + } + + constexpr bool empty() const noexcept { + return _begin == _end; + } + + constexpr size_type capacity() const noexcept { + return static_cast(_back_cap - _front_cap); + } + + constexpr allocator_type& get_allocator() noexcept { + return _alloc; + } + + constexpr const allocator_type& get_allocator() const noexcept { + return _alloc; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type + // deduction, not explicit types. + constexpr sentinel_type raw_sentinel() const noexcept { + return _end; + } + + constexpr sentinel_type raw_capacity() const noexcept { + return _back_cap; + } + + constexpr void set_data(pointer new_first) noexcept { + _front_cap = new_first; + } + + constexpr void + set_valid_range(pointer new_begin, pointer new_end) noexcept { + _begin = new_begin; + _end = new_end; + } + + constexpr void + set_valid_range(pointer new_begin, size_type new_size) noexcept { + _begin = new_begin; + _end = _begin + new_size; + } + + constexpr void set_sentinel(pointer new_end) noexcept { + PLUGIFY_ASSERT(_front_cap <= new_end, "new_end cannot precede _front_cap"); + _end = new_end; + } + + constexpr void set_sentinel(size_type new_size) noexcept { + _end = _begin + new_size; + } + + constexpr void set_capacity(size_type new_capacity) noexcept { + _back_cap = _front_cap + new_capacity; + } + + constexpr void set_capacity(pointer new_capacity) noexcept { + _back_cap = new_capacity; + } + + constexpr size_type front_spare() const noexcept { + return static_cast(_begin - _front_cap); + } + + constexpr size_type back_spare() const noexcept { + return static_cast(_back_cap - _end); + } + + constexpr reference back() noexcept { + return *(_end - 1); + } + + constexpr const_reference back() const noexcept { + return *(_end - 1); + } + + constexpr void swap_without_allocator( + split_buffer_pointer_layout< + split_buffer, + value_type, + alloc_rr&>& other + ) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_back_cap, other._back_cap); + std::swap(_end, other._end); + } + + constexpr void swap(split_buffer_pointer_layout& other) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_back_cap, other._back_cap); + std::swap(_end, other._end); + swap_allocator(_alloc, other._alloc); + } + + constexpr void reset() noexcept { + _front_cap = nullptr; + _begin = nullptr; + _end = nullptr; + _back_cap = nullptr; + } + + constexpr void copy_without_alloc( + const split_buffer_pointer_layout& other + ) noexcept(std::is_nothrow_copy_assignable::value) { + _front_cap = other._front_cap; + _begin = other._begin; + _end = other._end; + _back_cap = other._back_cap; + } + + private: + pointer _front_cap = nullptr; + pointer _begin = nullptr; + pointer _end = nullptr; + pointer _back_cap = nullptr; + PLUGIFY_NO_UNIQUE_ADDRESS allocator_type _alloc; + + template + friend class split_buffer_pointer_layout; + }; + + template + class split_buffer_size_layout { + protected: + using value_type = T; + using allocator_type = Allocator; + using alloc_rr = std::remove_reference_t; + using alloc_traits = std::allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using constIterator = const_pointer; + using sentinel_type = size_type; + + public: + constexpr split_buffer_size_layout() = default; + + constexpr explicit split_buffer_size_layout(const allocator_type& alloc) + : _alloc(alloc) { + } + + constexpr pointer front_cap() noexcept { + return _front_cap; + } + + constexpr const_pointer front_cap() const noexcept { + return _front_cap; + } + + constexpr pointer begin() noexcept { + return _begin; + } + + constexpr const_pointer begin() const noexcept { + return _begin; + } + + constexpr pointer end() noexcept { + return _begin + _size; + } + + constexpr pointer end() const noexcept { + return _begin + _size; + } + + constexpr size_type size() const noexcept { + return _size; + } + + constexpr bool empty() const noexcept { + return _size == 0; + } + + constexpr size_type capacity() const noexcept { + return _cap; + } + + constexpr allocator_type& get_allocator() noexcept { + return _alloc; + } + + constexpr const allocator_type& get_allocator() const noexcept { + return _alloc; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type + // deduction, not explicit types. + constexpr sentinel_type raw_sentinel() const noexcept { + return _size; + } + + constexpr sentinel_type raw_capacity() const noexcept { + return _cap; + } + + constexpr void set_data(pointer new_first) noexcept { + _front_cap = new_first; + } + + constexpr void + set_valid_range(pointer new_begin, pointer new_end) noexcept { + // Size-based split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + _size -= new_begin - _begin; + _begin = new_begin; + set_sentinel(new_end); + } + + constexpr void + set_valid_range(pointer new_begin, size_type new_size) noexcept { + // Size-based split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + _size -= new_begin - _begin; + _begin = new_begin; + set_sentinel(new_size); + } + + constexpr void set_sentinel(pointer new_end) noexcept { + _LIBCPP_ASSERT_INTERNAL(_front_cap <= new_end, "new_end cannot precede _front_cap"); + _size += new_end - end(); + } + + constexpr void set_sentinel(size_type new_size) noexcept { + _size = new_size; + } + + constexpr void set_capacity(size_type new_capacity) noexcept { + _cap = new_capacity; + } + + constexpr void set_capacity(pointer new_capacity) noexcept { + _cap = new_capacity - _begin; + } + + constexpr size_type front_spare() const noexcept { + return static_cast(_begin - _front_cap); + } + + constexpr size_type back_spare() const noexcept { + // `_cap - _end` tells us the total number of spares when in size-mode. We need to remove + // the front_spare from the count. + return _cap - _size - front_spare(); + } + + constexpr reference back() noexcept { + return _begin[_size - 1]; + } + + constexpr const_reference back() const noexcept { + return _begin[_size - 1]; + } + + constexpr void swap_without_allocator( + split_buffer_pointer_layout< + split_buffer, + value_type, + alloc_rr&>& other + ) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_cap, other._cap); + std::swap(_size, other._size); + } + + constexpr void swap(split_buffer_size_layout& other) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_cap, other._cap); + std::swap(_size, other._size); + swap_allocator(_alloc, other._alloc); + } + + constexpr void reset() noexcept { + _front_cap = nullptr; + _begin = nullptr; + _size = 0; + _cap = 0; + } + + constexpr void copy_without_alloc( + const split_buffer_size_layout& other + ) noexcept(std::is_nothrow_copy_assignable::value) { + _front_cap = other._front_cap; + _begin = other._begin; + _cap = other._cap; + _size = other._size; + } + + private: + pointer _front_cap = nullptr; + pointer _begin = nullptr; + size_type _size = 0; + size_type _cap = 0; + PLUGIFY_NO_UNIQUE_ADDRESS allocator_type _alloc; + + template + friend class split_buffer_size_layout; + }; + + // `split_buffer` is a contiguous array data structure. It may hold spare capacity at both ends of + // the sequence. This allows for a `split_buffer` to grow from both the front and the back without + // relocating its contents until it runs out of room. This characteristic sets it apart from + // `std::vector`, which only holds spare capacity at its end. As such, `split_buffer` is useful + // for implementing both `std::vector` and `std::deque`. + // + // The sequence is stored as a contiguous chunk of memory delimited by the following "pointers" (`o` + // denotes uninitialized memory and `x` denotes a valid object): + // + // |oooooooooooooooooooxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxoooooooooooooooooooooooo| + // ^ ^ ^ ^ + // _front_cap _begin _end _back_cap + // + // The range [_front_cap, _begin) contains uninitialized memory. It is referred to as the "front + // spare capacity". The range [_begin, _end) contains valid objects. It is referred to as the "valid + // range". The range [_end, _back_cap) contains uninitialized memory. It is referred to as the "back + // spare capacity". + // + // The layout of `split_buffer` is determined by the `Layout` template template parameter. This + // `Layout` allows the above pointers to be stored as different representations, such as integer + // offsets. A layout class template must provide the following interface: + // + // template + // class layout { + // protected: + // using value_type = T; + // using allocator_type = Allocator; + // using alloc_rr = std::remove_reference_t; + // using alloc_traits = allocator_traits; + // using reference = value_type&; + // using const_reference = const value_type&; + // using size_type = typename alloc_traits::size_type; + // using difference_type = typename alloc_traits::difference_type; + // using pointer = typename alloc_traits::pointer; + // using const_pointer = typename alloc_traits::const_pointer; + // using iterator = pointer; + // using constIterator = const_pointer; + // using sentinel_type = /* type that represents the layout's sentinel */; + // + // public: + // layout() = default; + // explicit layout(const allocator_type&); + // + // pointer front_cap(); + // const_pointer front_cap() const; + // + // pointer begin(); + // const_pointer begin() const; + // + // pointer end(); + // pointer end() const; + // + // size_type size() const; + // bool empty() const; + // size_type capacity() const; + // + // allocator_type& get_allocator(); + // allocator_type const& get_allocator() const; + // + // sentinel_type raw_sentinel() const; + // sentinel_type raw_capacity() const; + // + // void set_data(pointer); + // void set_valid_range(pointer begin, pointer end); + // void set_valid_range(pointer begin, size_type size); + // void set_sentinel(pointer end); + // void set_sentinel(size_type size); + // + // void set_capacity(size_type capacity); + // void set_capacity(pointer capacity); + // + // size_type front_spare() const; + // size_type back_spare() const; + // + // reference back(); + // const_reference back() const; + // + // template + // void swap_without_allocator(_OtherLayout&); + // void swap(layout&); + // + // void reset(); + // void copy_without_alloc(layout const&); + // }; + // + template class Layout> + class split_buffer : Layout, T, Allocator> { + using base_type = Layout, T, Allocator>; + + public: + using base_type::back_spare; + using base_type::copy_without_alloc; + using base_type::front_cap; + using base_type::front_spare; + using base_type::get_allocator; + using base_type::raw_capacity; + using base_type::raw_sentinel; + using base_type::reset; + using base_type::set_capacity; + using base_type::set_data; + using base_type::set_sentinel; + using base_type::set_valid_range; + + using typename base_type::alloc_rr; + using typename base_type::alloc_traits; + using typename base_type::allocator_type; + using typename base_type::constIterator; + using typename base_type::const_pointer; + using typename base_type::const_reference; + using typename base_type::difference_type; + using typename base_type::iterator; + using typename base_type::pointer; + using typename base_type::reference; + using typename base_type::size_type; + using typename base_type::value_type; + + // A split_buffer contains the following members which may be trivially relocatable: + // - pointer: may be trivially relocatable, so it's checked + // - allocator_type: may be trivially relocatable, so it's checked + // split_buffer doesn't have any self-references, so it's trivially relocatable if its members + // are. + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value, + split_buffer, + void>; + + split_buffer(const split_buffer&) = delete; + split_buffer& operator=(const split_buffer&) = delete; + + split_buffer() = default; + + constexpr explicit split_buffer(alloc_rr& a) + : base_type(a) { + } + + constexpr explicit split_buffer(const alloc_rr& a) + : base_type(a) { + } + + constexpr split_buffer(size_type cap, size_type start, alloc_rr& a); + + constexpr + split_buffer(split_buffer&& c) noexcept(std::is_nothrow_move_constructible_v); + + constexpr split_buffer(split_buffer&& c, const alloc_rr& a); + + + constexpr split_buffer& operator=(split_buffer&& c) noexcept( + (alloc_traits::propagate_on_container_move_assignment::value + && std::is_nothrow_move_assignable_v) + || !alloc_traits::propagate_on_container_move_assignment::value + ); + + constexpr ~split_buffer(); + + using base_type::back; + using base_type::begin; + using base_type::capacity; + using base_type::empty; + using base_type::end; + using base_type::size; + + constexpr void clear() noexcept { + destruct_at_end(begin()); + } + + constexpr reference front() { + return *begin(); + } + + constexpr const_reference front() const { + return *begin(); + } + + constexpr void shrink_to_fit() noexcept; + + template + constexpr void emplace_front(Args&&... args); + template + constexpr void emplace_back(Args&&... args); + + constexpr void pop_front() { + destruct_at_begin(begin() + 1); + } + + constexpr void pop_back() { + destruct_at_end(end() - 1); + } + + constexpr void construct_at_end(size_type n); + constexpr void construct_at_end(size_type n, const_reference x); + + template + constexpr void + construct_at_end(ForwardIterator first, ForwardIterator last); + + template + constexpr void + construct_at_end_with_sentinel(Iterator first, Sentinel last); + + template + constexpr void construct_at_end_with_size(Iterator first, size_type n); + + constexpr void destruct_at_begin(pointer new_begin) { + destruct_at_begin(new_begin, std::is_trivially_destructible()); + } + + constexpr void destruct_at_begin(pointer new_begin, std::false_type); + constexpr void destruct_at_begin(pointer new_begin, std::true_type); + + constexpr void destruct_at_end(pointer new_last) noexcept { + destruct_at_end(new_last, std::false_type()); + } + + constexpr void destruct_at_end(pointer new_last, std::false_type) noexcept; + constexpr void destruct_at_end(pointer new_last, std::true_type) noexcept; + + constexpr void swap( + split_buffer& x + ) noexcept(!alloc_traits::propagate_on_container_swap::value || std::is_nothrow_swappable_v); + + constexpr bool invariants() const { + if (front_cap() == nullptr) { + if (begin() != nullptr) { + return false; + } + + if (!empty()) { + return false; + } + + if (capacity() != 0) { + return false; + } + + return true; + } else { + if (begin() < front_cap()) { + return false; + } + + if (capacity() < size()) { + return false; + } + + if (end() < begin()) { + return false; + } + + return true; + } + } + + constexpr void + swap_without_allocator(split_buffer& other) noexcept { + base_type::swap_without_allocator(other); + } + + private: + constexpr void move_assign_alloc(split_buffer& c, std::true_type) noexcept( + std::is_nothrow_move_assignable_v + ) { + get_allocator() = std::move(c.get_allocator()); + } + + constexpr void move_assign_alloc(split_buffer&, std::false_type) noexcept { + } + + struct ConstructTransaction { + constexpr explicit ConstructTransaction( + split_buffer* parent, + pointer p, + size_type n + ) noexcept + : _pos(p) + , _end(p + n) + , _parent(parent) { + } + + constexpr ~ConstructTransaction() { + _parent->set_sentinel(_pos); + } + + pointer _pos; + const pointer _end; + + private: + split_buffer* _parent; + }; + + template class L2> + friend class split_buffer; + }; + + // Default constructs n objects starting at `end()` + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == size() + n + template class Layout> + constexpr void split_buffer::construct_at_end(size_type n) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos)); + } + } + + // Copy constructs n objects starting at `end()` from x + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == old size() + n + // Postcondition: [i] == x for all i in [size() - n, n) + template class Layout> + constexpr void + split_buffer::construct_at_end(size_type n, const_reference x) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos), x); + } + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end_with_sentinel(Iterator first, Sentinel last) { + alloc_rr& a = get_allocator(); + for (; first != last; ++first) { + if (back_spare() == 0) { + size_type old_cap = capacity(); + size_type new_cap = std::max(2 * old_cap, 8); + split_buffer buf(new_cap, 0, a); + pointer buf_end = buf.end(); + pointer cur_end = end(); + for (pointer p = begin(); p != cur_end; ++p) { + alloc_traits::construct(buf.get_allocator(), std::to_address(buf_end), std::move(*p)); + buf.set_sentinel(++buf_end); + } + swap(buf); + } + + alloc_traits::construct(a, std::to_address(end()), *first); + set_sentinel(size() + 1); + } + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end(ForwardIterator first, ForwardIterator last) { + construct_at_end_with_size(first, std::distance(first, last)); + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end_with_size(ForwardIterator first, size_type n) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos, (void) ++first) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos), *first); + } + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_begin(pointer new_begin, std::false_type) { + pointer pos = begin(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (pos != new_begin) { + alloc_traits::destroy(get_allocator(), std::to_address(pos++)); + } + set_valid_range(pos, end()); + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_begin(pointer new_begin, std::true_type) { + set_valid_range(new_begin, end()); + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_end(pointer new_last, std::false_type) noexcept { + pointer cur_end = end(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (new_last != cur_end) { + alloc_traits::destroy(get_allocator(), std::to_address(--cur_end)); + } + set_sentinel(cur_end); + } + + template class Layout> + constexpr split_buffer::split_buffer(size_type cap, size_type start, alloc_rr& a) + : base_type(a) { + PLUGIFY_ASSERT(cap >= start, "can't have a start point outside the capacity"); + if (cap > 0) { + auto allocation = allocate_at_least(get_allocator(), cap); + set_data(allocation.ptr); + cap = allocation.count; + } + + pointer pos = front_cap() + start; + set_valid_range(pos, pos); + set_capacity(cap); + } + + template class Layout> + constexpr split_buffer::~split_buffer() { + clear(); + if (front_cap()) { + alloc_traits::deallocate(get_allocator(), front_cap(), capacity()); + } + } + + template class Layout> + constexpr split_buffer::split_buffer(split_buffer&& c) noexcept( + std::is_nothrow_move_constructible_v + ) + : base_type(std::move(c)) { + c.reset(); + } + + template class Layout> + constexpr split_buffer::split_buffer(split_buffer&& c, const alloc_rr& a) + : base_type(a) { + if (a == c.get_allocator()) { + set_data(c.front_cap()); + set_valid_range(c.begin(), c.end()); + set_capacity(c.capacity()); + c.reset(); + } else { + auto allocation = allocate_at_least(get_allocator(), c.size()); + set_data(allocation.ptr); + set_valid_range(front_cap(), front_cap()); + set_capacity(allocation.count); + using Ip = std::move_iterator; + construct_at_end(Ip(c.begin()), Ip(c.end())); + } + } + + template class Layout> + constexpr split_buffer& + split_buffer::operator=(split_buffer&& c) noexcept( + (alloc_traits::propagate_on_container_move_assignment::value + && std::is_nothrow_move_assignable_v) + || !alloc_traits::propagate_on_container_move_assignment::value + ) { + clear(); + shrink_to_fit(); + copy_without_alloc(c); + move_assign_alloc( + c, + std::integral_constant() + ); + c.reset(); + return *this; + } + + template class Layout> + constexpr void split_buffer::swap( + split_buffer& x + ) noexcept(!alloc_traits::propagate_on_container_swap::value || std::is_nothrow_swappable_v) { + base_type::swap(x); + } + + template class Layout> + constexpr void split_buffer::shrink_to_fit() noexcept { + if (capacity() > size()) { +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + split_buffer t(size(), 0, get_allocator()); + if (t.capacity() < capacity()) { + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(end())); + t.set_sentinel(size()); + swap_without_allocator(t); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } + } + + template class Layout> + template + constexpr void split_buffer::emplace_front(Args&&... args) { + if (front_spare() == 0) { + pointer cur_end = end(); + if (back_spare() > 0) { + // The elements are pressed up against the front of the buffer: we need to move them + // back a little bit to make `emplace_front` have amortised O(1) complexity. + difference_type d = back_spare(); + d = (d + 1) / 2; + auto new_end = cur_end + d; + set_valid_range(std::move_backward(begin(), cur_end, new_end), new_end); + } else { + size_type c = std::max(2 * capacity(), 1); + split_buffer t(c, (c + 3) / 4, get_allocator()); + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(cur_end)); + base_type::swap_without_allocator(t); + } + } + + alloc_traits::construct(get_allocator(), std::to_address(begin() - 1), std::forward(args)...); + set_valid_range(begin() - 1, size() + 1); + } + + template class Layout> + template + constexpr void split_buffer::emplace_back(Args&&... args) { + pointer cur_end = end(); + if (back_spare() == 0) { + if (front_spare() > 0) { + difference_type d = front_spare(); + d = (d + 1) / 2; + cur_end = std::move(begin(), cur_end, begin() - d); + set_valid_range(begin() - d, cur_end); + } else { + size_type c = std::max(2 * capacity(), 1); + split_buffer t(c, c / 4, get_allocator()); + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(cur_end)); + base_type::swap_without_allocator(t); + } + } + + alloc_traits::construct(get_allocator(), std::to_address(cur_end), std::forward(args)...); + set_sentinel(++cur_end); + } + + template class Layout> + inline constexpr void + swap(split_buffer& x, split_buffer& y) noexcept( + noexcept(x.swap(y)) + ) { + x.swap(y); + } +} // namespace plg diff --git a/test/cross_call_master/external/plugify/include/plg/string.hpp b/test/cross_call_master/external/plugify/include/plg/string.hpp index 830f168..3613b95 100644 --- a/test/cross_call_master/external/plugify/include/plg/string.hpp +++ b/test/cross_call_master/external/plugify/include/plg/string.hpp @@ -1,1692 +1,3608 @@ -#pragma once - -// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc -#if PLUGIFY_COMPILER_CLANG -# pragma clang system_header -#elif PLUGIFY_COMPILER_GCC -# pragma GCC system_header -#endif +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// -#include // for std::initializer_list -#include // for std::basic_string_view -#include // for std::is_constant_evaluated, std::declval, std::false_type -#include // for std::min, std::max -#include // for std::unsigned_integral, std::signed_integral -#include // for std::distance, std::next, std::iterator_traits, std::input_iterator -#include // for std::move, std::hash -#include // for std::strong_ordering -#include // for std::allocator, std::swap, std::allocator_traits -#include // for std::numeric_limits -#include // for std::to_chars +#pragma once +// clang-format off + +/* + string synopsis + +#include +#include + +namespace std +{ + +template +class fpos +{ +private: + stateT st; +public: + fpos(streamoff = streamoff()); + + operator streamoff() const; + + stateT state() const; + void state(stateT); + + fpos& operator+=(streamoff); + fpos operator+ (streamoff) const; + fpos& operator-=(streamoff); + fpos operator- (streamoff) const; +}; + +template streamoff operator-(const fpos& x, const fpos& y); + +template bool operator==(const fpos& x, const fpos& y); +template bool operator!=(const fpos& x, const fpos& y); + +template +struct char_traits +{ + using char_type = charT; + using int_type = ...; + using off_type = streamoff; + using pos_type = streampos; + using state_type = mbstate_t; + using comparison_category = strong_ordering; // Since C++20 only for the specializations + // char, wchar_t, char8_t, char16_t, and char32_t. + + static void assign(char_type& c1, const char_type& c2) noexcept; + static constexpr bool eq(char_type c1, char_type c2) noexcept; + static constexpr bool lt(char_type c1, char_type c2) noexcept; + + static int compare(const char_type* s1, const char_type* s2, size_t n); + static size_t length(const char_type* s); + static const char_type* find(const char_type* s, size_t n, const char_type& a); + static char_type* move(char_type* s1, const char_type* s2, size_t n); + static char_type* copy(char_type* s1, const char_type* s2, size_t n); + static char_type* assign(char_type* s, size_t n, char_type a); + + static constexpr int_type not_eof(int_type c) noexcept; + static constexpr char_type to_char_type(int_type c) noexcept; + static constexpr int_type to_int_type(char_type c) noexcept; + static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept; + static constexpr int_type eof() noexcept; +}; + +template <> struct char_traits; +template <> struct char_traits; +template <> struct char_traits; // C++20 +template <> struct char_traits; +template <> struct char_traits; + +template, class Allocator = allocator > +class basic_string +{ +public: +// types: + typedef traits traits_type; + typedef typename traits_type::char_type value_type; + typedef Allocator allocator_type; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef implementation-defined iterator; + typedef implementation-defined const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static const size_type npos = -1; + + basic_string() + noexcept(std::is_nothrow_default_constructible::value); // constexpr since C++20 + explicit basic_string(const allocator_type& a); // constexpr since C++20 + basic_string(const basic_string& str); // constexpr since C++20 + basic_string(basic_string&& str) + noexcept(std::is_nothrow_move_constructible::value); // constexpr since C++20 + basic_string(const basic_string& str, size_type pos, + const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(const basic_string& str, size_type pos, size_type n, + const Allocator& a = Allocator()); // constexpr since C++20 + constexpr basic_string( + basic_string&& str, size_type pos, const Allocator& a = Allocator()); // since C++23 + constexpr basic_string( + basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); // since C++23 + template + basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); // C++17, constexpr since C++20 + template + explicit basic_string(const T& t, const Allocator& a = Allocator()); // C++17, constexpr since C++20 + basic_string(const value_type* s, const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(const value_type* s, size_type n, const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(nullptr_t) = delete; // C++23 + basic_string(size_type n, value_type c, const allocator_type& a = allocator_type()); // constexpr since C++20 + template + basic_string(InputIterator begin, InputIterator end, + const allocator_type& a = allocator_type()); // constexpr since C++20 + template R> + constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); // since C++23 + basic_string(std::initializer_list, const Allocator& = Allocator()); // constexpr since C++20 + basic_string(const basic_string&, const Allocator&); // constexpr since C++20 + basic_string(basic_string&&, const Allocator&); // constexpr since C++20 + + ~basic_string(); // constexpr since C++20 + + operator std::basic_string_view() const noexcept; // constexpr since C++20 + + basic_string& operator=(const basic_string& str); // constexpr since C++20 + template + basic_string& operator=(const T& t); // C++17, constexpr since C++20 + basic_string& operator=(basic_string&& str) + noexcept( + allocator_type::propagate_on_container_move_assignment::value || + allocator_type::is_always_equal::value ); // C++17, constexpr since C++20 + basic_string& operator=(const value_type* s); // constexpr since C++20 + basic_string& operator=(nullptr_t) = delete; // C++23 + basic_string& operator=(value_type c); // constexpr since C++20 + basic_string& operator=(std::initializer_list); // constexpr since C++20 + + iterator begin() noexcept; // constexpr since C++20 + const_iterator begin() const noexcept; // constexpr since C++20 + iterator end() noexcept; // constexpr since C++20 + const_iterator end() const noexcept; // constexpr since C++20 + + reverse_iterator rbegin() noexcept; // constexpr since C++20 + const_reverse_iterator rbegin() const noexcept; // constexpr since C++20 + reverse_iterator rend() noexcept; // constexpr since C++20 + const_reverse_iterator rend() const noexcept; // constexpr since C++20 + + const_iterator cbegin() const noexcept; // constexpr since C++20 + const_iterator cend() const noexcept; // constexpr since C++20 + const_reverse_iterator crbegin() const noexcept; // constexpr since C++20 + const_reverse_iterator crend() const noexcept; // constexpr since C++20 + + size_type size() const noexcept; // constexpr since C++20 + size_type length() const noexcept; // constexpr since C++20 + size_type max_size() const noexcept; // constexpr since C++20 + size_type capacity() const noexcept; // constexpr since C++20 + + void resize(size_type n, value_type c); // constexpr since C++20 + void resize(size_type n); // constexpr since C++20 + + template + constexpr void resize_and_overwrite(size_type n, Operation op); // since C++23 + + void reserve(size_type res_arg); // constexpr since C++20 + void reserve(); // deprecated in C++20, removed in C++26 + void shrink_to_fit(); // constexpr since C++20 + void clear() noexcept; // constexpr since C++20 + bool empty() const noexcept; // constexpr since C++20 + + const_reference operator[](size_type pos) const; // constexpr since C++20 + reference operator[](size_type pos); // constexpr since C++20 + + const_reference at(size_type n) const; // constexpr since C++20 + reference at(size_type n); // constexpr since C++20 + + basic_string& operator+=(const basic_string& str); // constexpr since C++20 + template + basic_string& operator+=(const T& t); // C++17, constexpr since C++20 + basic_string& operator+=(const value_type* s); // constexpr since C++20 + basic_string& operator+=(value_type c); // constexpr since C++20 + basic_string& operator+=(std::initializer_list); // constexpr since C++20 + + basic_string& append(const basic_string& str); // constexpr since C++20 + template + basic_string& append(const T& t); // C++17, constexpr since C++20 + basic_string& append(const basic_string& str, size_type pos, size_type n=npos); // C++14, constexpr since C++20 + template + basic_string& append(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 + basic_string& append(const value_type* s, size_type n); // constexpr since C++20 + basic_string& append(const value_type* s); // constexpr since C++20 + basic_string& append(size_type n, value_type c); // constexpr since C++20 + template + basic_string& append(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& append_range(R&& rg); // C++23 + basic_string& append(std::initializer_list); // constexpr since C++20 + + void push_back(value_type c); // constexpr since C++20 + void pop_back(); // constexpr since C++20 + reference front(); // constexpr since C++20 + const_reference front() const; // constexpr since C++20 + reference back(); // constexpr since C++20 + const_reference back() const; // constexpr since C++20 + + basic_string& assign(const basic_string& str); // constexpr since C++20 + template + basic_string& assign(const T& t); // C++17, constexpr since C++20 + basic_string& assign(basic_string&& str); // constexpr since C++20 + basic_string& assign(const basic_string& str, size_type pos, size_type n=npos); // C++14, constexpr since C++20 + template + basic_string& assign(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 + basic_string& assign(const value_type* s, size_type n); // constexpr since C++20 + basic_string& assign(const value_type* s); // constexpr since C++20 + basic_string& assign(size_type n, value_type c); // constexpr since C++20 + template + basic_string& assign(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& assign_range(R&& rg); // C++23 + basic_string& assign(std::initializer_list); // constexpr since C++20 + + basic_string& insert(size_type pos1, const basic_string& str); // constexpr since C++20 + template + basic_string& insert(size_type pos1, const T& t); // constexpr since C++20 + basic_string& insert(size_type pos1, const basic_string& str, + size_type pos2, size_type n2=npos); // constexpr since C++20 + template + basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n=npos); // C++17, constexpr since C++20 + basic_string& insert(size_type pos, const value_type* s, size_type n=npos); // C++14, constexpr since C++20 + basic_string& insert(size_type pos, const value_type* s); // constexpr since C++20 + basic_string& insert(size_type pos, size_type n, value_type c); // constexpr since C++20 + iterator insert(const_iterator p, value_type c); // constexpr since C++20 + iterator insert(const_iterator p, size_type n, value_type c); // constexpr since C++20 + template + iterator insert(const_iterator p, InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr iterator insert_range(const_iterator p, R&& rg); // C++23 + iterator insert(const_iterator p, std::initializer_list); // constexpr since C++20 + + basic_string& erase(size_type pos = 0, size_type n = npos); // constexpr since C++20 + iterator erase(const_iterator position); // constexpr since C++20 + iterator erase(const_iterator first, const_iterator last); // constexpr since C++20 + + basic_string& replace(size_type pos1, size_type n1, const basic_string& str); // constexpr since C++20 + template + basic_string& replace(size_type pos1, size_type n1, const T& t); // C++17, constexpr since C++20 + basic_string& replace(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2=npos); // C++14, constexpr since C++20 + template + basic_string& replace(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2=npos); // C++17, constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, const value_type* s, size_type n2); // constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, const value_type* s); // constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str); // constexpr since C++20 + template + basic_string& replace(const_iterator i1, const_iterator i2, const T& t); // C++17, constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, size_type n, value_type c); // constexpr since C++20 + template + basic_string& replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2); // constexpr since C++20 + template R> + constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); // C++23 + basic_string& replace(const_iterator i1, const_iterator i2, std::initializer_list); // constexpr since C++20 + + size_type copy(value_type* s, size_type n, size_type pos = 0) const; // constexpr since C++20 + basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr in C++20, removed in C++23 + basic_string substr(size_type pos = 0, size_type n = npos) const&; // since C++23 + constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; // since C++23 + void swap(basic_string& str) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); // C++17, constexpr since C++20 + + const value_type* c_str() const noexcept; // constexpr since C++20 + const value_type* data() const noexcept; // constexpr since C++20 + value_type* data() noexcept; // C++17, constexpr since C++20 + + allocator_type get_allocator() const noexcept; // constexpr since C++20 + + size_type find(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type rfind(const T& t, size_type pos = npos) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type rfind(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type rfind(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type rfind(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find_first_of(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_first_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_first_of(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find_first_of(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type find_last_of(const T& t, size_type pos = npos) const noexcept noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_last_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_last_of(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type find_last_of(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_first_not_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_first_not_of(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_last_not_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_last_not_of(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + int compare(const basic_string& str) const noexcept; // constexpr since C++20 + template + int compare(const T& t) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + int compare(size_type pos1, size_type n1, const basic_string& str) const; // constexpr since C++20 + template + int compare(size_type pos1, size_type n1, const T& t) const; // C++17, constexpr since C++20 + int compare(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2=npos) const; // C++14, constexpr since C++20 + template + int compare(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2=npos) const; // C++17, constexpr since C++20 + int compare(const value_type* s) const noexcept; // constexpr since C++20 + int compare(size_type pos1, size_type n1, const value_type* s) const; // constexpr since C++20 + int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; // constexpr since C++20 + + constexpr bool starts_with(std::basic_string_view sv) const noexcept; // C++20 + constexpr bool starts_with(charT c) const noexcept; // C++20 + constexpr bool starts_with(const charT* s) const; // C++20 + constexpr bool ends_with(std::basic_string_view sv) const noexcept; // C++20 + constexpr bool ends_with(charT c) const noexcept; // C++20 + constexpr bool ends_with(const charT* s) const; // C++20 + + constexpr bool contains(std::basic_string_view sv) const noexcept; // C++23 + constexpr bool contains(charT c) const noexcept; // C++23 + constexpr bool contains(const charT* s) const; // C++23 +}; + +template::value_type>> +basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string::value_type, + char_traits::value_type>, + Allocator>; // C++17 + +template>> + basic_string(from_range_t, R&&, Allocator = Allocator()) + -> basic_string, char_traits>, + Allocator>; // C++23 + +template> + explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) + -> basic_string; // C++17 + +template> + basic_string(std::basic_string_view, + typename see below::size_type, typename see below::size_type, + const Allocator& = Allocator()) + -> basic_string; // C++17 + +template +basic_string +operator+(const basic_string& lhs, + const basic_string& rhs); // constexpr since C++20 + +template +basic_string +operator+(const charT* lhs , const basic_string&rhs); // constexpr since C++20 + +template +basic_string +operator+(charT lhs, const basic_string& rhs); // constexpr since C++20 + +template +basic_string +operator+(const basic_string& lhs, const charT* rhs); // constexpr since C++20 + +template +basic_string +operator+(const basic_string& lhs, charT rhs); // constexpr since C++20 + +template + constexpr basic_string + operator+(const basic_string& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(basic_string&& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + const basic_string& rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + basic_string&& rhs); // Since C++26 + + +template +bool operator==(const basic_string& lhs, + const basic_string& rhs) noexcept; // constexpr since C++20 + +template +bool operator==(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator==(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 + +template +bool operator!=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator!=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator!=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator< (const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator< (const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator< (const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator> (const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator> (const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator> (const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator<=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator<=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator<=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator>=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator>=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator>=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const basic_string& rhs) noexcept; + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const charT* rhs) noexcept; + +template +void swap(basic_string& lhs, + basic_string& rhs) + noexcept(noexcept(lhs.swap(rhs))); // constexpr since C++20 + +template +std::basic_istream& +operator>>(std::basic_istream& is, basic_string& str); + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const basic_string& str); + +template +std::basic_istream& +getline(std::basic_istream& is, basic_string& str, + charT delim); + +template +std::basic_istream& +getline(std::basic_istream& is, basic_string& str); + +template +constexpr typename basic_string::size_type +erase(basic_string& c, const U& value); // C++20 +template +constexpr typename basic_string::size_type +erase_if(basic_string& c, Predicate pred); // C++20 + +typedef basic_string string; +typedef basic_string wstring; +typedef basic_string u8string; // C++20 +typedef basic_string u16string; +typedef basic_string u32string; + +int stoi (const string& str, size_t* idx = nullptr, int base = 10); +long stol (const string& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul (const string& str, size_t* idx = nullptr, int base = 10); +long long stoll (const string& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10); + +float stof (const string& str, size_t* idx = nullptr); +double stod (const string& str, size_t* idx = nullptr); +long double stold(const string& str, size_t* idx = nullptr); + +string to_string(int val); +string to_string(unsigned val); +string to_string(long val); +string to_string(unsigned long val); +string to_string(long long val); +string to_string(unsigned long long val); +string to_string(float val); +string to_string(double val); +string to_string(long double val); + +int stoi (const wstring& str, size_t* idx = nullptr, int base = 10); +long stol (const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul (const wstring& str, size_t* idx = nullptr, int base = 10); +long long stoll (const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10); + +float stof (const wstring& str, size_t* idx = nullptr); +double stod (const wstring& str, size_t* idx = nullptr); +long double stold(const wstring& str, size_t* idx = nullptr); + +wstring to_wstring(int val); +wstring to_wstring(unsigned val); +wstring to_wstring(long val); +wstring to_wstring(unsigned long val); +wstring to_wstring(long long val); +wstring to_wstring(unsigned long long val); +wstring to_wstring(float val); +wstring to_wstring(double val); +wstring to_wstring(long double val); + +template <> struct hash; +template <> struct hash; // C++20 +template <> struct hash; +template <> struct hash; +template <> struct hash; + +basic_string operator""s( const char *str, size_t len ); // C++14, constexpr since C++20 +basic_string operator""s( const wchar_t *str, size_t len ); // C++14, constexpr since C++20 +constexpr basic_string operator""s( const char8_t *str, size_t len ); // C++20 +basic_string operator""s( const char16_t *str, size_t len ); // C++14, constexpr since C++20 +basic_string operator""s( const char32_t *str, size_t len ); // C++14, constexpr since C++20 + +} // std + +*/ + +// clang-format on + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#if PLUGIFY_STRING_CONTAINERS_RANGES && (__cplusplus <= 202002L || !__has_include() || !defined(__cpp_lib_containers_ranges)) -# undef PLUGIFY_STRING_CONTAINERS_RANGES -# define PLUGIFY_STRING_CONTAINERS_RANGES 0 -#endif - -#if PLUGIFY_STRING_CONTAINERS_RANGES -# include -#endif - -#ifndef PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS -# include -#endif +#include "plg/allocator.hpp" +#include "plg/guards.hpp" +#include "plg/concepts.hpp" #ifndef PLUGIFY_STRING_NO_STD_FORMAT #include "plg/format.hpp" #endif -#include "plg/allocator.hpp" +// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc +#if PLUGIFY_COMPILER_CLANG +# pragma clang system_header +#elif PLUGIFY_COMPILER_GCC +# pragma GCC system_header +#endif +// from https://github.com/llvm/llvm-project/blob/main/libcxx/include/string namespace plg { - namespace detail { - template - concept is_allocator = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; + // basic_string + template + class basic_string; - template - concept is_char_traits = requires { - // Required type definitions - typename Traits::char_type; - typename Traits::int_type; - typename Traits::off_type; - typename Traits::pos_type; - typename Traits::state_type; - } && requires( - typename Traits::char_type c1, - typename Traits::char_type c2, - typename Traits::char_type& cr, - const typename Traits::char_type& ccr, - typename Traits::char_type* p, - const typename Traits::char_type* cp, - typename Traits::int_type i1, - typename Traits::int_type i2, - std::size_t n - ) { - // Character operations - { Traits::assign(cr, ccr) } -> std::same_as; - { Traits::eq(ccr, ccr) } -> std::convertible_to; - { Traits::lt(ccr, ccr) } -> std::convertible_to; - - // String operations - { Traits::compare(cp, cp, n) } -> std::convertible_to; - { Traits::length(cp) } -> std::convertible_to; - { Traits::find(cp, n, ccr) } -> std::convertible_to; - - // Memory operations - { Traits::move(p, cp, n) } -> std::same_as; - { Traits::copy(p, cp, n) } -> std::same_as; - { Traits::assign(p, n, c1) } -> std::same_as; - - // int_type operations - { Traits::not_eof(i1) } -> std::same_as; - { Traits::to_char_type(i1) } -> std::same_as; - { Traits::to_int_type(c1) } -> std::same_as; - { Traits::eq_int_type(i1, i2) } -> std::convertible_to; - { Traits::eof() } -> std::same_as; - }; + template + constexpr basic_string concatenate_strings( + const Allocator& alloc, + std::type_identity_t> str1, + std::type_identity_t> str2 + ); - struct uninitialized_size_tag {}; + template + inline const bool string_is_trivial_iterator_v = false; - template - constexpr bool dependent_false = false; + template + concept string_is_trivial_iterator = std::is_arithmetic_v; -#if PLUGIFY_STRING_CONTAINERS_RANGES - template - concept string_compatible_range = std::ranges::input_range && std::convertible_to, Type>; -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + concept string_view_convertible = std::is_convertible_v> && !std::is_convertible_v; - } // namespace detail + // second concept = the above, but exclude std::basic_string itself + template + concept string_view_convertible_with_exceptiom = string_view_convertible && !std::is_same_v, basic_string>; - // basic_string - // based on implementations from libc++, libstdc++ and Microsoft STL - template, detail::is_allocator Allocator = plg::allocator> + template + concept string_like = requires(T v) { + { std::string_view(v) }; + }; + + template + struct padding { + char _pad[N]; + }; + + template <> + struct padding<0> {}; + + struct uninitialized_size_tag {}; + + struct init_with_sentinel_tag {}; + + template , class Allocator = allocator> class basic_string { - private: - using allocator_traits = std::allocator_traits; public: + // using self = std::basic_string; + using self_view = std::basic_string_view; using traits_type = Traits; - using value_type = typename traits_type::char_type; + using value_type = CharT; using allocator_type = Allocator; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; + using alloc_traits = std::allocator_traits; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; using reference = value_type&; using const_reference = const value_type&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + + // A basic_string contains the following members which may be trivially relocatable: + // - pointer: is currently assumed to be trivially relocatable, but is still checked in case + // that changes + // - size_type: is always trivially relocatable, since it has to be an integral type + // - value_type: is always trivially relocatable, since it has to be trivial + // - unsigned char: is a fundamental type, so it's trivially relocatable + // - allocator_type: may or may not be trivially relocatable, so it's checked + // + // This string implementation doesn't contain any references into itself. It only contains a + // bit that says whether it is in small or large string mode, so the entire structure is + // trivially relocatable if its members are. +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + // When compiling with AddressSanitizer (ASan), basic_string cannot be trivially + // relocatable. Because the object's memory might be poisoned when its content + // is kept inside objects memory (short string optimization), instead of in allocated + // external memory. In such cases, the destructor is responsible for unpoisoning + // the memory to avoid triggering false positives. + // Therefore it's crucial to ensure the destructor is called. + // + // However, it is replaceable since implementing move-assignment as a destroy + + // move-construct will maintain the right ASAN state. + using trivially_relocatable = void; +#else + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value, + basic_string, + void>; +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + +#if PLUGIFY_INSTRUMENTED_WITH_ASAN && __has_cpp_attribute(__no_sanitize__) +# define PLUGIFY_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address"))) +// This macro disables AddressSanitizer (ASan) instrumentation for a specific function, +// allowing memory accesses that would normally trigger ASan errors to proceed without crashing. +// This is useful for accessing parts of objects memory, which should not be accessed, +// such as unused bytes in short strings, that should never be accessed +// by other parts of the program. +#else +# define PLUGIFY_INTERNAL_MEMORY_ACCESS +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + constexpr pointer asan_volatile_wrapper(pointer const& ptr) const { + if (std::is_constant_evaluated()) { + return ptr; + } + + volatile pointer copy_ptr = ptr; + + return const_cast(copy_ptr); + } + + constexpr const_pointer asan_volatile_wrapper(const const_pointer& ptr) const { + if (std::is_constant_evaluated()) { + return ptr; + } + + volatile const_pointer copy_ptr = ptr; + + return const_cast(copy_ptr); + } + +# define PLUGIFY_ASAN_VOLATILE_WRAPPER(PTR) asan_volatile_wrapper(PTR) +#else +# define PLUGIFY_ASAN_VOLATILE_WRAPPER(PTR) PTR +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + + static_assert(!std::is_array_v, "Character type of basic_string must not be an array"); + static_assert( + std::is_standard_layout_v, + "Character type of basic_string must be standard-layout" + ); + static_assert( + std::is_trivially_default_constructible_v, + "Character type of basic_string must be trivially default constructible" + ); + static_assert( + std::is_trivially_copyable_v, + "Character type of basic_string must be trivially copyable" + ); + static_assert( + std::is_same_v, + "traits_type::char_type must be the same type as CharT" + ); + static_assert( + std::is_same_v, + "Allocator::value_type must be same type as value_type" + ); + // static_assert(std::check_valid_allocator::value, ""); + using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - using sview_type = std::basic_string_view; - constexpr static size_type npos = static_cast(-1); + using alloc_result = allocation_result; private: - constexpr static auto _terminator = value_type(); - - PLUGIFY_NO_UNIQUE_ADDRESS - allocator_type _allocator; + static constexpr int char_bit = std::numeric_limits::digits + std::numeric_limits::is_signed; + static_assert(char_bit == 8, "This implementation assumes that one byte contains 8 bits"); - PLUGIFY_WARN_PUSH() + struct long_ { + constexpr long_() = default; -#if PLUGIFY_COMPILER_CLANG - PLUGIFY_WARN_IGNORE("-Wgnu-anonymous-struct") - PLUGIFY_WARN_IGNORE("-Wzero-length-array") -#elif PLUGIFY_COMPILER_GCC - PLUGIFY_WARN_IGNORE("-Wpedantic") -#elif PLUGIFY_COMPILER_MSVC - PLUGIFY_WARN_IGNORE(4201) - PLUGIFY_WARN_IGNORE(4200) -#endif + constexpr long_(alloc_result alloc, size_type size) + : _data(alloc.ptr) + , _size(size) + , _cap(alloc.count / endian_factor) + , _is_long(true) { + PLUGIFY_ASSERT(!fits_in_sso(alloc.count), "Long capacity should always be larger than the SSO"); + } - template - struct padding { - [[maybe_unused]] uint8_t pad[sizeof(CharT) - 1]; + pointer _data; + size_type _size; + size_type _cap : sizeof(size_type) * char_bit - 1; + size_type _is_long : 1; }; - template - struct padding { - // template specialization to remove the padding structure to avoid warnings on zero length arrays - // also, this allows us to take advantage of the empty-base-class optimization. - }; + static constexpr size_type min_cap = ((sizeof(long_) - 1) / sizeof(value_type) > 2 ? (sizeof(long_) - 1) / sizeof(value_type) : 2) + 1; - // size must correspond to the last byte of long_data.cap, so we don't want the compiler to insert - // padding after size if sizeof(value_type) != 1; Also ensures both layouts are the same size. - struct sso_size : padding { - PLUGIFY_PACK(struct { - uint8_t spare_size : 7; - uint8_t is_long : 1; - }); - }; + struct short_ { + constexpr short_() + : _data{} + , _spare_size(min_cap - 1) + , _is_long(false) { + } - static constexpr int char_bit = std::numeric_limits::digits + std::numeric_limits::is_signed; - static_assert(char_bit == 8, "assumes an 8 bit byte."); - - struct long_data { - pointer data; - size_type size; - PLUGIFY_PACK(struct { - size_type cap : sizeof(size_type) * char_bit - 1; - size_type is_long : 1; - }); + value_type _data[min_cap - 1]; + PLUGIFY_NO_UNIQUE_ADDRESS padding _padding; + uint8_t _spare_size : 7; + uint8_t _is_long : 1; }; - static constexpr size_type min_cap = (sizeof(long_data) - 1) / sizeof(value_type) > 2 ? (sizeof(long_data) - 1) / sizeof(value_type) : 2; + // The endian_factor is required because the field we use to store the size + // has one fewer bit than it would if it were not a bitfield. + // + // If the LSB is used to store the short-flag in the short string representation, + // we have to multiply the size by two when it is stored and divide it by two when + // it is loaded to make sure that we always store an even number. In the long string + // representation, we can ignore this because we can assume that we always allocate + // an even amount of value_types. + // + // If the MSB is used for the short-flag, the max_size() is numeric_limits::max() + // / 2. This does not impact the short string representation, since we never need the MSB + // for representing the size of a short string anyway. + + static constexpr size_type endian_factor = std::endian::native == std::endian::big ? 2 : 1; + + static_assert( + sizeof(short_) == (sizeof(value_type) * min_cap), + "short has an unexpected size." + ); + static_assert( + sizeof(short_) == sizeof(long_), + "short and long layout structures must be the same size" + ); + + union rep { + short_ s{}; + long_ l; + } _rep; + PLUGIFY_NO_UNIQUE_ADDRESS + allocator_type _alloc; + + // annotate the string with its size() at scope exit. The string has to be in a valid state + // at that point. + struct annotate_new_size { + basic_string& _str; - struct short_data { - value_type data[min_cap]; - sso_size size; + constexpr explicit annotate_new_size(basic_string& str) + : _str(str) { + } + + constexpr void operator()() { + _str.annotate_new(_str.size()); + } }; - PLUGIFY_WARN_POP() + // Construct a string with the given allocator and enough storage to hold `size` characters, + // but don't initialize the characters. The contents of the string, including the null + // terminator, must be initialized separately. + constexpr /*explicit*/ basic_string(uninitialized_size_tag, size_type size, const allocator_type& a) + : _alloc(a) { + init_internal_buffer(size); + } - static_assert(sizeof(short_data) == (sizeof(value_type) * (min_cap + 1)), "short has an unexpected size."); - static_assert(sizeof(short_data) == sizeof(long_data), "short and long layout structures must be the same size"); + template + constexpr basic_string(init_with_sentinel_tag, Iter first, Sent last, const allocator_type& a) + : _alloc(a) { + init_with_sentinel(std::move(first), std::move(last)); + } - union { - long_data _long; - short_data _short{}; - } _storage; + constexpr iterator make_iterator(pointer p) { + return iterator(p); + } - constexpr static bool fits_in_sso(size_type size) noexcept { - return size < min_cap; + constexpr const_iterator make_const_iterator(const_pointer p) const { + return const_iterator(p); } - constexpr void long_init() noexcept { - set_long(true); - set_long_data(nullptr); - set_long_size(0); - set_long_cap(0); + public: + static const size_type npos = static_cast(-1); + + constexpr basic_string() noexcept(std::is_nothrow_default_constructible_v) + : _rep(short_()) { + annotate_new(0); } - constexpr void short_init() noexcept { - set_long(false); - set_short_size(0); + constexpr /*explicit*/ basic_string(const allocator_type& a) noexcept + : _rep(short_()) + , _alloc(a) { + annotate_new(0); } - constexpr void default_init(size_type size) noexcept { - if (fits_in_sso(size)) - short_init(); - else - long_init(); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& str) + : _alloc(alloc_traits::select_on_container_copy_construction(str._alloc)) { + if (!str.is_long()) { + _rep = str._rep; + annotate_new(get_short_size()); + } else { + init_copy_ctor_external(std::to_address(str.get_long_pointer()), str.get_long_size()); + } } - constexpr auto& get_long_data() noexcept { - return _storage._long.data; + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS + basic_string(const basic_string& str, const allocator_type& a) + : _alloc(a) { + if (!str.is_long()) { + _rep = str._rep; + annotate_new(get_short_size()); + } else { + init_copy_ctor_external(std::to_address(str.get_long_pointer()), str.get_long_size()); + } } - constexpr const auto& get_long_data() const noexcept { - return _storage._long.data; + constexpr basic_string(basic_string&& str) noexcept + // Turning off ASan instrumentation for variable initialization with + // PLUGIFY_INTERNAL_MEMORY_ACCESS does not work consistently during + // initialization of r_, so we instead unpoison str's memory manually first. str's + // memory needs to be unpoisoned only in the case where it's a short string. + : _rep([](basic_string& s) -> decltype(s._rep)&& { + if (!s.is_long()) { + s.annotate_delete(); + } + return std::move(s._rep); + }(str)) + , _alloc(std::move(str._alloc)) { + str._rep = rep(); + str.annotate_new(0); + if (!is_long()) { + annotate_new(size()); + } } - constexpr auto& get_short_data() noexcept { - return _storage._short.data; + constexpr basic_string(basic_string&& str, const allocator_type& a) + : _alloc(a) { + if (str.is_long() && a != str._alloc) { // copy, not move + init(std::to_address(str.get_long_pointer()), str.get_long_size()); + } else { + if (std::is_constant_evaluated()) { + _rep = rep(); + } + if (!str.is_long()) { + str.annotate_delete(); + } + _rep = str._rep; + str._rep = rep(); + str.annotate_new(0); + if (!is_long() && this != std::addressof(str)) { + annotate_new(size()); + } + } } - constexpr const auto& get_short_data() const noexcept { - return _storage._short.data; + constexpr basic_string(const CharT* PLUGIFY_NO_NULL s) + requires(is_allocator) + { + PLUGIFY_ASSERT(s != nullptr, "basic_string(const char*) detected nullptr"); + init(s, traits_type::length(s)); } - constexpr void set_short_size(size_type size) noexcept { - _storage._short.size.spare_size = min_cap - (size & 0x7F); + constexpr basic_string(const CharT* PLUGIFY_NO_NULL s, const Allocator& a) + requires(is_allocator) + : _alloc(a) { + PLUGIFY_ASSERT(s != nullptr, "basic_string(const char*, allocator) detected nullptr"); + init(s, traits_type::length(s)); } - constexpr size_type get_short_size() const noexcept { - return min_cap - _storage._short.size.spare_size; + basic_string(std::nullptr_t) = delete; + + constexpr basic_string(const CharT* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "basic_string(const char*, n) detected nullptr"); + init(s, n); } - constexpr void set_long_size(size_type size) noexcept { - _storage._long.size = size; + constexpr basic_string(const CharT* s, size_type n, const Allocator& a) + : _alloc(a) { + PLUGIFY_ASSERT( + n == 0 || s != nullptr, + "basic_string(const char*, n, allocator) detected nullptr" + ); + init(s, n); } - constexpr size_type get_long_size() const noexcept { - return _storage._long.size; + constexpr basic_string(size_type n, CharT c) { + init(n, c); } - constexpr void set_long_cap(size_type cap) noexcept { - _storage._long.cap = (cap & 0x7FFFFFFFFFFFFFFF); + constexpr basic_string(basic_string&& str, size_type pos, const Allocator& alloc = Allocator()) + : basic_string(std::move(str), pos, npos, alloc) { } - constexpr size_type get_long_cap() const noexcept { - return _storage._long.cap; + constexpr basic_string( + basic_string&& str, + size_type pos, + size_type n, + const Allocator& alloc = Allocator() + ) + : _alloc(alloc) { + if (pos > str.size()) { + this->throw_out_of_range(); + } + + auto len = std::min(n, str.size() - pos); + if (alloc_traits::is_always_equal::value || alloc == str._alloc) { + move_assign(std::move(str), pos, len); + } else { + // Perform a copy because the allocators are not compatible. + init(str.data() + pos, len); + } } - constexpr void set_long_data(value_type* data) noexcept { - _storage._long.data = data; + constexpr basic_string(size_type n, CharT c, const Allocator& a) + requires(is_allocator) + : _alloc(a) { + init(n, c); } - constexpr bool is_long() const noexcept { - return _storage._long.is_long == true; + constexpr basic_string( + const basic_string& str, + size_type pos, + size_type n, + const Allocator& a = Allocator() + ) + : _alloc(a) { + size_type str_sz = str.size(); + if (pos > str_sz) { + this->throw_out_of_range(); + } + init(str.data() + pos, std::min(n, str_sz - pos)); } - constexpr void set_long(bool is_long) noexcept { - _storage._long.is_long = is_long; + constexpr basic_string(const basic_string& str, size_type pos, const Allocator& a = Allocator()) + : _alloc(a) { + size_type str_sz = str.size(); + if (pos > str_sz) { + this->throw_out_of_range(); + } + init(str.data() + pos, str_sz - pos); } - constexpr void set_size(size_type size) noexcept { - if (is_long()) - set_long_size(size); - else - set_short_size(size); + template T> + constexpr basic_string( + const T& t, + size_type pos, + size_type n, + const allocator_type& a = allocator_type() + ) + : _alloc(a) { + self_view sv0 = t; + self_view sv = sv0.substr(pos, n); + init(sv.data(), sv.size()); } - constexpr sview_type view() const noexcept { - return sview_type(data(), size()); + template T> + constexpr /*explicit*/ basic_string(const T& t) { + self_view sv = t; + init(sv.data(), sv.size()); } - constexpr void reallocate(size_type new_cap, bool copy_old) { - if (new_cap == get_long_cap()) - return; + template T> + constexpr /*explicit*/ basic_string(const T& t, const allocator_type& a) + : _alloc(a) { + self_view sv = t; + init(sv.data(), sv.size()); + } - auto old_len = get_long_size(); - auto old_cap = get_long_cap(); - auto& old_buffer = get_long_data(); + template + constexpr basic_string(InputIterator first, InputIterator last) { + init(first, last); + } - auto new_len = std::min(new_cap, old_len); - auto new_data = allocator_traits::allocate(_allocator, new_cap + 1); + template + constexpr basic_string(InputIterator first, InputIterator last, const allocator_type& a) + : _alloc(a) { + init(first, last); + } - if (old_buffer != nullptr) { - if (old_len != 0 && copy_old) - Traits::copy(new_data, old_buffer, new_len); - allocator_traits::deallocate(_allocator, old_buffer, old_cap + 1); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string(std::from_range_t, Range&& range, const allocator_type& a = allocator_type()) + : _alloc(a) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + init_with_size( + std::ranges::begin(range), + std::ranges::end(range), + std::ranges::distance(range) + ); + } else { + init_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } + } +#endif - set_long_data(new_data); - set_long_size(new_len); - set_long_cap(new_cap); + constexpr basic_string(std::initializer_list il) { + init(il.begin(), il.end()); } - constexpr void deallocate() { - if (is_long()) { - if (auto& buffer = get_long_data(); buffer != nullptr) { - allocator_traits::deallocate(_allocator, buffer, get_long_cap() + 1); - buffer = nullptr; - } - } + constexpr basic_string(std::initializer_list il, const Allocator& a) + : _alloc(a) { + init(il.begin(), il.end()); } - constexpr void grow_to(size_type new_cap) { - if (is_long() == true) { - reallocate(new_cap, true); - return; - } + inline constexpr ~basic_string() { + reset_internal_buffer(); + } - auto buffer = allocator_traits::allocate(_allocator, new_cap + 1); - auto len = get_short_size(); + constexpr operator self_view() const noexcept { + return self_view(begin(), end()); + } - Traits::copy(buffer, get_short_data(), len); - Traits::assign(buffer[len], _terminator); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string& operator=(const basic_string& str); - long_init(); - set_long_data(buffer); - set_long_size(len); - set_long_cap(new_cap); + template T> + constexpr basic_string& operator=(const T& t) { + self_view sv = t; + return assign(sv); } - constexpr void null_terminate() { - auto buffer = data(); - if (buffer == nullptr) [[unlikely]] - return; - Traits::assign(buffer[size()], _terminator); + constexpr basic_string& operator=(basic_string&& str + ) noexcept(alloc_traits::propagate_on_container_move_assignment::value) { + move_assign( + str, + std::integral_constant() + ); + return *this; } - constexpr bool addr_in_range(const_pointer ptr) const noexcept { - if (std::is_constant_evaluated()) - return false; - else - return data() <= ptr && ptr <= data() + size(); + constexpr basic_string& operator=(std::initializer_list il) { + return assign(il.begin(), il.size()); } - template - constexpr void internal_replace_impl(const F& func, size_type pos, size_type oldcount, size_type count) { - auto cap = capacity(); - auto sz = size(); + constexpr basic_string& operator=(const value_type* PLUGIFY_NO_NULL s) { + return assign(s); + } - auto rsz = sz - oldcount + count; + basic_string& operator=(std::nullptr_t) = delete; + constexpr basic_string& operator=(value_type c); - if (cap < rsz) - grow_to(rsz); + constexpr iterator begin() noexcept { + return make_iterator(get_pointer()); + } - if (oldcount != count) - Traits::move(data() + pos + count, data() + pos + oldcount, sz - pos - oldcount); + constexpr const_iterator begin() const noexcept { + return make_const_iterator(get_pointer()); + } - func(); + constexpr iterator end() noexcept { + return make_iterator(get_pointer() + size()); + } - set_size(rsz); - null_terminate(); + constexpr const_iterator end() const noexcept { + return make_const_iterator(get_pointer() + size()); } - constexpr void internal_replace(size_type pos, const_pointer str, size_type oldcount, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_replace_impl([&]() { Traits::copy(data() + pos, rstr.data(), count); }, pos, oldcount, count); - } else - internal_replace_impl([&]() { Traits::copy(data() + pos, str, count); }, pos, oldcount, count); + constexpr reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); } - constexpr void internal_replace(size_type pos, value_type ch, size_type oldcount, size_type count) { - internal_replace_impl([&]() { Traits::assign(data() + pos, count, ch); }, pos, oldcount, count); + constexpr const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); } - template - constexpr void internal_insert_impl(const F& func, size_type pos, size_type count) { - if (count == 0) [[unlikely]] - return; + constexpr reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - auto cap = capacity(); - auto sz = size(); - auto rsz = sz + count; + constexpr const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - if (cap < rsz) - grow_to(rsz); + constexpr const_iterator cbegin() const noexcept { + return begin(); + } - Traits::move(data() + pos + count, data() + pos, sz - pos); - func(); + constexpr const_iterator cend() const noexcept { + return end(); + } - set_size(rsz); - null_terminate(); + constexpr const_reverse_iterator crbegin() const noexcept { + return rbegin(); } - constexpr void internal_insert(size_type pos, const_pointer str, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_insert_impl([&]() { Traits::copy(data() + pos, rstr.data(), count); }, pos, count); - } else - internal_insert_impl([&]() { Traits::copy(data() + pos, str, count); }, pos, count); + constexpr const_reverse_iterator crend() const noexcept { + return rend(); } - constexpr void internal_insert(size_type pos, value_type ch, size_type count) { - internal_insert_impl([&]() { Traits::assign(data() + pos, count, ch); }, pos, count); + constexpr size_type size() const noexcept { + return is_long() ? get_long_size() : get_short_size(); } - template - constexpr void internal_append_impl(const F& func, size_type count) { - if (count == 0) [[unlikely]] - return; + constexpr size_type length() const noexcept { + return size(); + } - auto cap = capacity(); - auto sz = size(); - auto rsz = sz + count; + constexpr size_type max_size() const noexcept { + constexpr bool uses_lsb = endian_factor == 2; - if (cap < rsz) - grow_to(rsz); + if (size_type m = alloc_traits::max_size(_alloc); + m <= std::numeric_limits::max() / 2) { + size_type res = m - alignment; - func(sz); - set_size(rsz); - null_terminate(); - } + // When the endian_factor == 2, our string representation assumes that the capacity + // (including the null terminator) is always even, so we have to make sure the + // lowest bit isn't set when the string grows to max_size() + if constexpr (uses_lsb) { + res &= ~size_type(1); + } - constexpr void internal_append(const_pointer str, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_append_impl([&](size_type pos) { Traits::copy(data() + pos, rstr.data(), count); }, count); - } else - internal_append_impl([&](size_type pos) { Traits::copy(data() + pos, str, count); }, count); + // We have to allocate space for the null terminator, but max_size() doesn't include + // it. + return res - 1; + } else { + return uses_lsb ? m - alignment - 1 : (m / 2) - alignment - 1; + } } - constexpr void internal_append(value_type ch, size_type count) { - internal_append_impl([&](size_type pos) { Traits::assign(data() + pos, count, ch); }, count); + constexpr size_type capacity() const noexcept { + return (is_long() ? get_long_cap() : min_cap) - 1; } - template - constexpr void internal_assign_impl(const F& func, size_type size, bool copy_old) { - if (fits_in_sso(size)) { - if (is_long() == true) { - deallocate(); - short_init(); - } + constexpr void resize(size_type n, value_type c); - set_short_size(size); - func(get_short_data()); - null_terminate(); - } else { - if (is_long() == false) - long_init(); - if (get_long_cap() < size) - reallocate(size, copy_old); + constexpr void resize(size_type n) { + resize(n, value_type()); + } + + constexpr void reserve(size_type requested_capacity); - func(get_long_data()); - set_long_size(size); - null_terminate(); +#if PLUGIFY_HAS_CXX23 + /*template + constexpr void resize_and_overwrite(size_type n, Op op) { + size_type sz = size(); + size_type cap = capacity(); + if (n > cap) { + grow_by_without_replace(cap, n - cap, sz, sz, 0); } - } + annotate_delete(); + set_size(n); + annotate_new(n); + erase_to_end(std::move(op)(data(), auto(n))); + }*/ +#endif + + constexpr void shrink_to_fit() noexcept; + constexpr void clear() noexcept; - constexpr void internal_assign(const_pointer str, size_type size, bool copy_old = false) { - if (addr_in_range(str)) { - basic_string rstr(str, size); - internal_assign_impl([&](auto data) { Traits::copy(data, rstr.data(), size); }, size, copy_old); - } else - internal_assign_impl([&](auto data) { Traits::copy(data, str, size); }, size, copy_old); + [[nodiscard]] constexpr bool empty() const noexcept { + return size() == 0; } - constexpr void internal_assign(value_type ch, size_type count, bool copy_old = false) { - internal_assign_impl([&](auto data) { Traits::assign(data, count, ch); }, count, copy_old); + constexpr const_reference operator[](size_type pos) const noexcept { + PLUGIFY_ASSERT(pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(pos) && !fits_in_sso(pos)) { + return *(get_long_pointer() + pos); + } + return *(data() + pos); } - public: - explicit constexpr basic_string(detail::uninitialized_size_tag, size_type size, const Allocator& allocator) - : _allocator(allocator) { - PLUGIFY_ASSERT(size <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - if (fits_in_sso(size)) - short_init(); - else { - long_init(); - reallocate(size, false); + constexpr reference operator[](size_type pos) noexcept { + PLUGIFY_ASSERT(pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(pos) && !fits_in_sso(pos)) { + return *(get_long_pointer() + pos); } - set_size(size); + return *(get_pointer() + pos); } - constexpr basic_string() noexcept(std::is_nothrow_default_constructible::value) - : basic_string(Allocator()) {} + constexpr const_reference at(size_type n) const; + constexpr reference at(size_type n); - explicit constexpr basic_string(const Allocator& allocator) noexcept - : _allocator(allocator) { - short_init(); + constexpr basic_string& operator+=(const basic_string& str) { + return append(str); } - constexpr basic_string(size_type count, value_type ch, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(ch, count); + template T> + constexpr basic_string& operator+=(const T& t) { + self_view sv = t; + return append(sv); } - constexpr basic_string(const basic_string& str, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - auto len = std::min(count, str.size() - pos); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str.data() + pos, len); + constexpr basic_string& operator+=(const value_type* PLUGIFY_NO_NULL s) { + return append(s); } - constexpr basic_string(const basic_string& str, size_type pos, const Allocator& allocator = Allocator()) - : basic_string(str, pos, npos, allocator) {} - constexpr basic_string(const value_type* str, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str, count); + constexpr basic_string& operator+=(value_type c) { + push_back(c); + return *this; } - constexpr basic_string(const value_type* str, const Allocator& allocator = Allocator()) - : basic_string(str, Traits::length(str), allocator) {} - - template - constexpr basic_string(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - if constexpr (std::contiguous_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(first), len); - } else { - if constexpr (std::random_access_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - reserve(len); - } - for (auto it = first; it != last; ++it) { - push_back(*it); - } - } + constexpr basic_string& operator+=(std::initializer_list il) { + return append(il); } - constexpr basic_string(const basic_string& str, const Allocator& allocator) - : _allocator(allocator) { - auto len = str.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str.data(), len); + constexpr basic_string& append(const basic_string& str) { + return append(str.data(), str.size()); } - constexpr basic_string(const basic_string& str) - : basic_string(str, str.get_allocator()) {} - constexpr basic_string(basic_string&& str) noexcept(std::is_nothrow_move_constructible::value) - : _allocator(std::move(str._allocator)), _storage(std::move(str._storage)) { - str.short_init(); + template T> + constexpr basic_string& append(const T& t) { + self_view sv = t; + return append(sv.data(), sv.size()); } - constexpr basic_string(basic_string&& str, const Allocator& allocator) - : _allocator(allocator) { - if constexpr (allocator_traits::is_always_equal::value) { - std::swap(_storage, str._storage); - } else { - if (!str.is_long() || get_allocator() == str.get_allocator()) { - std::swap(_storage, str._storage); - } else { - internal_assign(str.data(), str.size()); - str.deallocate(); - } + constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); + + template T> + constexpr basic_string& append(const T& t, size_type pos, size_type n = npos) { + self_view sv = t; + size_type sz = sv.size(); + if (pos > sz) { + throw_out_of_range(); } - str.short_init(); + return append(sv.data() + pos, std::min(n, sz - pos)); } - constexpr basic_string(std::initializer_list list, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - auto len = list.size(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(list.begin()), len); + constexpr basic_string& append(const value_type* s, size_type n); + constexpr basic_string& append(const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& append(size_type n, value_type c); + + template + constexpr basic_string& append(InputIterator first, InputIterator last) { + const basic_string temp(first, last, _alloc); + append(temp.data(), temp.size()); + return *this; } - template - requires (std::is_convertible_v) - constexpr basic_string(const Type& t, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - auto sv = sview_type(t); - PLUGIFY_ASSERT(pos <= sv.length(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - auto ssv = sv.substr(pos, count); - auto len = ssv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(ssv.data(), len); + template + constexpr basic_string& append(ForwardIterator first, ForwardIterator last) { + size_type sz = size(); + size_type cap = capacity(); + size_type n = static_cast(std::distance(first, last)); + if (n == 0) { + return *this; + } + + if (string_is_trivial_iterator_v && !addr_in_range(*first)) { + if (cap - sz < n) { + grow_by_without_replace(cap, sz + n - cap, sz, sz, 0); + } + annotate_increase(n); + auto end = copy_non_overlapping_range(first, last, std::to_address(get_pointer() + sz)); + traits_type::assign(*end, value_type()); + set_size(sz + n); + return *this; + } else { + const basic_string temp(first, last, _alloc); + return append(temp.data(), temp.size()); + } } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string(const Type& t, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - sview_type sv(t); - auto len = sv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(sv.data(), len); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& append_range(Range&& range) { + insert_range(end(), std::forward(range)); + return *this; } +#endif - constexpr basic_string(basic_string&& str, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : basic_string(std::move(str), allocator) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - erase(pos, count); + constexpr basic_string& append(std::initializer_list il) { + return append(il.begin(), il.size()); } - constexpr basic_string(basic_string&& str, size_type pos, const Allocator& allocator = Allocator()) - : basic_string(std::move(str), pos, npos, allocator) {} + constexpr void push_back(value_type c); + constexpr void pop_back(); -#if __cplusplus > 202002L - basic_string(std::nullptr_t) = delete; -#endif + constexpr reference front() noexcept { + PLUGIFY_ASSERT(!empty(), "string::front(): string is empty"); + return *get_pointer(); + } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string(std::from_range_t, Range&& range, const Allocator& allocator = Allocator()) - : basic_string(std::ranges::begin(range), std::ranges::end(range), allocator) {} -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + constexpr const_reference front() const noexcept { + PLUGIFY_ASSERT(!empty(), "string::front(): string is empty"); + return *data(); + } - constexpr ~basic_string() { - deallocate(); + constexpr reference back() noexcept { + PLUGIFY_ASSERT(!empty(), "string::back(): string is empty"); + return *(get_pointer() + size() - 1); } - constexpr basic_string& operator=(const basic_string& str) { - return assign(str); + constexpr const_reference back() const noexcept { + PLUGIFY_ASSERT(!empty(), "string::back(): string is empty"); + return *(data() + size() - 1); } - constexpr basic_string& operator=(basic_string&& str) noexcept( - allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value) { - return assign(std::move(str)); + template T> + constexpr basic_string& assign(const T& t) { + self_view sv = t; + return assign(sv.data(), sv.size()); } - constexpr basic_string& operator=(const value_type* str) { - return assign(str, Traits::length(str)); + constexpr void move_assign(basic_string&& str, size_type pos, size_type len) { + // Pilfer the allocation from str. + PLUGIFY_ASSERT(_alloc == str._alloc, "move_assign called with wrong allocator"); + size_type old_sz = str.size(); + if (!str.is_long()) { + str.annotate_delete(); + } + _rep = str._rep; + str._rep = rep(); + str.annotate_new(0); + + Traits::move(data(), data() + pos, len); + set_size(len); + Traits::assign(data()[len], value_type()); + + if (!is_long()) { + annotate_new(len); + } else if (old_sz > len) { + annotate_shrink(old_sz); + } } - constexpr basic_string& operator=(value_type ch) { - return assign(std::addressof(ch), 1); + constexpr basic_string& assign(const basic_string& str) { + return *this = str; } - constexpr basic_string& operator=(std::initializer_list list) { - return assign(list.begin(), list.size()); + constexpr basic_string& + assign(basic_string&& str) noexcept(alloc_traits::propagate_on_container_move_assignment::value + ) { + *this = std::move(str); + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& operator=(const Type& t) { - sview_type sv(t); - return assign(sv); + constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); + + template T> + constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos) { + self_view sv = t; + size_type sz = sv.size(); + if (pos > sz) { + throw_out_of_range(); + } + return assign(sv.data() + pos, std::min(n, sz - pos)); } -#if __cplusplus > 202002L - constexpr basic_string& operator=(std::nullptr_t) = delete; -#endif + constexpr basic_string& assign(const value_type* s, size_type n); + constexpr basic_string& assign(const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& assign(size_type n, value_type c); - constexpr basic_string& assign(size_type count, value_type ch) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(ch, count); + template + constexpr basic_string& assign(InputIterator first, InputIterator last) { + assign_with_sentinel(first, last); return *this; } - constexpr basic_string& assign(const basic_string& str, size_type pos, size_type count = npos) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::assign(): pos out of range", std::out_of_range); - internal_assign(str.data(), std::min(count, str.size() - pos)); + template + constexpr basic_string& assign(ForwardIterator first, ForwardIterator last) { + if (string_is_trivial_iterator_v) { + size_type n = static_cast(std::distance(first, last)); + assign_trivial(first, last, n); + } else { + assign_with_sentinel(first, last); + } + return *this; } - constexpr basic_string& assign(const basic_string& str) { - if (this == &str) [[unlikely]] - return *this; +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& assign_range(Range&& range) { + if constexpr (string_is_trivial_iterator_v> + && (std::ranges::forward_range || std::ranges::sized_range) ) { + size_type n = static_cast(std::ranges::distance(range)); + assign_trivial(std::ranges::begin(range), std::ranges::end(range), n); - if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != str.get_allocator()) { - deallocate(); - short_init(); - } - } - _allocator = str._allocator; + } else { + assign_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } - internal_assign(str.data(), str.size()); return *this; } +#endif - constexpr basic_string& assign(basic_string&& str) noexcept( - allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value) { - if (this == &str) [[unlikely]] - return *this; + constexpr basic_string& assign(std::initializer_list il) { + return assign(il.begin(), il.size()); + } - if constexpr (allocator_traits::propagate_on_container_move_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != str.get_allocator()) { - deallocate(); - short_init(); - } - } - _allocator = std::move(str._allocator); + constexpr basic_string& insert(size_type pos1, const basic_string& str) { + return insert(pos1, str.data(), str.size()); + } + + template T> + constexpr basic_string& insert(size_type pos1, const T& t) { + self_view sv = t; + return insert(pos1, sv.data(), sv.size()); + } + + template T> + constexpr basic_string& + insert(size_type pos1, const T& t, size_type pos2, size_type n = npos) { + self_view sv = t; + size_type str_sz = sv.size(); + if (pos2 > str_sz) { + throw_out_of_range(); } + return insert(pos1, sv.data() + pos2, std::min(n, str_sz - pos2)); + } + + constexpr basic_string& + insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos); + constexpr basic_string& insert(size_type pos, const value_type* s, size_type n); + constexpr basic_string& insert(size_type pos, const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& insert(size_type pos, size_type n, value_type c); + constexpr iterator insert(const_iterator pos, value_type c); + +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr iterator insert_range(const_iterator position, Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + return insert_with_size(position, std::ranges::begin(range), std::ranges::end(range), n); - if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) { - deallocate(); - short_init(); - std::swap(_storage, str._storage); } else { - if (get_allocator() == str.get_allocator()) { - deallocate(); - short_init(); - std::swap(_storage, str._storage); - } else { - internal_assign(str.data(), str.size()); - } + basic_string temp(std::from_range, std::forward(range), _alloc); + return insert(position, temp.data(), temp.data() + temp.size()); } + } +#endif - return *this; + constexpr iterator insert(const_iterator pos, size_type n, value_type c) { + difference_type p = pos - begin(); + insert(static_cast(p), n, c); + return begin() + p; } - constexpr basic_string& assign(const value_type* str, size_type count) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(str, count); - return *this; + template + constexpr iterator insert(const_iterator pos, InputIterator first, InputIterator last) { + const basic_string temp(first, last, _alloc); + return insert(pos, temp.data(), temp.data() + temp.size()); } - constexpr basic_string& assign(const value_type* str) { - return assign(str, Traits::length(str)); + template + constexpr iterator insert(const_iterator pos, ForwardIterator first, ForwardIterator last) { + auto n = static_cast(std::distance(first, last)); + return insert_with_size(pos, first, last, n); } - template - constexpr basic_string& assign(InputIterator first, InputIterator last) { - if constexpr (std::contiguous_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(first), len); - } else { - if constexpr (std::random_access_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - reserve(len); - } - for (auto it = first; it != last; ++it) { - push_back(*it); - } - } - return *this; + constexpr iterator insert(const_iterator pos, std::initializer_list il) { + return insert(pos, il.begin(), il.end()); } - constexpr basic_string& assign(std::initializer_list list) { - auto len = list.size(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(list.begin()), len); - return *this; + constexpr basic_string& erase(size_type pos = 0, size_type n = npos); + constexpr iterator erase(const_iterator pos); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str) { + return replace(pos1, n1, str.data(), str.size()); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& assign(const Type& t) { - sview_type sv(t); - return assign(sv.data(), sv.length()); + template T> + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t) { + self_view sv = t; + return replace(pos1, n1, sv.data(), sv.size()); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& assign(const Type& t, size_type pos, size_type count = npos) { - auto sv = sview_type(t).substr(pos, count); - auto len = sv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - return assign(sv.data(), len); + constexpr basic_string& + replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos); + + template T> + constexpr basic_string& + replace(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) { + self_view sv = t; + size_type str_sz = sv.size(); + if (pos2 > str_sz) { + throw_out_of_range(); + } + return replace(pos1, n1, sv.data() + pos2, std::min(n2, str_sz - pos2)); } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string& assign_range(Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(str.size() <= max_size(), "plg::basic_string::assign_range(): resulted string size would exceed max_size()", std::length_error); - return assign(std::move(str)); + constexpr basic_string& + replace(size_type pos, size_type n1, const value_type* s, size_type n2); + constexpr basic_string& + replace(size_type pos, size_type n1, const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); + + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, const basic_string& str) { + return replace( + static_cast(i1 - begin()), + static_cast(i2 - i1), + str.data(), + str.size() + ); } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr allocator_type get_allocator() const noexcept { - return _allocator; + template T> + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t) { + self_view sv = t; + return replace(i1 - begin(), i2 - i1, sv); } - constexpr reference operator[](size_type pos) { - return data()[pos]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), s, n); } - constexpr const_reference operator[](size_type pos) const { - return data()[pos]; + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), s); } - constexpr reference at(size_type pos) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::at(): pos out of range", std::out_of_range); - return data()[pos]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, size_type n, value_type c) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), n, c); } - constexpr const_reference at(size_type pos) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::at(): pos out of range", std::out_of_range); - return data()[pos]; + template + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2) { + const basic_string temp(j1, j2, _alloc); + return replace(i1, i2, temp); } - constexpr reference front() { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::front(): vector is empty", std::length_error); - return data()[0]; +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& + replace_with_range(const_iterator i1, const_iterator i2, Range&& range) { + basic_string temp(std::from_range, std::forward(range), _alloc); + return replace(i1, i2, temp); } +#endif - constexpr const_reference front() const { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::front(): vector is empty", std::length_error); - return data()[0]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, std::initializer_list il) { + return replace(i1, i2, il.begin(), il.end()); } - constexpr reference back() { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::back(): vector is empty", std::length_error); - return data()[size() - 1]; + constexpr size_type copy(value_type* s, size_type n, size_type pos = 0) const; + + constexpr basic_string substr(size_type pos = 0, size_type n = npos) const& { + return basic_string(*this, pos, n); } - constexpr const_reference back() const { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::back(): vector is empty", std::length_error); - return data()[size() - 1]; + constexpr basic_string substr(size_type pos = 0, size_type n = npos) && { + return basic_string(std::move(*this), pos, n); + } + + constexpr void swap(basic_string& str) noexcept; + + // [string.ops] + // ------------ + + constexpr const value_type* c_str() const noexcept { + return data(); } constexpr const value_type* data() const noexcept { - return is_long() ? get_long_data() : get_short_data(); + return std::to_address(get_pointer()); } constexpr value_type* data() noexcept { - return is_long() ? get_long_data() : get_short_data(); + return std::to_address(get_pointer()); } - constexpr const value_type* c_str() const noexcept { - return data(); + constexpr allocator_type get_allocator() const noexcept { + return _alloc; } - constexpr operator sview_type() const noexcept { - return view(); + // find + + constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find(str.data(), pos, str.size()); } - constexpr iterator begin() noexcept { - return data(); + template T> + constexpr size_type find(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find(sv.data(), pos, sv.size()); } - constexpr const_iterator begin() const noexcept { - return data(); + constexpr size_type find(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find(): received nullptr"); + return operator self_view().find(s, pos, n); } - constexpr const_iterator cbegin() const noexcept { - return data(); + constexpr size_type + find(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find(): received nullptr"); + return operator self_view().find(s, pos, traits_type::length(s)); } - constexpr iterator end() noexcept { - return data() + size(); + constexpr size_type find(value_type c, size_type pos = 0) const noexcept { + return operator self_view().find(c, pos); } - constexpr const_iterator end() const noexcept { - return data() + size(); + // rfind + + constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().rfind(str.data(), pos, str.size()); } - constexpr const_iterator cend() const noexcept { - return data() + size(); + template T> + constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().rfind(sv.data(), pos, sv.size()); } - constexpr reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); + constexpr size_type rfind(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::rfind(): received nullptr"); + return operator self_view().rfind(s, pos, n); } - constexpr const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); + constexpr size_type + rfind(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::rfind(): received nullptr"); + return operator self_view().rfind(s, pos, traits_type::length(s)); } - constexpr const_reverse_iterator crbegin() const noexcept { - return const_reverse_iterator(cend()); + constexpr size_type rfind(value_type c, size_type pos = npos) const noexcept { + return operator self_view().rfind(c, pos); } - constexpr reverse_iterator rend() noexcept { - return reverse_iterator(begin()); + // find_first_of + + constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find_first_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find_first_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_first_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_first_of(): received nullptr"); + return operator self_view().find_first_of(s, pos, n); + } + + constexpr size_type + find_first_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_first_of(): received nullptr"); + return operator self_view().find_first_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_first_of(value_type c, size_type pos = 0) const noexcept { + return find(c, pos); + } + + // find_last_of + + constexpr size_type + find_last_of(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().find_last_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_last_of(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().find_last_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_last_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_last_of(): received nullptr"); + return operator self_view().find_last_of(s, pos, n); + } + + constexpr size_type + find_last_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_last_of(): received nullptr"); + return operator self_view().find_last_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_last_of(value_type c, size_type pos = npos) const noexcept { + return rfind(c, pos); + } + + // find_first_not_of + + constexpr size_type + find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find_first_not_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find_first_not_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_first_not_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_first_not_of(): received nullptr"); + return operator self_view().find_first_not_of(s, pos, n); + } + + constexpr size_type + find_first_not_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_first_not_of(): received nullptr"); + return operator self_view().find_first_not_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept { + return operator self_view().find_first_not_of(c, pos); + } + + // find_last_not_of + + constexpr size_type + find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().find_last_not_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().find_last_not_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_last_not_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_last_not_of(): received nullptr"); + return operator self_view().find_last_not_of(s, pos, n); + } + + constexpr size_type + find_last_not_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_last_not_of(): received nullptr"); + return operator self_view().find_last_not_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept { + return operator self_view().find_last_not_of(c, pos); + } + + // compare + + constexpr int compare(const basic_string& str) const noexcept { + return compare(self_view(str)); + } + + template T> + constexpr int compare(const T& t) const noexcept { + self_view sv = t; + size_t lhs_sz = size(); + size_t rhs_sz = sv.size(); + int result = traits_type::compare(data(), sv.data(), std::min(lhs_sz, rhs_sz)); + if (result != 0) { + return result; + } + if (lhs_sz < rhs_sz) { + return -1; + } + if (lhs_sz > rhs_sz) { + return 1; + } + return 0; + } + + template T> + constexpr int compare(size_type pos1, size_type n1, const T& t) const { + self_view sv = t; + return compare(pos1, n1, sv.data(), sv.size()); + } + + constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const { + return compare(pos1, n1, str.data(), str.size()); + } + + constexpr int compare( + size_type pos1, + size_type n1, + const basic_string& str, + size_type pos2, + size_type n2 = npos + ) const { + return compare(pos1, n1, self_view(str), pos2, n2); + } + + template T> + inline constexpr int + compare(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) const { + self_view sv = t; + return self_view(*this).substr(pos1, n1).compare(sv.substr(pos2, n2)); + } + + constexpr int compare(const value_type* PLUGIFY_NO_NULL s) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::compare(): received nullptr"); + return compare(0, npos, s, traits_type::length(s)); + } + + constexpr int + compare(size_type pos1, size_type n1, const value_type* PLUGIFY_NO_NULL s) const { + PLUGIFY_ASSERT(s != nullptr, "string::compare(): received nullptr"); + return compare(pos1, n1, s, traits_type::length(s)); + } + + constexpr int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; + + // starts_with + + constexpr bool starts_with(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).starts_with(sv); + } + + constexpr bool starts_with(value_type c) const noexcept { + return !empty() && Traits::eq(front(), c); + } + + constexpr bool starts_with(const value_type* PLUGIFY_NO_NULL s) const noexcept { + return starts_with(self_view(s)); + } + + // ends_with + + constexpr bool ends_with(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).ends_with(sv); + } + + constexpr bool ends_with(value_type c) const noexcept { + return !empty() && Traits::eq(back(), c); + } + + constexpr bool ends_with(const value_type* PLUGIFY_NO_NULL s) const noexcept { + return ends_with(self_view(s)); + } + + // contains + + constexpr bool contains(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).contains(sv); + } + + constexpr bool contains(value_type c) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).contains(c); + } + + constexpr bool contains(const value_type* PLUGIFY_NO_NULL s) const { + return self_view(typename self_view::assume_valid(), data(), size()).contains(s); + } + + [[nodiscard]] constexpr bool invariants() const; + + private: + [[nodiscard]] constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS bool is_long() const noexcept { + if (std::is_constant_evaluated() && __builtin_constant_p(_rep.l._is_long)) { + return _rep.l._is_long; + } + return _rep.s._is_long; + } + + static constexpr bool fits_in_sso(size_type sz) { + return sz < min_cap; + } + + template + constexpr void assign_trivial(Iterator first, Sentinel last, size_type n); + + template + constexpr void assign_with_sentinel(Iterator first, Sentinel last); + + // Copy [first, last) into [dest, dest + (last - first)). Assumes that the ranges don't + // overlap. + template + static constexpr value_type* + copy_non_overlapping_range(ForwardIter first, Sent last, value_type* dest) { + if constexpr (std::contiguous_iterator + && std::is_same_v> + && std::is_same_v) { + PLUGIFY_ASSERT( + !is_overlapping_range(std::to_address(first), std::to_address(last), dest), + "copy_non_overlapping_range called with an overlapping range!" + ); + traits_type::copy(dest, std::to_address(first), last - first); + return dest + (last - first); + } else { + for (; first != last; ++first) { + traits_type::assign(*dest++, *first); + } + return dest; + } + } + + template + constexpr iterator + insert_from_safe_copy(size_type n, size_type ip, ForwardIterator first, Sentinel last) { + size_type sz = size(); + size_type cap = capacity(); + value_type* p; + if (cap - sz >= n) { + annotate_increase(n); + p = std::to_address(get_pointer()); + size_type n_move = sz - ip; + if (n_move != 0) { + traits_type::move(p + ip + n, p + ip, n_move); + } + } else { + grow_by_without_replace(cap, sz + n - cap, sz, ip, 0, n); + p = std::to_address(get_long_pointer()); + } + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + copy_non_overlapping_range(std::move(first), std::move(last), p + ip); + + return begin() + ip; + } + + template + constexpr iterator + insert_with_size(const_iterator pos, Iterator first, Sentinel last, size_type n); + + // internal buffer accessors + // ------------------------- + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void set_short_size(size_type s) noexcept { + PLUGIFY_ASSERT( + s < min_cap, + "s should never be greater than or equal to the short string capacity" + ); + _rep.s._spare_size = (min_cap - 1) - s; + _rep.s._is_long = false; + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS size_type get_short_size() const noexcept { + PLUGIFY_ASSERT(!_rep.s._is_long, "String has to be short when trying to get the short size"); + return (min_cap - 1) - _rep.s._spare_size; + } + + constexpr void set_long_size(size_type s) noexcept { + _rep.l._size = s; + } + + constexpr size_type get_long_size() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long size"); + return _rep.l._size; + } + + constexpr void set_size(size_type s) noexcept { + if (is_long()) { + set_long_size(s); + } else { + set_short_size(s); + } } - constexpr const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); + constexpr size_type get_long_cap() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long capacity"); + return _rep.l._cap * endian_factor; + } + + constexpr pointer get_long_pointer() noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long pointer"); + return PLUGIFY_ASAN_VOLATILE_WRAPPER(_rep.l._data); + } + + constexpr const_pointer get_long_pointer() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long pointer"); + return PLUGIFY_ASAN_VOLATILE_WRAPPER(_rep.l._data); + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS pointer get_short_pointer() noexcept { + return PLUGIFY_ASAN_VOLATILE_WRAPPER( + std::pointer_traits::pointer_to(_rep.s._data[0]) + ); + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS const_pointer get_short_pointer() const noexcept { + return PLUGIFY_ASAN_VOLATILE_WRAPPER( + std::pointer_traits::pointer_to(_rep.s._data[0]) + ); + } + + constexpr pointer get_pointer() noexcept { + return is_long() ? get_long_pointer() : get_short_pointer(); + } + + constexpr const_pointer get_pointer() const noexcept { + return is_long() ? get_long_pointer() : get_short_pointer(); + } + + // Internal buffer management + // -------------------------- + // + // These functions are only responsible for managing the buffer itself, not the value inside + // the buffer. As such, none of these facilities ensure that there is a null terminator at + // `data()[size()]`. + + // Allocate a buffer of capacity size with alloc and return it + static constexpr long_ allocate_long_buffer(Allocator& alloc, size_type capacity) { + auto buffer = allocate_at_least(alloc, recommend(capacity) + 1); + + if (std::is_constant_evaluated()) { + for (size_type i = 0; i != buffer.count; ++i) { + std::construct_at(std::addressof(buffer.ptr[i])); + } + } + + return long_(buffer, capacity); + } + + // Deallocate the long buffer if it exists and clear the short buffer so we are an empty + // string + constexpr void reset_internal_buffer() { + annotate_delete(); + if (is_long()) { + alloc_traits::deallocate(_alloc, get_long_pointer(), get_long_cap()); + } + _rep.s = short_(); + } + + // Replace the current buffer with alloc; the first size elements constitute a string + constexpr void replace_internal_buffer(long_ alloc) { + reset_internal_buffer(); + _rep.l = alloc; + } + + // Initialize the internal buffer to hold size elements + // The elements and null terminator have to be set by the caller + constexpr pointer init_internal_buffer(size_type size) { + if (std::is_constant_evaluated()) { + _rep = rep(); + } + + if (size > max_size()) { + throw_length_error(); + } + + if (fits_in_sso(size)) { + set_short_size(size); + annotate_new(size); + return get_short_pointer(); + } else { + _rep.l = allocate_long_buffer(_alloc, size); + annotate_new(size); + return get_long_pointer(); + } + } + + // ASan annotation helpers + // ----------------------- + + // The following functions are no-ops outside of AddressSanitizer mode. + constexpr void annotate_contiguous_container( + const void* old_mid, + const void* new_mid + ) const { + if (!is_long()) { + return; + } + + plg::annotate_contiguous_container( + data(), + data() + capacity() + 1, + old_mid, + new_mid + ); } - constexpr const_reverse_iterator crend() const noexcept { - return const_reverse_iterator(cbegin()); + constexpr void annotate_new(size_type current_size) const noexcept { + annotate_contiguous_container(data() + capacity() + 1, data() + current_size + 1); } - constexpr bool empty() const noexcept { - return size() == 0; + constexpr void annotate_delete() const noexcept { + annotate_contiguous_container(data() + size() + 1, data() + capacity() + 1); } - constexpr size_type size() const noexcept { - return is_long() ? get_long_size() : get_short_size(); + constexpr void annotate_increase(size_type n) const noexcept { + annotate_contiguous_container(data() + size() + 1, data() + size() + 1 + n); } - constexpr size_type length() const noexcept { - return size(); + constexpr void annotate_shrink(size_type old_size) const noexcept { + annotate_contiguous_container(data() + old_size + 1, data() + size() + 1); } - constexpr size_type max_size() const noexcept { - // const size_type alignment = 16; - // size_type m = allocator_traits::max_size(_allocator); - // if (m <= std::numeric_limits::max() / 2) - // return m - alignment; - // else - //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; - return (allocator_traits::max_size(_allocator) - 1) / 2; - } + // Disable ASan annotations and enable them again when going out of scope. It is assumed + // that the string is in a valid state at that point, so `size()` can be called safely. + struct [[nodiscard]] annotation_guard { + annotation_guard(const annotation_guard&) = delete; + annotation_guard& operator=(const annotation_guard&) = delete; - constexpr size_type capacity() const noexcept { - return is_long() ? get_long_cap() : min_cap; - } + constexpr annotation_guard(basic_string& str) + : str(str) { + str.annotate_delete(); + } - constexpr void reserve(size_type cap) { - PLUGIFY_ASSERT(cap <= max_size(), "plg::basic_string::reserve(): allocated memory size would exceed max_size()", std::length_error); - if (cap <= capacity()) - return; + constexpr ~annotation_guard() { + str.annotate_new(str.size()); + } - auto new_cap = std::max(cap, size()); - if (new_cap == capacity()) - return; + basic_string& str; + }; - grow_to(new_cap); + template + static constexpr size_type align_it(size_type s) noexcept { + return (s + (a - 1)) & ~(a - 1); } - void reserve() { - shrink_to_fit(); - } + enum { alignment = 8 }; - constexpr void shrink_to_fit() { - if (is_long() == false) - return; + static constexpr size_type recommend(size_type s) noexcept { + if (s < min_cap) { + return min_cap - 1; + } + const size_type boundary = sizeof(value_type) < alignment ? alignment / sizeof(value_type) : endian_factor; + size_type guess = align_it(s + 1) - 1; + if (guess == min_cap) { + guess += endian_factor; + } - reallocate(size(), true); + PLUGIFY_ASSERT(guess >= s, "recommendation is below the requested size"); + return guess; + } + + inline constexpr void init(const value_type* s, size_type sz); + inline constexpr void init(size_type n, value_type c); + + // Slow path for the (inlined) copy constructor for 'long' strings. + // Always externally instantiated and not inlined. + // Requires that s is zero terminated. + // The main reason for this function to exist is because for unstable, we + // want to allow inlining of the copy constructor. However, we don't want + // to call the init() functions as those are marked as inline which may + // result in over-aggressive inlining by the compiler, where our aim is + // to only inline the fast path code directly in the ctor. + PLUGIFY_NOINLINE constexpr void init_copy_ctor_external(const value_type* s, size_type sz); + + template + inline constexpr void init(InputIterator first, InputIterator last); + + template + inline constexpr void init(ForwardIterator first, ForwardIterator last); + + template + constexpr void init_with_sentinel(InputIterator first, Sentinel last); + template + constexpr void init_with_size(InputIterator first, Sentinel last, size_type sz); + + constexpr void grow_by_without_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add = 0 + ); + constexpr void grow_by_and_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add, + const value_type* p_new_stuff + ); + + // assign_no_alias is invoked for assignment operations where we + // have proof that the input does not alias the current instance. + // For example, operator=(basic_string) performs a 'self' check. + template + PLUGIFY_NOINLINE constexpr basic_string& assign_no_alias(const value_type* s, size_type n); + + constexpr void erase_to_end(size_type pos) { + PLUGIFY_ASSERT( + pos <= capacity(), + "Trying to erase at position outside the strings capacity!" + ); + null_terminate_at(std::to_address(get_pointer()), pos); + } + + // erase_external_with_move is invoked for erase() invocations where + // `n ~= npos`, likely requiring memory moves on the string data. + PLUGIFY_NOINLINE constexpr void erase_external_with_move(size_type pos, size_type n); + + constexpr void copy_assign_alloc(const basic_string& str) { + copy_assign_alloc( + str, + std::integral_constant() + ); + } + + constexpr void copy_assign_alloc(const basic_string& str, std::true_type) { + if (_alloc == str._alloc) { + _alloc = str._alloc; + } else { + if (!str.is_long()) { + reset_internal_buffer(); + _alloc = str._alloc; + } else { + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + auto alloc = str._alloc; + replace_internal_buffer(allocate_long_buffer(alloc, str.size())); + _alloc = std::move(alloc); + } + } } - constexpr void clear() noexcept { - set_size(0); + constexpr void copy_assign_alloc(const basic_string&, std::false_type) noexcept { } - constexpr basic_string& insert(size_type pos, size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - insert(std::next(cbegin(), pos), count, ch); - return *this; + constexpr void + move_assign(basic_string& str, std::false_type) noexcept(alloc_traits::is_always_equal::value); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void + move_assign(basic_string& str, std::true_type) noexcept; + + constexpr void move_assign_alloc( + basic_string& str + ) noexcept(!alloc_traits::propagate_on_container_move_assignment::value || std::is_nothrow_move_assignable_v) { + move_assign_alloc( + str, + std::integral_constant() + ); } - constexpr basic_string& insert(size_type pos, const value_type* str) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - auto len = Traits::length(str); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, str, len); - return *this; + constexpr void move_assign_alloc( + basic_string& c, + std::true_type + ) noexcept(std::is_nothrow_move_assignable_v) { + _alloc = std::move(c._alloc); } - constexpr basic_string& insert(size_type pos, const value_type* str, size_type count) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - internal_insert(pos, str, count); - return *this; + constexpr void move_assign_alloc(basic_string&, std::false_type) noexcept { } - constexpr basic_string& insert(size_type pos, const basic_string& str) { - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - internal_insert(pos, const_pointer(str.data()), str.size()); + PLUGIFY_NOINLINE constexpr basic_string& assign_external(const value_type* s); + PLUGIFY_NOINLINE constexpr basic_string& assign_external(const value_type* s, size_type n); + + // Assigns the value in s, guaranteed to be n < min_cap in length. + inline constexpr basic_string& assign_short(const value_type* s, size_type n) { + size_type old_size = size(); + if (n > old_size) { + annotate_increase(n - old_size); + } + pointer p; + if (is_long()) { + set_long_size(n); + p = get_long_pointer(); + } else { + set_short_size(n); + p = get_short_pointer(); + } + traits_type::move(std::to_address(p), s, n); + traits_type::assign(p[n], value_type()); + if (old_size > n) { + annotate_shrink(old_size); + } return *this; } - constexpr basic_string& insert(size_type pos, const basic_string& str, size_type pos_str, size_type count = npos) { - PLUGIFY_ASSERT(pos <= size() && pos_str <= str.size(), "plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range); - count = std::min(count, str.length() - pos_str); - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - return insert(pos, str.data() + pos_str, count); + constexpr basic_string& null_terminate_at(value_type* p, size_type newsz) { + size_type old_size = size(); + if (newsz > old_size) { + annotate_increase(newsz - old_size); + } + set_size(newsz); + traits_type::assign(p[newsz], value_type()); + if (old_size > newsz) { + annotate_shrink(old_size); + } + return *this; } - constexpr iterator insert(const_iterator pos, value_type ch) { - return insert(pos, 1, ch); + template + constexpr bool addr_in_range(const T& v) const { + return is_pointer_in_range(data(), data() + size() + 1, std::addressof(v)); } - constexpr iterator insert(const_iterator pos, size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - auto spos = std::distance(cbegin(), pos); - internal_insert(spos, ch, count); - return std::next(begin(), spos); + [[noreturn]] static void throw_length_error() { + PLUGIFY_THROW("constructed string size would exceed max_size()", std::length_error); } - template - constexpr iterator insert(const_iterator pos, InputIterator first, InputIterator last) { - auto spos = std::distance(cbegin(), pos); - auto len = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(spos, const_pointer(first), len); - return std::next(begin(), spos); - } - - constexpr iterator insert(const_iterator pos, std::initializer_list list) { - PLUGIFY_ASSERT(size() + list.size() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - auto spos = std::distance(cbegin(), pos); - internal_insert(spos, const_pointer(list.begin()), list.size()); - return std::next(begin(), spos); - } - - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& insert(size_type pos, const Type& t) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - sview_type sv(t); - PLUGIFY_ASSERT(size() + sv.length() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, const_pointer(sv.data()), sv.length()); - return *this; + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& insert(size_type pos, const Type& t, size_type pos_str, size_type count = npos) { - auto sv = sview_type(t); - PLUGIFY_ASSERT(pos <= size() && pos_str <= sv.length(), "plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range); - auto ssv = sv.substr(pos_str, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, const_pointer(ssv.data()), ssv.length()); - return *this; - } + friend constexpr basic_string + concatenate_strings<>(const Allocator&, std::type_identity_t, std::type_identity_t); -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr iterator insert_range(const_iterator pos, Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error); - return insert(pos - begin(), str); - } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + friend inline constexpr bool + operator==(const basic_string&, const CharT2*) noexcept; + }; - constexpr basic_string& erase(size_type pos = 0, size_type count = npos) { - auto sz = size(); - auto buffer = data(); + template < + std::input_iterator InputIterator, + class CharT = std::iter_value_t, + is_allocator Allocator = allocator> + basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string, Allocator>; + + template > + explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) + -> basic_string; + + template < + class CharT, + is_char_traits Traits, + is_allocator Allocator = allocator, + class Sz = typename std::allocator_traits::size_type> + basic_string(std::basic_string_view, Sz, Sz, const Allocator& = Allocator()) + -> basic_string; + +#if PLUGIFY_HAS_CXX23 + template < + std::ranges::input_range Range, + is_allocator Allocator = std::allocator>> + basic_string(std::from_range_t, Range&&, Allocator = Allocator()) -> basic_string< + std::ranges::range_value_t, + std::char_traits>, + Allocator>; +#endif - PLUGIFY_ASSERT(pos <= sz, "plg::basic_string::erase(): pos out of range", std::out_of_range); + template + constexpr void basic_string::init(const value_type* s, size_type sz) { + pointer p = init_internal_buffer(sz); + traits_type::copy(std::to_address(p), s, sz); + traits_type::assign(p[sz], value_type()); + } - count = std::min(count, sz - pos); + template + PLUGIFY_NOINLINE constexpr void + basic_string::init_copy_ctor_external(const value_type* s, size_type sz) { + pointer p = init_internal_buffer(sz); + traits_type::copy(std::to_address(p), s, sz + 1); + } - auto left = sz - (pos + count); - if (left != 0) - Traits::move(buffer + pos, buffer + pos + count, left); + template + constexpr void basic_string::init(size_type n, value_type c) { + pointer p = init_internal_buffer(n); + traits_type::assign(std::to_address(p), n, c); + traits_type::assign(p[n], value_type()); + } - auto new_size = pos + left; - set_size(new_size); - null_terminate(); + template + template + constexpr void + basic_string::init(InputIterator first, InputIterator last) { + init_with_sentinel(std::move(first), std::move(last)); + } - return *this; + template + template + constexpr void + basic_string::init_with_sentinel(InputIterator first, Sentinel last) { + _rep = rep(); + annotate_new(0); + +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + for (; first != last; ++first) { + push_back(*first); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + reset_internal_buffer(); + throw; } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr iterator erase(const_iterator position) { - auto pos = std::distance(cbegin(), position); - erase(pos, 1); - return begin() + pos; - } + template + template + constexpr void + basic_string::init(ForwardIterator first, ForwardIterator last) { + size_type sz = static_cast(std::distance(first, last)); + init_with_size(first, last, sz); + } - constexpr iterator erase(const_iterator first, const_iterator last) { - auto pos = std::distance(cbegin(), first); - auto len = std::distance(first, last); - erase(pos, len); - return begin() + pos; - } + template + template + constexpr void basic_string::init_with_size( + InputIterator first, + Sentinel last, + size_type sz + ) { + pointer p = init_internal_buffer(sz); + +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + auto end = copy_non_overlapping_range(std::move(first), std::move(last), std::to_address(p)); + traits_type::assign(*end, value_type()); +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + reset_internal_buffer(); + throw; + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr void push_back(value_type ch) { - PLUGIFY_ASSERT(size() + 1 <= max_size(), "plg::basic_string::push_back(): resulted string size would exceed max_size()", std::length_error); - append(1, ch); - } + template + constexpr void basic_string::grow_by_and_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add, + const value_type* p_new_stuff + ) { + size_type ms = max_size(); + if (delta_cap > ms - old_cap) { + throw_length_error(); + } + pointer old_p = get_pointer(); + size_type cap = old_cap < ms / 2 - alignment + ? recommend(std::max(old_cap + delta_cap, 2 * old_cap)) + : ms; + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + long_ buffer = allocate_long_buffer(_alloc, cap); + if (n_copy != 0) { + traits_type::copy(std::to_address(buffer._data), std::to_address(old_p), n_copy); + } + if (n_add != 0) { + traits_type::copy(std::to_address(buffer._data) + n_copy, p_new_stuff, n_add); + } + size_type sec_cp_sz = old_sz - n_del - n_copy; + if (sec_cp_sz != 0) { + traits_type::copy( + std::to_address(buffer._data) + n_copy + n_add, + std::to_address(old_p) + n_copy + n_del, + sec_cp_sz + ); + } + buffer._size = n_copy + n_add + sec_cp_sz; + traits_type::assign(buffer._data[buffer._size], value_type()); + replace_internal_buffer(buffer); + } - constexpr void pop_back() { - erase(end() - 1); - } + template + constexpr void basic_string::grow_by_without_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add + ) { + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + size_type ms = max_size(); + if (delta_cap > ms - old_cap) { + this->throw_length_error(); + } + pointer old_p = get_pointer(); + size_type cap = old_cap < ms / 2 - alignment + ? recommend(std::max(old_cap + delta_cap, 2 * old_cap)) + : ms; + long_ buffer = allocate_long_buffer(_alloc, cap); + if (n_copy != 0) { + traits_type::copy(std::to_address(buffer._data), std::to_address(old_p), n_copy); + } + size_type sec_cp_sz = old_sz - n_del - n_copy; + if (sec_cp_sz != 0) { + traits_type::copy( + std::to_address(buffer._data) + n_copy + n_add, + std::to_address(old_p) + n_copy + n_del, + sec_cp_sz + ); + } + + // This is -1 to make sure the caller sets the size properly, since old versions of this + // function didn't set the size at all. + buffer._size = npos; + replace_internal_buffer(buffer); + set_long_size(old_sz - n_del + n_add); + } - constexpr basic_string& append(size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ch, count); - return *this; - } + // assign - constexpr basic_string& append(const basic_string& str) { - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(str.data(), str.size()); + template + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_no_alias(const value_type* s, size_type n) { + const auto cap = is_short ? min_cap : get_long_cap(); + const auto size = is_short ? get_short_size() : get_long_size(); + if (n >= cap) { + grow_by_and_replace(cap - 1, n - cap + 1, size, 0, size, n, s); return *this; } - constexpr basic_string& append(const basic_string& str, size_type pos, size_type count = npos) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::append(): pos out of range", std::out_of_range); - auto ssv = sview_type(str).substr(pos, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ssv.data(), ssv.length()); - return *this; + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + pointer p; + if (is_short) { + p = get_short_pointer(); + set_short_size(n); + } else { + p = get_long_pointer(); + set_long_size(n); } + traits_type::copy(std::to_address(p), s, n); + traits_type::assign(p[n], value_type()); + return *this; + } - constexpr basic_string& append(const value_type* str, size_type count) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(str, count); + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_external(const value_type* s, size_type n) { + const auto cap = capacity(); + const auto sz = size(); + if (cap >= n) { + if (n > sz) { + annotate_increase(n - sz); + } + value_type* p = std::to_address(get_pointer()); + traits_type::move(p, s, n); + return null_terminate_at(p, n); + } else { + grow_by_and_replace(cap, n - cap, sz, 0, sz, n, s); return *this; } + } - constexpr basic_string& append(const value_type* str) { - auto len = Traits::length(str); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - return append(str, len); - } + template + constexpr basic_string& + basic_string::assign(const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::assign received nullptr"); + return (__builtin_constant_p(n) && fits_in_sso(n)) ? assign_short(s, n) + : assign_external(s, n); + } - template - constexpr basic_string& append(InputIterator first, InputIterator last) { - auto len = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(const_pointer(first), len); - return *this; - } + template + constexpr basic_string& + basic_string::assign(size_type n, value_type c) { + size_type cap = capacity(); + size_type old_size = size(); + if (cap < n) { + grow_by_without_replace(cap, n - cap, old_size, 0, old_size); + annotate_increase(n); + } else if (n > old_size) { + annotate_increase(n - old_size); + } + value_type* p = std::to_address(get_pointer()); + traits_type::assign(p, n, c); + return null_terminate_at(p, n); + } - constexpr basic_string& append(std::initializer_list list) { - PLUGIFY_ASSERT(size() + list.size() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(const_pointer(list.begin()), list.size()); - return *this; - } + template + constexpr basic_string& + basic_string::operator=(value_type c) { + size_type old_size = size(); + if (old_size == 0) { + annotate_increase(1); + } + pointer p; + if (is_long()) { + p = get_long_pointer(); + set_long_size(1); + } else { + p = get_short_pointer(); + set_short_size(1); + } + traits_type::assign(*p, c); + traits_type::assign(*++p, value_type()); + if (old_size > 1) { + annotate_shrink(old_size); + } + return *this; + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& append(const Type& t) { - sview_type sv(t); - PLUGIFY_ASSERT(size() + sv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(sv.data(), sv.size()); + template + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string& + basic_string::operator=(const basic_string& str) { + if (this == std::addressof(str)) { return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& append(const Type& t, size_type pos, size_type count = npos) { - sview_type sv(t); - PLUGIFY_ASSERT(pos <= sv.length(), "plg::basic_string::append(): pos out of range", std::out_of_range); - auto ssv = sv.substr(pos, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ssv.data(), ssv.length()); - return *this; - } + copy_assign_alloc(str); -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string& append_range(Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error); - return append(str); + if (is_long()) { + return assign_no_alias(str.data(), str.size()); } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr basic_string& operator+=(const basic_string& str) { - return append(str); + if (str.is_long()) { + return assign_no_alias(str.data(), str.size()); } - constexpr basic_string& operator+=(value_type ch) { - push_back(ch); - return *this; - } + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + _rep = str._rep; - constexpr basic_string& operator+=(const value_type* str) { - return append(str); - } + return *this; + } - constexpr basic_string& operator+=(std::initializer_list list) { - return append(list); + template + inline constexpr void + basic_string::move_assign(basic_string& str, std::false_type) noexcept( + alloc_traits::is_always_equal::value + ) { + if (_alloc != str._alloc) { + assign(str); + } else { + move_assign(str, std::true_type()); } + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& operator+=(const Type& t) { - return append(sview_type(t)); + template + inline constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void + basic_string::move_assign(basic_string& str, std::true_type) noexcept { + annotate_delete(); + if (is_long()) { + reset_internal_buffer(); + } + size_type str_old_size = str.size(); + bool str_was_short = !str.is_long(); + + move_assign_alloc(str); + _rep = str._rep; + str.set_short_size(0); + traits_type::assign(str.get_short_pointer()[0], value_type()); + + if (str_was_short && this != std::addressof(str)) { + str.annotate_shrink(str_old_size); + } else { + // ASan annotations: was long, so object memory is unpoisoned as new. + // Or is same as *this, and annotate_delete() was called. + str.annotate_new(0); + } + + // ASan annotations: Guard against `std::string s; s = std::move(s);` + // You can find more here: https://en.cppreference.com/w/cpp/utility/move + // Quote: "Unless otherwise specified, all standard library objects that have been moved + // from are placed in a "valid but unspecified state", meaning the object's class + // invariants hold (so functions without preconditions, such as the assignment operator, + // can be safely used on the object after it was moved from):" + // Quote: "v = std::move(v); // the value of v is unspecified" + if (!is_long() && std::addressof(str) != this) { + // If it is long string, delete was never called on original str's buffer. + annotate_new(get_short_size()); } + } - constexpr int compare(const basic_string& str) const noexcept { - return view().compare(str.view()); - } + template + template + constexpr void + basic_string::assign_with_sentinel(InputIterator first, Sentinel last) { + const basic_string temp(init_with_sentinel_tag(), std::move(first), std::move(last), _alloc); + assign(temp.data(), temp.size()); + } - constexpr int compare(size_type pos1, size_type count1, const basic_string& str) const { - return view().compare(pos1, count1, str.view()); + template + template + constexpr void + basic_string::assign_trivial(Iterator first, Sentinel last, size_type n) { + PLUGIFY_ASSERT( + string_is_trivial_iterator_v, + "The iterator type given to `assign_trivial` must be trivial" + ); + + size_type old_size = size(); + size_type cap = capacity(); + if (cap < n) { + // Unlike `append` functions, if the input range points into the string itself, there is + // no case that the input range could get invalidated by reallocation: + // 1. If the input range is a subset of the string itself, its size cannot exceed the + // capacity of the string, + // thus no reallocation would happen. + // 2. In the exotic case where the input range is the byte representation of the string + // itself, the string + // object itself stays valid even if reallocation happens. + size_type sz = size(); + grow_by_without_replace(cap, n - cap, sz, 0, sz); + annotate_increase(n); + } else if (n > old_size) { + annotate_increase(n - old_size); + } + pointer p = get_pointer(); + for (; first != last; ++p, (void) ++first) { + traits_type::assign(*p, *first); + } + traits_type::assign(*p, value_type()); + set_size(n); + if (n < old_size) { + annotate_shrink(old_size); } + } - constexpr int compare(size_type pos1, size_type count1, const basic_string& str, size_type pos2, size_type count2 = npos) const { - return view().compare(pos1, count1, str.view(), pos2, count2); + template + constexpr basic_string& + basic_string::assign(const basic_string& str, size_type pos, size_type n) { + size_type sz = str.size(); + if (pos > sz) { + this->throw_out_of_range(); } + return assign(str.data() + pos, std::min(n, sz - pos)); + } - constexpr int compare(const value_type* str) const { - return view().compare(str); - } + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_external(const value_type* s) { + return assign_external(s, traits_type::length(s)); + } - constexpr int compare(size_type pos1, size_type count1, const value_type* str) const { - return view().compare(pos1, count1, str); + template + constexpr basic_string& + basic_string::assign(const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::assign received nullptr"); + if (auto len = traits_type::length(s); __builtin_constant_p(len) && fits_in_sso(len)) { + return assign_short(s, len); } + return assign_external(s); + } - constexpr int compare(size_type pos1, size_type count1, const value_type* str, size_type count2) const { - return view().compare(pos1, count1, str, count2); - } + // append - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(const Type& t) const noexcept(noexcept(std::is_nothrow_convertible_v)) { - return view().compare(sview_type(t)); + template + constexpr basic_string& + basic_string::append(const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::append received nullptr"); + size_type cap = capacity(); + size_type sz = size(); + if (cap - sz < n) { + grow_by_and_replace(cap, sz + n - cap, sz, sz, 0, n, s); + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(size_type pos1, size_type count1, const Type& t) const { - return view().compare(pos1, count1, sview_type(t)); + if (n == 0) { + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(size_type pos1, size_type count1, const Type& t, size_type pos2, size_type count2 = npos) const { - return view().compare(pos1, count1, sview_type(t), pos2, count2); - } + annotate_increase(n); + value_type* p = std::to_address(get_pointer()); + traits_type::copy(p + sz, s, n); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr bool starts_with(sview_type sv) const noexcept { - return view().starts_with(sv); + template + constexpr basic_string& + basic_string::append(size_type n, value_type c) { + if (n == 0) { + return *this; } - constexpr bool starts_with(Char ch) const noexcept { - return view().starts_with(ch); + size_type cap = capacity(); + size_type sz = size(); + if (cap - sz < n) { + grow_by_without_replace(cap, sz + n - cap, sz, sz, 0); } + annotate_increase(n); + pointer p = get_pointer(); + traits_type::assign(std::to_address(p) + sz, n, c); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr bool starts_with(const Char* str) const { - return view().starts_with(str); - } + template + constexpr void basic_string::push_back(value_type c) { + bool is_short = !is_long(); + size_type cap; + size_type sz; + if (is_short) { + cap = min_cap - 1; + sz = get_short_size(); + } else { + cap = get_long_cap() - 1; + sz = get_long_size(); + } + if (sz == cap) { + grow_by_without_replace(cap, 1, sz, sz, 0); + is_short = false; // the string is always long after grow_by + } + annotate_increase(1); + pointer p; + if (is_short) { + p = get_short_pointer() + sz; + set_short_size(sz + 1); + } else { + p = get_long_pointer() + sz; + set_long_size(sz + 1); + } + traits_type::assign(*p, c); + traits_type::assign(*++p, value_type()); + } - constexpr bool ends_with(sview_type sv) const noexcept { - return view().ends_with(sv); + template + constexpr basic_string& + basic_string::append(const basic_string& str, size_type pos, size_type n) { + size_type sz = str.size(); + if (pos > sz) { + this->throw_out_of_range(); } + return append(str.data() + pos, std::min(n, sz - pos)); + } - constexpr bool ends_with(Char ch) const noexcept { - return view().ends_with(ch); - } + template + constexpr basic_string& + basic_string::append(const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::append received nullptr"); + return append(s, traits_type::length(s)); + } - constexpr bool ends_with(const Char* str) const { - return view().ends_with(str); - } + // insert - constexpr bool contains(sview_type sv) const noexcept { - return view().contains(sv); + template + constexpr basic_string& + basic_string::insert(size_type pos, const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::insert received nullptr"); + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } + size_type cap = capacity(); - constexpr bool contains(Char ch) const noexcept { - return view().contains(ch); + if (cap - sz < n) { + grow_by_and_replace(cap, sz + n - cap, sz, pos, 0, n, s); + return *this; } - constexpr bool contains(const Char* str) const { - return view().contains(str); + if (n == 0) { + return *this; } - constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - return replace(pos, count, str, 0, str.length()); + annotate_increase(n); + value_type* p = std::to_address(get_pointer()); + size_type n_move = sz - pos; + if (n_move != 0) { + if (is_pointer_in_range(p + pos, p + sz, s)) { + s += n; + } + traits_type::move(p + pos + n, p + pos, n_move); } + traits_type::move(p + pos, s, n); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const basic_string& str) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - return replace(pos, count, str, 0, str.length()); + template + constexpr basic_string& + basic_string::insert(size_type pos, size_type n, value_type c) { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } - constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2 = npos) { - PLUGIFY_ASSERT(pos <= size() && pos2 <= str.size(), "plg::basic_string::replace(): pos or pos_str out of range", std::out_of_range); - count2 = std::min(count2, str.length() - pos2); - auto ssv = sview_type(str).substr(pos2, count2); - return replace(pos, count, ssv.data(), ssv.length()); + if (n == 0) { + return *this; } - template - constexpr basic_string& replace(const_iterator first, const_iterator last, InputIterator first2, InputIterator last2) { - return replace(first, last, const_pointer(first2), std::distance(first2, last2)); - } + size_type cap = capacity(); + value_type* p; + if (cap - sz >= n) { + annotate_increase(n); + p = std::to_address(get_pointer()); + size_type n_move = sz - pos; + if (n_move != 0) { + traits_type::move(p + pos + n, p + pos, n_move); + } + } else { + grow_by_without_replace(cap, sz + n - cap, sz, pos, 0, n); + p = std::to_address(get_long_pointer()); + } + traits_type::assign(p + pos, n, c); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr basic_string& replace(size_type pos, size_type count, const value_type* str, size_type count2) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - count = std::min(count, length() - pos); - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - internal_replace(pos, const_pointer(str), count, count2); - return *this; + template + template + constexpr typename basic_string::iterator + basic_string::insert_with_size( + const_iterator pos, + Iterator first, + Sentinel last, + size_type n + ) { + size_type ip = static_cast(pos - begin()); + if (n == 0) { + return begin() + ip; + } + + if (string_is_trivial_iterator_v && !addr_in_range(*first)) { + return insert_from_safe_copy(n, ip, std::move(first), std::move(last)); + } else { + const basic_string temp(init_with_sentinel_tag(), std::move(first), std::move(last), _alloc); + return insert_from_safe_copy(n, ip, temp.begin(), temp.end()); } + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const value_type* str, size_type count2) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - return replace(pos, count, str, count2); - } + template + constexpr basic_string& basic_string::insert( + size_type pos1, + const basic_string& str, + size_type pos2, + size_type n + ) { + size_type str_sz = str.size(); + if (pos2 > str_sz) { + this->throw_out_of_range(); + } + return insert(pos1, str.data() + pos2, std::min(n, str_sz - pos2)); + } - constexpr basic_string& replace(size_type pos, size_type count, const value_type* str) { - return replace(pos, count, str, Traits::length(str)); - } + template + constexpr basic_string& + basic_string::insert(size_type pos, const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::insert received nullptr"); + return insert(pos, s, traits_type::length(s)); + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const value_type* str) { - return replace(first, last, str, Traits::length(str)); + template + constexpr typename basic_string::iterator + basic_string::insert(const_iterator pos, value_type c) { + size_type ip = static_cast(pos - begin()); + size_type sz = size(); + size_type cap = capacity(); + value_type* p; + if (cap == sz) { + grow_by_without_replace(cap, 1, sz, ip, 0, 1); + p = std::to_address(get_long_pointer()); + } else { + annotate_increase(1); + p = std::to_address(get_pointer()); + size_type n_move = sz - ip; + if (n_move != 0) { + traits_type::move(p + ip + 1, p + ip, n_move); + } } + traits_type::assign(p[ip], c); + traits_type::assign(p[++sz], value_type()); + set_size(sz); + return begin() + static_cast(ip); + } - constexpr basic_string& replace(size_type pos, size_type count, size_type count2, value_type ch) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - count = std::min(count, length() - pos); - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - internal_replace(pos, ch, count, count2); + // replace + + template + constexpr basic_string& + basic_string::replace( + size_type pos, + size_type n1, + const value_type* s, + size_type n2 + ) { + PLUGIFY_ASSERT(n2 == 0 || s != nullptr, "string::replace received nullptr"); + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); + } + n1 = std::min(n1, sz - pos); + size_type cap = capacity(); + if (cap - sz + n1 < n2) { + grow_by_and_replace(cap, sz - n1 + n2 - cap, sz, pos, n1, n2, s); return *this; } - constexpr basic_string& replace(const_iterator first, const_iterator last, size_type count2, value_type ch) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - internal_replace(pos, ch, count, count2); - return *this; + value_type* p = std::to_address(get_pointer()); + if (n1 != n2) { + if (n2 > n1) { + annotate_increase(n2 - n1); + } + size_type n_move = sz - pos - n1; + if (n_move != 0) { + if (n1 > n2) { + traits_type::move(p + pos, s, n2); + traits_type::move(p + pos + n2, p + pos + n1, n_move); + return null_terminate_at(p, sz + (n2 - n1)); + } + if (is_pointer_in_range(p + pos + 1, p + sz, s)) { + if (p + pos + n1 <= s) { + s += n2 - n1; + } else { // p + pos < s < p + pos + n1 + traits_type::move(p + pos, s, n1); + pos += n1; + s += n2; + n2 -= n1; + n1 = 0; + } + } + traits_type::move(p + pos + n2, p + pos + n1, n_move); + } } + traits_type::move(p + pos, s, n2); + return null_terminate_at(p, sz + (n2 - n1)); + } - constexpr basic_string& replace(const_iterator first, const_iterator last, std::initializer_list list) { - return replace(first, last, const_pointer(list.begin()), list.size()); + template + constexpr basic_string& + basic_string::replace(size_type pos, size_type n1, size_type n2, value_type c) { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); + } + n1 = std::min(n1, sz - pos); + size_type cap = capacity(); + value_type* p; + if (cap - sz + n1 >= n2) { + p = std::to_address(get_pointer()); + if (n1 != n2) { + if (n2 > n1) { + annotate_increase(n2 - n1); + } + size_type n_move = sz - pos - n1; + if (n_move != 0) { + traits_type::move(p + pos + n2, p + pos + n1, n_move); + } + } + } else { + grow_by_without_replace(cap, sz - n1 + n2 - cap, sz, pos, n1, n2); + p = std::to_address(get_long_pointer()); } + traits_type::assign(p + pos, n2, c); + return null_terminate_at(p, sz - (n1 - n2)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(size_type pos, size_type count, const Type& t) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - sview_type sv(t); - return replace(pos, count, sv.data(), sv.length()); - } + template + constexpr basic_string& + basic_string::replace( + size_type pos1, + size_type n1, + const basic_string& str, + size_type pos2, + size_type n2 + ) { + size_type str_sz = str.size(); + if (pos2 > str_sz) { + this->throw_out_of_range(); + } + return replace(pos1, n1, str.data() + pos2, std::min(n2, str_sz - pos2)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(const_iterator first, const_iterator last, const Type& t) { - sview_type sv(t); - return replace(first, last, sv.data(), sv.length()); - } + template + constexpr basic_string& + basic_string::replace(size_type pos, size_type n1, const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::replace received nullptr"); + return replace(pos, n1, s, traits_type::length(s)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(size_type pos, size_type count, const Type& t, size_type pos2, size_type count2 = npos) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - auto sv = sview_type(t).substr(pos2, count2); - return replace(pos, count, sv.data(), sv.length()); - } + // erase -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr iterator replace_with_range(const_iterator first, const_iterator last, Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - return replace(first, last, str);// replace checks for max_size() + // 'externally instantiated' erase() implementation, called when n != npos. + // Does not check pos against size() + template + PLUGIFY_NOINLINE constexpr void + basic_string::erase_external_with_move(size_type pos, size_type n) { + if (n == 0) { + return; } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr basic_string substr(size_type pos = 0, size_type count = npos) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::substr(): pos out of range", std::out_of_range); - return basic_string(*this, pos, count); + size_type sz = size(); + value_type* p = std::to_address(get_pointer()); + n = std::min(n, sz - pos); + size_type n_move = sz - pos - n; + if (n_move != 0) { + traits_type::move(p + pos, p + pos + n, n_move); } + null_terminate_at(p, sz - n); + } - constexpr size_type copy(value_type* str, size_type count, size_type pos = 0) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::copy(): pos out of range", std::out_of_range); - return view().copy(str, count, pos); + template + constexpr basic_string& + basic_string::erase(size_type pos, size_type n) { + if (pos > size()) { + this->throw_out_of_range(); } - - constexpr void resize(size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::resize(): resulted string size would exceed max_size()", std::length_error); - auto cap = capacity(); - auto sz = size(); - auto rsz = count + sz; - - if (sz < rsz) { - if (cap < rsz) - grow_to(rsz); - Traits::assign(data() + sz, count, ch); - } - set_size(rsz); - null_terminate(); + if (n == npos) { + erase_to_end(pos); + } else { + erase_external_with_move(pos, n); } + return *this; + } - constexpr void resize(size_type count) { - resize(count, _terminator); - } + template + inline constexpr typename basic_string::iterator + basic_string::erase(const_iterator pos) { + PLUGIFY_ASSERT(pos != end(), "string::erase(iterator) called with a non-dereferenceable iterator"); + iterator b = begin(); + size_type r = static_cast(pos - b); + erase(r, 1); + return b + static_cast(r); + } - template - constexpr void resize_and_overwrite(size_type, Operation) { - static_assert(detail::dependent_false, "plg::basic_string::resize_and_overwrite(count, op) not implemented!"); - } + template + inline constexpr typename basic_string::iterator + basic_string::erase(const_iterator first, const_iterator last) { + PLUGIFY_ASSERT(first <= last, "string::erase(first, last) called with invalid range"); + iterator b = begin(); + size_type r = static_cast(first - b); + erase(r, static_cast(last - first)); + return b + static_cast(r); + } - constexpr void swap(basic_string& other) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value) { - using std::swap; - if constexpr (allocator_traits::propagate_on_container_swap::value) { - swap(_allocator, other._allocator); - } - swap(_storage, other._storage); - } + template + inline constexpr void basic_string::pop_back() { + PLUGIFY_ASSERT(!empty(), "string::pop_back(): string is already empty"); + erase_to_end(size() - 1); + } - constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept { - return view().find(sview_type(str), pos); + template + inline constexpr void basic_string::clear() noexcept { + size_type old_size; + if (is_long()) { + old_size = get_long_size(); + traits_type::assign(*get_long_pointer(), value_type()); + set_long_size(0); + } else { + old_size = get_short_size(); + traits_type::assign(*get_short_pointer(), value_type()); + set_short_size(0); } + annotate_shrink(old_size); + } - constexpr size_type find(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find(str, pos, count); + template + constexpr void basic_string::resize(size_type n, value_type c) { + size_type sz = size(); + if (n > sz) { + append(n - sz, c); + } else { + erase_to_end(n); } + } - constexpr size_type find(const value_type* str, size_type pos = 0) const noexcept { - return view().find(str, pos); + template + constexpr void basic_string::reserve(size_type requested_capacity) { + if (requested_capacity > max_size()) { + this->throw_length_error(); } - constexpr size_type find(value_type ch, size_type pos = 0) const noexcept { - return view().find(ch, pos); + // Make sure reserve(n) never shrinks. This is technically only required in C++20 + // and later (since P0966R1), however we provide consistent behavior in all Standard + // modes because this function is instantiated in the shared library. + if (requested_capacity <= capacity()) { + return; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find(sview_type(t), pos); - } + [[maybe_unused]] annotation_guard g(*this); + long_ buffer = allocate_long_buffer(_alloc, requested_capacity); + buffer._size = size(); + traits_type::copy(std::to_address(buffer._data), data(), buffer._size + 1); + replace_internal_buffer(buffer); + } - constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept { - return view().rfind(sview_type(str), pos); + template + inline constexpr void basic_string::shrink_to_fit() noexcept { + size_type target_capacity = recommend(size()); + if (target_capacity == capacity()) { + return; } - constexpr size_type rfind(const value_type* str, size_type pos, size_type count) const noexcept { - return view().rfind(str, pos, count); - } + PLUGIFY_ASSERT(is_long(), "Trying to shrink small string"); - constexpr size_type rfind(const value_type* str, size_type pos = npos) const noexcept { - return view().rfind(str, pos); - } + // We're a long string and we're shrinking into the small buffer. + const auto ptr = get_long_pointer(); + const auto size = get_long_size(); + const auto cap = get_long_cap(); - constexpr size_type rfind(value_type ch, size_type pos = npos) const noexcept { - return view().rfind(ch, pos); + if (fits_in_sso(target_capacity)) { + [[maybe_unused]] annotation_guard g(*this); + set_short_size(size); + traits_type::copy(std::to_address(get_short_pointer()), std::to_address(ptr), size + 1); + alloc_traits::deallocate(_alloc, ptr, cap); + return; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type rfind(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().rfind(sview_type(t), pos); - } +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + [[maybe_unused]] annotation_guard g(*this); + long_ buffer = allocate_long_buffer(_alloc, size); - constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept { - return view().find_first_of(sview_type(str), pos); - } + // The Standard mandates shrink_to_fit() does not increase the capacity. + // With equal capacity keep the existing buffer. This avoids extra work + // due to swapping the elements. + if (buffer._cap * endian_factor - 1 >= capacity()) { + alloc_traits::deallocate(_alloc, buffer._data, buffer._cap * endian_factor); + return; + } - constexpr size_type find_first_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_first_of(str, pos, count); - } + traits_type::copy( + std::to_address(buffer._data), + std::to_address(get_long_pointer()), + size + 1 + ); + replace_internal_buffer(buffer); +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + return; + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr size_type find_first_of(const value_type* str, size_type pos = 0) const noexcept { - return view().find_first_of(str, pos); + template + constexpr typename basic_string::const_reference + basic_string::at(size_type n) const { + if (n >= size()) { + this->throw_out_of_range(); } + return (*this)[n]; + } - constexpr size_type find_first_of(value_type ch, size_type pos = 0) const noexcept { - return view().find_first_of(ch, pos); + template + constexpr typename basic_string::reference + basic_string::at(size_type n) { + if (n >= size()) { + this->throw_out_of_range(); } + return (*this)[n]; + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_first_of(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find_first_of(sview_type(t), pos); + template + constexpr typename basic_string::size_type + basic_string::copy(value_type* s, size_type n, size_type pos) const { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } + size_type rlen = std::min(n, sz - pos); + traits_type::copy(s, data() + pos, rlen); + return rlen; + } - constexpr size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept { - return view().find_first_not_of(sview_type(str), pos); + template + inline constexpr void basic_string::swap(basic_string& str) noexcept { + PLUGIFY_ASSERT( + alloc_traits::propagate_on_container_swap::value || alloc_traits::is_always_equal::value || _alloc == str._alloc, + "swapping non-equal allocators" + ); + if (!is_long()) { + annotate_delete(); } - - constexpr size_type find_first_not_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_first_not_of(str, pos, count); + if (this != std::addressof(str) && !str.is_long()) { + str.annotate_delete(); } - - constexpr size_type find_first_not_of(const value_type* str, size_type pos = 0) const noexcept { - return view().find_first_not_of(str, pos); + std::swap(_rep, str._rep); + swap_allocator(_alloc, str._alloc); + if (!is_long()) { + annotate_new(get_short_size()); } - - constexpr size_type find_first_not_of(value_type ch, size_type pos = 0) const noexcept { - return view().find_first_not_of(ch, pos); + if (this != std::addressof(str) && !str.is_long()) { + str.annotate_new(str.get_short_size()); } + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_first_not_of(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find_first_not_of(sview_type(t), pos); + // compare + + template + inline constexpr int basic_string::compare( + size_type pos1, + size_type n1, + const value_type* s, + size_type n2 + ) const { + PLUGIFY_ASSERT(n2 == 0 || s != nullptr, "string::compare(): received nullptr"); + size_type sz = size(); + if (pos1 > sz || n2 == npos) { + this->throw_out_of_range(); + } + size_type rlen = std::min(n1, sz - pos1); + int r = traits_type::compare(data() + pos1, s, std::min(rlen, n2)); + if (r == 0) { + if (rlen < n2) { + r = -1; + } else if (rlen > n2) { + r = 1; + } } + return r; + } - constexpr size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept { - return view().find_last_of(sview_type(str), pos); - } + // invariants - constexpr size_type find_last_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_last_of(str, pos, count); + template + inline constexpr bool basic_string::invariants() const { + if (size() > capacity()) { + return false; } - - constexpr size_type find_last_of(const value_type* str, size_type pos = npos) const noexcept { - return view().find_last_of(str, pos); + if (capacity() < min_cap - 1) { + return false; } - - constexpr size_type find_last_of(value_type ch, size_type pos = npos) const noexcept { - return view().find_last_of(ch, pos); + if (data() == nullptr) { + return false; } - - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_last_of(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().find_last_of(sview_type(t), pos); + if (!Traits::eq(data()[size()], value_type())) { + return false; } + return true; + } - constexpr size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept { - return view().find_last_not_of(sview_type(str), pos); - } + // operator== - constexpr size_type find_last_not_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_last_not_of(str, pos, count); - } + template + inline constexpr bool operator==( + const basic_string& lhs, + const basic_string& rhs + ) noexcept { + size_t lhs_sz = lhs.size(); + return lhs_sz == rhs.size() && Traits::compare(lhs.data(), rhs.data(), lhs_sz) == 0; + } - constexpr size_type find_last_not_of(const value_type* str, size_type pos = npos) const noexcept { - return view().find_last_not_of(str, pos); - } + template + inline constexpr bool operator==( + const basic_string& lhs, + const CharT* PLUGIFY_NO_NULL rhs + ) noexcept { + PLUGIFY_ASSERT(rhs != nullptr, "operator==(basic_string, char*): received nullptr"); - constexpr size_type find_last_not_of(value_type ch, size_type pos = npos) const noexcept { - return view().find_last_not_of(ch, pos); - } + using String = basic_string; - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_last_not_of(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().find_last_not_of(sview_type(t), pos); + size_t rhs_len = Traits::length(rhs); + if (__builtin_constant_p(rhs_len) && !String::fits_in_sso(rhs_len)) { + if (!lhs.is_long()) { + return false; + } } - - friend constexpr basic_string operator+(const basic_string& lhs, const basic_string& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::copy(buffer + lhs_sz, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; + if (rhs_len != lhs.size()) { + return false; } + return lhs.compare(0, String::npos, rhs, rhs_len) == 0; + } - friend constexpr basic_string operator+(basic_string&& lhs, const basic_string& rhs) { - return std::move(lhs.append(rhs)); - } + template + constexpr auto operator<=>( + const basic_string& lhs, + const basic_string& rhs + ) noexcept { + return std::basic_string_view(lhs) + <=> std::basic_string_view(rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, basic_string&& rhs) { - return std::move(rhs.insert(0, lhs)); - } + template + constexpr auto operator<=>(const basic_string& lhs, const CharT* rhs) { + return std::basic_string_view(lhs) + <=> std::basic_string_view(rhs); + } - friend constexpr basic_string operator+(basic_string&& lhs, basic_string&& rhs) { - return std::move(lhs.append(rhs)); - } + // operator + + + template + constexpr basic_string concatenate_strings( + const Allocator& alloc, + std::type_identity_t> str1, + std::type_identity_t> str2 + ) { + using String = basic_string; + String r( + uninitialized_size_tag(), + str1.size() + str2.size(), + String::alloc_traits::select_on_container_copy_construction(alloc) + ); + auto ptr = std::to_address(r.get_pointer()); + Traits::copy(ptr, str1.data(), str1.size()); + Traits::copy(ptr + str1.size(), str2.data(), str2.size()); + Traits::assign(ptr[str1.size() + str2.size()], CharT()); + return r; + } - friend constexpr basic_string operator+(const Char* lhs, const basic_string& rhs) { - auto lhs_sz = Traits::length(lhs); - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(rhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs, lhs_sz); - Traits::copy(buffer + lhs_sz, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; - } + template + constexpr basic_string operator+( + const basic_string& lhs, + const basic_string& rhs + ) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const Char* lhs, basic_string&& rhs) { - return std::move(rhs.insert(0, lhs)); - } + template + constexpr basic_string + operator+(const CharT* lhs, const basic_string& rhs) { + return concatenate_strings(rhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(Char lhs, const basic_string& rhs) { - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), rhs_sz + 1, basic_string::allocator_traits::select_on_container_copy_construction(rhs._allocator)); - auto buffer = ret.data(); - Traits::assign(buffer, 1, lhs); - Traits::copy(buffer + 1, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; - } + // extern template string operator+ , allocator >(char + // const*, string const&); + + template + constexpr basic_string + operator+(CharT lhs, const basic_string& rhs) { + return concatenate_strings( + rhs.get_allocator(), + std::basic_string_view(std::addressof(lhs), 1), + rhs + ); + } - friend constexpr basic_string operator+(Char lhs, basic_string&& rhs) { - rhs.insert(rhs.begin(), lhs); - return std::move(rhs); - } + template + constexpr basic_string + operator+(const basic_string& lhs, const CharT* rhs) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, const Char* rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = Traits::length(rhs); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::copy(buffer + lhs_sz, rhs, rhs_sz); - ret.null_terminate(); - return ret; - } + template + constexpr basic_string + operator+(const basic_string& lhs, CharT rhs) { + return concatenate_strings( + lhs.get_allocator(), + lhs, + std::basic_string_view(std::addressof(rhs), 1) + ); + } +#if PLUGIFY_HAS_CXX26 + + template + constexpr basic_string operator+( + const basic_string& lhs, + std::type_identity_t> rhs + ) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(basic_string&& lhs, const Char* rhs) { - return std::move(lhs.append(rhs)); - } + template + constexpr basic_string operator+( + std::type_identity_t> lhs, + const basic_string& rhs + ) { + return concatenate_strings(rhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, Char rhs) { - auto lhs_sz = lhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + 1, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::assign(buffer + lhs_sz, 1, rhs); - ret.null_terminate(); - return ret; - } +#endif // PLUGIFY_HAS_CXX26 - friend constexpr basic_string operator+(basic_string&& lhs, Char rhs) { - lhs.push_back(rhs); - return std::move(lhs); - } - }; + template + inline constexpr basic_string operator+( + basic_string&& lhs, + const basic_string& rhs + ) { + return std::move(lhs.append(rhs)); + } - template - constexpr bool operator==(const basic_string& lhs, const basic_string& rhs) noexcept { - return lhs.compare(rhs) == 0; + template + inline constexpr basic_string operator+( + const basic_string& lhs, + basic_string&& rhs + ) { + return std::move(rhs.insert(0, lhs)); } - template - constexpr bool operator==(const basic_string& lhs, const Char* rhs) { - return lhs.compare(rhs) == 0; + template + inline constexpr basic_string + operator+(basic_string&& lhs, basic_string&& rhs) { + return std::move(lhs.append(rhs)); } - template - constexpr std::strong_ordering operator<=>(const basic_string& lhs, const basic_string& rhs) noexcept { - return lhs.compare(rhs) <=> 0; + template + inline constexpr basic_string + operator+(const CharT* lhs, basic_string&& rhs) { + return std::move(rhs.insert(0, lhs)); } - template - constexpr std::strong_ordering operator<=>(const basic_string& lhs, const Char* rhs) { - return lhs.compare(rhs) <=> 0; + template + inline constexpr basic_string + operator+(CharT lhs, basic_string&& rhs) { + rhs.insert(rhs.begin(), lhs); + return std::move(rhs); } - // swap - template - constexpr void swap(basic_string& lhs, basic_string& rhs) noexcept(noexcept(lhs.swap(rhs))) { - lhs.swap(rhs); + template + inline constexpr basic_string + operator+(basic_string&& lhs, const CharT* rhs) { + return std::move(lhs.append(rhs)); } - // erasure - template - constexpr typename basic_string::size_type erase(basic_string& c, const U& value) { - auto it = std::remove(c.begin(), c.end(), value); - auto r = std::distance(it, c.end()); - c.erase(it, c.end()); - return r; + template + inline constexpr basic_string + operator+(basic_string&& lhs, CharT rhs) { + lhs.push_back(rhs); + return std::move(lhs); } - template - constexpr typename basic_string::size_type erase_if(basic_string& c, Pred pred) { - auto it = std::remove_if(c.begin(), c.end(), pred); - auto r = std::distance(it, c.end()); - c.erase(it, c.end()); - return r; +#if PLUGIFY_HAS_CXX26 + + template + constexpr basic_string operator+( + basic_string&& lhs, + std::type_identity_t> rhs + ) { + return std::move(lhs.append(rhs)); + } + + template + constexpr basic_string operator+( + std::type_identity_t> lhs, + basic_string&& rhs + ) { + return std::move(rhs.insert(0, lhs)); } - // deduction guides - template::value_type>> - basic_string(InputIterator, InputIterator, Allocator = Allocator()) -> basic_string::value_type, std::char_traits::value_type>, Allocator>; +#endif // PLUGIFY_HAS_CXX26 - template> - explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) -> basic_string; + // swap + + template + inline constexpr void swap( + basic_string& lhs, + basic_string& rhs + ) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); + } - template> - basic_string(std::basic_string_view, typename basic_string::size_type, typename basic_string::size_type, const Allocator& = Allocator()) -> basic_string; + template + inline constexpr typename basic_string::size_type + erase(basic_string& str, const Up& v) { + auto old_size = str.size(); + str.erase(std::remove(str.begin(), str.end(), v), str.end()); + return old_size - str.size(); + } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template>> - basic_string(std::from_range_t, Range&&, Allocator = Allocator()) -> basic_string, std::char_traits>, Allocator>; -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + inline constexpr typename basic_string::size_type + erase_if(basic_string& str, Predicate pred) { + auto old_size = str.size(); + str.erase(std::remove_if(str.begin(), str.end(), pred), str.end()); + return old_size - str.size(); + } // basic_string typedef-names using string = basic_string; @@ -1702,8 +3618,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtol(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return static_cast(ret); } @@ -1713,8 +3630,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtol(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1724,8 +3642,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoll(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1735,8 +3654,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoul(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1746,8 +3666,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoull(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1757,8 +3678,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtof(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1768,8 +3690,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtod(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1779,19 +3702,22 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtold(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } namespace detail { - template - PLUGIFY_FORCE_INLINE constexpr S to_string(V v) { + template + constexpr S to_string(V v) { // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers. // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented), // so we need +1 here. - constexpr std::size_t bufSize = std::numeric_limits::digits10 + 2; // +1 for minus, +1 for digits10 + constexpr std::size_t bufSize = std::numeric_limits::digits10 + 2; // +1 for minus, + // +1 for + // digits10 char buf[bufSize]; const auto res = std::to_chars(buf, buf + bufSize, v); return S(buf, res.ptr); @@ -1800,7 +3726,12 @@ namespace plg { typedef int (*wide_printf)(wchar_t* __restrict, std::size_t, const wchar_t* __restrict, ...); #if PLUGIFY_COMPILER_MSVC - inline int truncate_snwprintf(wchar_t* __restrict buffer, std::size_t count, const wchar_t* __restrict format, ...) { + inline int truncate_snwprintf( + wchar_t* __restrict buffer, + std::size_t count, + const wchar_t* __restrict format, + ... + ) { int r; va_list args; va_start(args, format); @@ -1810,16 +3741,19 @@ namespace plg { } #endif - PLUGIFY_FORCE_INLINE constexpr wide_printf get_swprintf() noexcept { + constexpr wide_printf get_swprintf() noexcept { #if PLUGIFY_COMPILER_MSVC - return static_cast(truncate_snwprintf); + return static_cast< + int(__cdecl*)(wchar_t* __restrict, std::size_t, const wchar_t* __restrict, ...)>( + truncate_snwprintf + ); #else return swprintf; #endif } - template - PLUGIFY_FORCE_INLINE constexpr S as_string(P sprintf_like, const typename S::value_type* fmt, V v) { + template + constexpr S as_string(P sprintf_like, const typename S::value_type* fmt, V v) { typedef typename S::size_type size_type; S s; s.resize(s.capacity()); @@ -1832,7 +3766,7 @@ namespace plg { s.resize(used); break; } - available = used; // Assume this is advice of how much space we need. + available = used; // Assume this is advice of how much space we need. } else { available = available * 2 + 1; } @@ -1840,7 +3774,7 @@ namespace plg { } return s; } - }// namespace detail + } // namespace detail inline string to_string(int val) { return detail::to_string(val); } inline string to_string(unsigned val) { return detail::to_string(val); } @@ -1861,49 +3795,61 @@ namespace plg { inline wstring to_wstring(float val) { return detail::as_string(detail::get_swprintf(), L"%f", val); } inline wstring to_wstring(double val) { return detail::as_string(detail::get_swprintf(), L"%f", val); } inline wstring to_wstring(long double val) { return detail::as_string(detail::get_swprintf(), L"%Lf", val); } -#endif // PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS +#endif // PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS #ifndef PLUGIFY_STRING_NO_STD_HASH // hash support namespace detail { - template, Allocator>> + template < + typename Char, + typename Allocator, + typename String = basic_string, Allocator> + > struct string_hash_base { constexpr std::size_t operator()(const String& str) const noexcept { - return std::hash{}(typename String::sview_type(str)); + return std::hash{}(typename String::self_view(str)); } }; - }// namespace detail -#endif // PLUGIFY_STRING_NO_STD_HASH + } // namespace detail +#endif // PLUGIFY_STRING_NO_STD_HASH #ifndef PLUGIFY_STRING_NO_STD_FORMAT // format support namespace detail { - template + template static constexpr const Char* format_string() { - if constexpr (std::is_same_v || std::is_same_v) + if constexpr (std::is_same_v || std::is_same_v) { return "{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return L"{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return u"{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return U"{}"; + } return ""; } - template, Allocator>> + template < + typename Char, + typename Allocator, + typename String = basic_string, Allocator> + > struct string_formatter_base { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } - template + template auto format(const String& str, FormatContext& ctx) const { return std::format_to(ctx.out(), format_string(), str.c_str()); } }; } -#endif // PLUGIFY_STRING_NO_STD_FORMAT +#endif // PLUGIFY_STRING_NO_STD_FORMAT inline namespace literals { inline namespace string_literals { @@ -1916,6 +3862,7 @@ namespace plg { #elif PLUGIFY_COMPILER_MSVC PLUGIFY_WARN_IGNORE(4455) #endif + // suffix for basic_string literals constexpr string operator""s(const char* str, std::size_t len) { return string{str, len}; } constexpr u8string operator""s(const char8_t* str, std::size_t len) { return u8string{str, len}; } @@ -1924,29 +3871,34 @@ namespace plg { constexpr wstring operator""s(const wchar_t* str, std::size_t len) { return wstring{str, len}; } PLUGIFY_WARN_POP() - }// namespace string_literals - }// namespace literals -}// namespace plg + } // namespace string_literals + } // namespace literals +} // namespace plg #ifndef PLUGIFY_STRING_NO_STD_HASH // hash support namespace std { - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; -}// namespace std -#endif // PLUGIFY_STRING_NO_STD_HASH + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; +} // namespace std +#endif // PLUGIFY_STRING_NO_STD_HASH #ifndef PLUGIFY_STRING_NO_STD_FORMAT // format support @@ -1955,24 +3907,29 @@ namespace fmt { #else namespace std { #endif - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; -}// namespace std -#endif // PLUGIFY_STRING_NO_STD_FORMAT + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; +} // namespace std +#endif // PLUGIFY_STRING_NO_STD_FORMAT -template +template std::ostream& operator<<(std::ostream& os, const plg::basic_string& str) { os << str.c_str(); return os; @@ -1982,30 +3939,24 @@ std::ostream& operator<<(std::ostream& os, const plg::basic_string namespace plg { - namespace detail { - // Concept to match string-like types including char* and const char* - template - concept is_string_like = requires(T v) { - { std::string_view(v) }; - }; - } - - template + template constexpr string join(const Range& range, std::string_view separator) { string result; auto it = range.cbegin(); auto end = range.cend(); - if (it == end) return result; + if (it == end) { + return result; + } // First pass: compute total size size_t total_size = 0; size_t count = 0; for (auto tmp = it; tmp != end; ++tmp) { - using Elem = std::decay_t; - if constexpr (detail::is_string_like) { + using elem = std::decay_t; + if constexpr (string_like) { total_size += std::string_view(*tmp).size(); } else { total_size += std::formatted_size("{}", *tmp); @@ -2020,9 +3971,7 @@ namespace plg { auto in = std::back_inserter(result); // Second pass: actual formatting - /*if (it != end)*/ { - std::format_to(in, "{}", *it++); - } + /*if (it != end)*/ { std::format_to(in, "{}", *it++); } while (it != end) { std::format_to(in, "{}{}", separator, *it++); } @@ -2030,14 +3979,16 @@ namespace plg { return result; } - template + template constexpr string join(const Range& range, Proj&& proj, std::string_view separator) { string result; auto it = range.cbegin(); auto end = range.cend(); - if (it == end) return result; + if (it == end) { + return result; + } // First pass: compute total size size_t total_size = 0; @@ -2045,9 +3996,8 @@ namespace plg { for (auto tmp = it; tmp != end; ++tmp) { auto&& projected = std::invoke(std::forward(proj), *tmp); - using Elem = std::decay_t; - - if constexpr (detail::is_string_like) { + using elem = std::decay_t; + if constexpr (string_like) { total_size += std::string_view(*projected).size(); } else { total_size += std::formatted_size("{}", projected); @@ -2073,5 +4023,5 @@ namespace plg { return result; } -} // namespace plugify -#endif // PLUGIFY_STRING_NO_STD_FORMAT \ No newline at end of file +} // namespace plugify +#endif // PLUGIFY_STRING_NO_STD_FORMAT \ No newline at end of file diff --git a/test/cross_call_master/external/plugify/include/plg/uninitialized.hpp b/test/cross_call_master/external/plugify/include/plg/uninitialized.hpp new file mode 100644 index 0000000..9cc3400 --- /dev/null +++ b/test/cross_call_master/external/plugify/include/plg/uninitialized.hpp @@ -0,0 +1,157 @@ +#pragma once + +namespace plg { + template + struct has_construct_impl : std::false_type {}; + + template + struct has_construct_impl< + decltype((void) std::declval().construct(std::declval()...)), + Alloc, + Args...> : std::true_type {}; + + template + struct has_construct : has_construct_impl {}; + + // __has_destroy + template + struct has_destroy : std::false_type {}; + + template + struct has_destroy().destroy(std::declval()))> + : std::true_type {}; + + template + struct allocator_has_trivial_move_construct : std::negation> {}; + + template + struct allocator_has_trivial_move_construct, Type> : std::true_type {}; + + template + struct allocator_has_trivial_destroy : std::negation> {}; + + template + struct allocator_has_trivial_destroy, U> : std::true_type {}; + + template + struct allocator_has_trivial_copy_construct + : std::negation> {}; + + template + struct allocator_has_trivial_copy_construct, Type> : std::true_type {}; + + // Destroy all elements in [__first, __last) from left to right using allocator destruction. + template + void allocator_destroy(Alloc& alloc, Iter first, Sent last) { + for (; first != last; ++first) + std::allocator_traits::destroy(alloc, std::to_address(first)); + } + + template + class AllocatorDestroyRangeReverse { + public: + AllocatorDestroyRangeReverse(Alloc& alloc, Iter& first, Iter& last) + : _alloc(alloc), _first(first), _last(last) {} + + void operator()() const { + allocator_destroy(_alloc, std::reverse_iterator(_last), std::reverse_iterator(_first)); + } + + private: + Alloc& _alloc; + Iter& _first; + Iter& _last; + }; + + // Copy-construct [first1, last1) in [first2, first2 + N), where N is + // distance(first1, last1). + // + // The caller has to ensure that first2 can hold at least N uninitialized elements. If an + // exception is thrown the already copied elements are destroyed in reverse order of their + // construction. + template + Iter2 uninitialized_allocator_copy_impl( + Alloc& alloc, + Iter1 first1, + Sent1 last1, + Iter2 first2 + ) { + auto destruct_first = first2; + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(alloc, destruct_first, first2) + ); + while (first1 != last1) { + std::allocator_traits::construct(alloc, std::to_address(first2), *first1); + ++first1; + ++first2; + } + guard.complete(); + return first2; + } + + template < + class Alloc, + class In, + class RawTypeIn = std::remove_const_t, + class Out> + // using RawTypeIn because of the allocator extension + requires (std::is_trivially_copy_constructible_v && + std::is_trivially_copy_assignable_v && + std::is_same_v, std::remove_const_t> && + allocator_has_trivial_copy_construct::value) + Out* uninitialized_allocator_copy_impl(Alloc&, In* first1, In* last1, Out* first2) { + return std::copy(first1, last1, const_cast(first2)); + } + + template + Iter2 uninitialized_allocator_copy(Alloc& alloc, Iter1 first1, Sent1 last1, Iter2 first2) { + return uninitialized_allocator_copy_impl(alloc, std::move(first1), std::move(last1), std::move(first2)); + } + + // __uninitialized_allocator_relocate relocates the objects in [__first, __last) into + // __result. + // Relocation means that the objects in [__first, __last) are placed into __result as-if by + // move-construct and destroy, except that the move constructor and destructor may never be + // called if they are known to be equivalent to a memcpy. + // + // Preconditions: __result doesn't contain any objects and [__first, __last) contains + // objects Postconditions: __result contains the objects from [__first, __last) and + // [__first, __last) doesn't contain any objects + // + // The strong exception guarantee is provided if any of the following are true: + // - is_nothrow_move_constructible + // - is_copy_constructible + // - is_trivially_relocatable + template + void uninitialized_allocator_relocate(Alloc& alloc, T* first, T* last, T* result) { + if (std::is_constant_evaluated() || + !is_trivially_relocatable::value || + !allocator_has_trivial_move_construct::value || + !allocator_has_trivial_destroy::value + ) { + auto destruct_first = result; + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(alloc, destruct_first, result) + ); + auto iter = first; + while (iter != last) { + std::allocator_traits::construct( + alloc, + result, +#if PLUGIFY_HAS_EXCEPTIONS + std::move_if_noexcept(*iter) +#else + std::move(*iter) +#endif // PLUGIFY_HAS_EXCEPTIONS + ); + ++iter; + ++result; + } + guard.complete(); + allocator_destroy(alloc, first, last); + } else { + // Casting to void* to suppress clang complaining that this is technically UB. + std::memcpy(static_cast(result), first, sizeof(T) * static_cast(last - first)); + } + } +}; // namespace plg diff --git a/test/cross_call_master/external/plugify/include/plg/variant.hpp b/test/cross_call_master/external/plugify/include/plg/variant.hpp index e9ee06b..9e7ada0 100644 --- a/test/cross_call_master/external/plugify/include/plg/variant.hpp +++ b/test/cross_call_master/external/plugify/include/plg/variant.hpp @@ -1,11 +1,9 @@ #pragma once -#include #include #include // swap #include // used for index_type #include -#include #ifndef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE # include @@ -20,39 +18,41 @@ #define PLG_FWD(x) static_cast(x) #define PLG_MOV(x) static_cast< std::remove_reference_t&& >(x) -#include "plg/macro.hpp" +#include "plg/config.hpp" +#include "plg/concepts.hpp" // from https://github.com/groundswellaudio/swl-variant namespace plg { -#if PLUGIFY_EXCEPTIONS +#if PLUGIFY_HAS_EXCEPTIONS class bad_variant_access : public std::exception { - const char* message = ""; // llvm test requires a well formed what() on default init - public : + public: explicit bad_variant_access(const char* str) noexcept : message{str} {} bad_variant_access() noexcept = default; bad_variant_access(const bad_variant_access&) noexcept = default; bad_variant_access& operator=(const bad_variant_access&) noexcept = default; const char* what() const noexcept override { return message; } + private: + const char* message = ""; // llvm test requires a well formed what() on default init }; -#endif // PLUGIFY_EXCEPTIONS +#endif // PLUGIFY_HAS_EXCEPTIONS namespace detail { //struct variant_tag{}; struct emplacer_tag{}; - } - + } // namespace detail + template struct in_place_type_t : private detail::emplacer_tag {}; - + template struct in_place_index_t : private detail::emplacer_tag {}; - + template inline static constexpr in_place_index_t in_place_index; - + template inline static constexpr in_place_type_t in_place_type; - + namespace detail { template constexpr int find_first_true(bool (&&arr)[N]) { @@ -186,7 +186,6 @@ namespace plg { template<> struct node_trait { - template static constexpr auto elem_size = not(std::is_same_v) ? 2 : 1; @@ -343,9 +342,7 @@ namespace plg { // Ts... must be sorted in ascending size template using smallest_suitable_integer_type = - type_pack_element<(static_cast(Num > std::numeric_limits::max()) + ...), - Ts... - >; + type_pack_element<(static_cast((Num > std::numeric_limits::max())) + ...), Ts...>; // why do we need this again? i think something to do with GCC? namespace swap_trait { @@ -356,7 +353,7 @@ namespace plg { template inline constexpr bool nothrow = noexcept(swap(std::declval(), std::declval())); - } + } // namespace swap_trait #ifndef PLUGIFY_VARIANT_NO_STD_HASH template @@ -500,13 +497,13 @@ namespace plg { #undef CAT2 #undef INJECTSEQ - } // inline namespace v1 + } // namespace v1 struct variant_npos_t { template constexpr bool operator==(T idx) const noexcept { return idx == std::numeric_limits::max(); } }; - } + } // namespace detail inline static constexpr detail::variant_npos_t variant_npos; @@ -556,6 +553,8 @@ namespace plg { static constexpr bool trivial_dtor = std::is_trivially_destructible_v; public: + using trivially_relocatable = std::conditional_t...>, variant, void>; + template using alternative = std::remove_reference_t().template get())>; @@ -578,12 +577,12 @@ namespace plg { requires std::is_default_constructible_v> : _storage{in_place_index<0>}, _current{0} {} - + // copy constructor (trivial) constexpr variant(const variant&) requires trivial_copy_ctor = default; - + // note : both the copy and move constructor cannot be meaningfully constexpr without std::construct_at // copy constructor constexpr variant(const variant& o) @@ -591,7 +590,7 @@ namespace plg { : _storage{detail::dummy_type{}} { construct_from(o); } - + // move constructor (trivial) constexpr variant(variant&&) requires trivial_move_ctor @@ -636,7 +635,7 @@ namespace plg { explicit constexpr variant(in_place_index_t tag, std::initializer_list list, Args&&... args) : _storage{tag, list, PLG_FWD(args)...}, _current{Index} {} - + template requires ( detail::appears_exactly_once @@ -684,12 +683,12 @@ namespace plg { }); return *this; } - + // move assignment(trivial) constexpr variant& operator=(variant&& o) requires (trivial_move_assign and trivial_move_ctor and trivial_dtor) = default; - + // move assignment constexpr variant& operator=(variant&& o) noexcept((std::is_nothrow_move_constructible_v && ...) && (std::is_nothrow_move_assignable_v && ...)) @@ -705,7 +704,7 @@ namespace plg { }); return *this; } - + // generic assignment template requires detail::has_non_ambiguous_match @@ -714,14 +713,14 @@ namespace plg { && std::is_nothrow_constructible_v, T&&>) { using related_type = detail::best_overload_match; constexpr auto new_index = index_of; - + if (_current == new_index) unsafe_get() = PLG_FWD(t); else { constexpr bool do_simple_emplace = std::is_nothrow_constructible_v or not std::is_nothrow_move_constructible_v; - + if constexpr (do_simple_emplace) emplace(PLG_FWD(t)); else { @@ -729,12 +728,12 @@ namespace plg { emplace(PLG_MOV(tmp)); } } - + return *this; } - + // ================================== modifiers (20.7.3.5) - + template requires (std::is_constructible_v && detail::appears_exactly_once) constexpr T& emplace(Args&&... args) { @@ -789,7 +788,7 @@ namespace plg { full._current = npos; }; - switch(static_cast(index() == npos) + static_cast(o.index() == npos) * 2) { + switch (static_cast(index() == npos) + static_cast(o.index() == npos) * 2) { case 0 : break; case 1 : @@ -806,7 +805,7 @@ namespace plg { } } - assert(not(valueless_by_exception() && o.valueless_by_exception())); + PLUGIFY_ASSERT(not(valueless_by_exception() && o.valueless_by_exception()), ""); detail::visit_with_index(o, [&o, this](auto&& elem, auto index_cst) { if (index() == index_cst) { @@ -827,7 +826,7 @@ namespace plg { // we could refactor this detail::destruct>(elem); - o.template emplace_no_dtor<(unsigned)(this_index) >(PLG_MOV(tmp)); + o.template emplace_no_dtor(this_index)>(PLG_MOV(tmp)); }); }); } @@ -838,28 +837,28 @@ namespace plg { template constexpr auto& unsafe_get() & noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return _storage.template get(); } template constexpr auto&& unsafe_get() && noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return PLG_MOV(_storage.template get()); } template constexpr const auto& unsafe_get() const & noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return _storage.template get(); } template constexpr const auto&& unsafe_get() const && noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return PLG_MOV(_storage.template get()); } @@ -876,7 +875,7 @@ namespace plg { return; } } - assert(not o.valueless_by_exception()); + PLUGIFY_ASSERT(not o.valueless_by_exception(), ""); detail::visit_with_index(PLG_FWD(o), PLG_FWD(fn)); } @@ -938,7 +937,7 @@ namespace plg { // destroy the current element without checking for valueless constexpr void reset_no_check() { - assert(index() < size); + PLUGIFY_ASSERT(index() < size, ""); if constexpr (not trivial_dtor) { detail::visit_with_index(*this, [](auto& elem, auto index_cst) { detail::destruct>(elem); @@ -973,8 +972,8 @@ namespace plg { template constexpr bool holds_alternative(const variant& v) noexcept { static_assert((std::is_same_v || ...), "Requested type is not contained in the variant"); - constexpr auto Index = variant::template index_of; - return v.index() == Index; + constexpr auto index = variant::template index_of; + return v.index() == index; } // ========= get by index @@ -982,7 +981,9 @@ namespace plg { template constexpr auto& get(variant& v) { static_assert(Idx < sizeof...(Ts), "Index exceeds the variant size. "); - PLUGIFY_ASSERT(v.index() == Idx, "plg::variant:get(): Bad variant access in get.", bad_variant_access); + if (v.index() != Idx) { + PLUGIFY_THROW("bad variant access in get", bad_variant_access); + } return (v.template unsafe_get()); } @@ -1061,8 +1062,9 @@ namespace plg { template constexpr decltype(auto) visit(Fn&& fn, Vs&&... vs) { if constexpr ((std::decay_t::can_be_valueless || ...)) - PLUGIFY_ASSERT(!(vs.valueless_by_exception() || ...), "plg::variant:visit(): Bad variant access in visit.", bad_variant_access); - + if ((vs.valueless_by_exception() || ...)) { + PLUGIFY_THROW("bad variant access in visit", bad_variant_access); + } if constexpr (sizeof...(Vs) == 1) return detail::visit(PLG_FWD(fn), PLG_FWD(vs)...); else @@ -1151,10 +1153,9 @@ namespace plg { struct monostate{}; constexpr bool operator==(monostate, monostate) noexcept { return true; } - constexpr bool operator> (monostate, monostate) noexcept { return false; } - constexpr bool operator< (monostate, monostate) noexcept { return false; } - constexpr bool operator<=(monostate, monostate) noexcept { return true; } - constexpr bool operator>=(monostate, monostate) noexcept { return true; } + constexpr std::strong_ordering operator<=>(monostate, monostate) noexcept { + return std::strong_ordering::equal; + } // ===================================== specialized algorithms (20.7.10) @@ -1239,7 +1240,7 @@ namespace std { template<> struct hash { - constexpr std::size_t operator()(plg::monostate) const noexcept { return static_cast(-1); } + constexpr std::size_t operator()(plg::monostate) const noexcept { return static_cast(66740831); } }; } // namespace std #endif // PLUGIFY_VARIANT_NO_STD_HASH diff --git a/test/cross_call_master/external/plugify/include/plg/vector.hpp b/test/cross_call_master/external/plugify/include/plg/vector.hpp index 11aada1..cd26021 100644 --- a/test/cross_call_master/external/plugify/include/plg/vector.hpp +++ b/test/cross_call_master/external/plugify/include/plg/vector.hpp @@ -1,1032 +1,1538 @@ #pragma once +#include +#include +#include +#include +#include +#include #include -#include -#include +#include #include #include -#include -#include -#include -#include #include - -#include -#include -#include - -#if PLUGIFY_VECTOR_CONTAINERS_RANGES && (__cplusplus <= 202002L || !__has_include() || !defined(__cpp_lib_containers_ranges)) -# undef PLUGIFY_VECTOR_CONTAINERS_RANGES -# define PLUGIFY_VECTOR_CONTAINERS_RANGES 0 -#endif - -#if PLUGIFY_VECTOR_CONTAINERS_RANGES -# include -#endif +#include +#include +#include #include "plg/allocator.hpp" +#include "plg/guards.hpp" +#include "plg/split_buffer.hpp" +#include "plg/uninitialized.hpp" + +// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc +#if PLUGIFY_COMPILER_CLANG +# pragma clang system_header +#elif PLUGIFY_COMPILER_GCC +# pragma GCC system_header +#endif +// from https://github.com/llvm/llvm-project/blob/main/libcxx/include/vector namespace plg { namespace detail { - template - concept is_alloc = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; - - struct initialized_value_tag {}; + template + struct temp_value { + using allocator_traits = std::allocator_traits; -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template - concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; -#endif - } // namespace detail + union { + T v; + }; + PLUGIFY_NO_UNIQUE_ADDRESS Alloc& a; - template - struct vector_iterator { - using allocator_traits = std::allocator_traits; - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename allocator_traits::value_type; - using difference_type = std::ptrdiff_t; - using pointer = typename allocator_traits::pointer; - using reference = value_type&; - protected: - pointer _current; - public: - constexpr vector_iterator() = default; - constexpr vector_iterator(const vector_iterator& other) = default; - constexpr vector_iterator(vector_iterator&& other) = default; - constexpr vector_iterator(pointer ptr) - : _current(ptr) {} - constexpr vector_iterator& operator=(const vector_iterator& other) = default; - constexpr vector_iterator& operator=(vector_iterator&& other) = default; - constexpr ~vector_iterator() = default; - public: - constexpr reference operator*() const noexcept { - return *_current; - } - constexpr pointer operator->() const noexcept { - return _current; - } - constexpr vector_iterator& operator++() noexcept { - ++_current; - return *this; - } - constexpr vector_iterator operator++(int) const noexcept { - return vector_iterator(_current++); - } - constexpr vector_iterator& operator--() noexcept { - --_current; - return *this; - } - constexpr vector_iterator operator--(int) const noexcept { - return vector_iterator(_current--); - } - constexpr vector_iterator& operator+=(const difference_type n) noexcept { - _current += n; - return *this; - } - constexpr vector_iterator operator+(const difference_type n) const noexcept { - vector_iterator temp = *this; - return temp += n; - } - constexpr vector_iterator& operator-=(const difference_type n) noexcept { - _current -= n; - return *this; - } - constexpr vector_iterator operator-(const difference_type n) const noexcept { - vector_iterator temp = *this; - return temp -= n; - } - constexpr reference operator[](const difference_type n) const noexcept { - return _current[n]; - } - template - constexpr friend typename vector_iterator::difference_type operator-(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; - operator const pointer() const noexcept { - return _current; - } -#endif // __cpp_impl_three_way_comparison - pointer base() const noexcept { - return _current; - } - }; + constexpr T* addr() { + return std::addressof(v); + } - template - constexpr typename vector_iterator::difference_type operator-(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - using difference_type = typename vector_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } -#if __cpp_impl_three_way_comparison - template - constexpr auto operator<=>(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); - } -#endif // __cpp_impl_three_way_comparison + constexpr T& get() { + return *addr(); + } - template - struct vector_const_iterator { - using allocator_traits = std::allocator_traits; - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename allocator_traits::value_type; - using difference_type = std::ptrdiff_t; - using pointer = typename allocator_traits::const_pointer; - using reference = const value_type&; - protected: - pointer _current; - public: - constexpr vector_const_iterator() = default; - constexpr vector_const_iterator(const vector_const_iterator& other) = default; - constexpr vector_const_iterator(vector_const_iterator&& other) = default; - constexpr vector_const_iterator(pointer ptr) - : _current(ptr) {} - constexpr vector_const_iterator(const vector_iterator& other) // allow only iterator to const_iterator conversion - : _current(other.base()) {} - constexpr vector_const_iterator& operator=(const vector_const_iterator& other) = default; - constexpr vector_const_iterator& operator=(vector_const_iterator&& other) = default; - constexpr ~vector_const_iterator() = default; - public: - constexpr reference operator*() const noexcept { - return *_current; - } - constexpr pointer operator->() const noexcept { - return _current; - } - constexpr vector_const_iterator& operator++() noexcept { - ++_current; - return *this; - } - constexpr vector_const_iterator operator++(int) noexcept { - return vector_const_iterator(_current++); - } - constexpr vector_const_iterator& operator--() noexcept { - --_current; - return *this; - } - constexpr vector_const_iterator operator--(int) noexcept { - return vector_const_iterator(_current--); - } - constexpr vector_const_iterator& operator+=(const difference_type n) noexcept { - _current += n; - return *this; - } - constexpr vector_const_iterator operator+(const difference_type n) const noexcept { - vector_const_iterator temp = *this; - return temp += n; - } - constexpr vector_const_iterator& operator-=(const difference_type n) noexcept { - _current -= n; - return *this; - } - constexpr vector_const_iterator operator-(const difference_type n) const noexcept { - vector_const_iterator temp = *this; - return temp -= n; - } - constexpr reference operator[](const difference_type n) const noexcept { - return _current[n]; - } - template - constexpr friend typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; -#endif // __cpp_impl_three_way_comparison - template - constexpr friend typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; - operator const pointer() const noexcept { - return _current; - } -#endif // __cpp_impl_three_way_comparison - pointer base() const noexcept { - return _current; - } - }; + template + PLUGIFY_NO_CFI constexpr + explicit temp_value(Alloc& alloc, Args&&... args) + : a(alloc) { + allocator_traits::construct(a, addr(), std::forward(args)...); + } - template - constexpr typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - using difference_type = typename vector_const_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } - template - constexpr auto operator<=>(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); - } - template - constexpr typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - using difference_type = typename vector_const_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } - template - constexpr auto operator<=>(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); + constexpr ~temp_value() { + allocator_traits::destroy(a, addr()); + } + }; } - // vector - // based on implementations from libc++, libstdc++ and Microsoft STL - template> + template > class vector { - using allocator_traits = std::allocator_traits; + template + using split_buffer = split_buffer; public: + // + // Types + // using value_type = T; using allocator_type = Allocator; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; + using alloc_traits = std::allocator_traits; using reference = value_type&; using const_reference = const value_type&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; - using iterator = vector_iterator; - using const_iterator = vector_const_iterator; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - protected: - PLUGIFY_NO_UNIQUE_ADDRESS - allocator_type _allocator; - pointer _begin; - pointer _end; - pointer _capacity; + //static_assert(std::check_valid_allocator::value, ""); + static_assert( + std::is_same_v, + "Allocator::value_type must be same type as value_type" + ); - private: - constexpr static size_type growth_factor = 2; // When resizing, what number to scale by + // + // [vector.cons], construct/copy/destroy + // + constexpr vector() noexcept(std::is_nothrow_default_constructible_v) = default; - constexpr void copy_constructor(const vector& other) { - const size_type capacity = other.capacity(); - _begin = allocator_traits::allocate(_allocator, capacity); - std::uninitialized_copy(other.begin(), other.end(), begin()); - _end = _begin + other.size(); - _capacity = _begin + capacity; + constexpr explicit vector(const allocator_type& a) noexcept + : _alloc(a) { } - template - constexpr void range_constructor(InputIterator first, InputIterator last) { - const size_type count = static_cast(std::distance(first, last)); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_copy(first, last, _begin); - _capacity = _begin + count; - _end = _begin + count; + constexpr explicit vector(size_type n) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n); + } + guard.complete(); } - constexpr bool is_full() const { - return _end == _capacity; + constexpr + explicit vector(size_type n, const allocator_type& a) + : _alloc(a) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n); + } + guard.complete(); } - constexpr size_type calculate_new_capacity() const { - const size_type old_capacity = capacity(); - return old_capacity == 0 ? 1 : growth_factor * old_capacity; + constexpr vector(size_type n, const value_type& x) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n, x); + } + guard.complete(); } - constexpr iterator const_iterator_cast(const_iterator iter) noexcept { - return begin() + (iter - cbegin()); + constexpr + vector(size_type n, const value_type& x, const allocator_type& a) + : _alloc(a) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n, x); + } + guard.complete(); } - constexpr void reallocate(size_type new_capacity) { - reallocate(new_capacity, [](pointer const) {}); + template + constexpr + vector(InputIterator first, InputIterator last) { + init_with_sentinel(first, last); } - template - constexpr void reallocate(size_type new_capacity, const F& construct) { - const size_type old_size = size(); - const size_type old_capacity = capacity(); - PLUGIFY_ASSERT(new_capacity >= old_size, "plg::vector::reallocate(): resulted vector size would exceed size()", std::length_error); - if (new_capacity == old_capacity) - return; - - pointer const new_begin = allocator_traits::allocate(_allocator, new_capacity); - construct(new_begin); - std::uninitialized_move(_begin, _end, new_begin); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + old_size; - _capacity = _begin + new_capacity; - } + template + constexpr + vector(InputIterator first, InputIterator last, const allocator_type& a) + : _alloc(a) { + init_with_sentinel(first, last); + } + + template + constexpr + vector(ForwardIterator first, ForwardIterator last) { + size_type n = static_cast(std::distance(first, last)); + init_with_size(first, last, n); + } + + template + constexpr + vector(ForwardIterator first, ForwardIterator last, const allocator_type& a) + : _alloc(a) { + size_type n = static_cast(std::distance(first, last)); + init_with_size(first, last, n); + } + +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr vector( + std::from_range_t, + Range&& range, + const allocator_type& alloc = allocator_type() + ) : _alloc(alloc) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + init_with_size(std::ranges::begin(range), std::ranges::end(range), n); - template - constexpr void emplace_at_end(const F& construct) { - if (is_full()) { - reallocate(calculate_new_capacity(), construct); } else { - construct(_begin); + init_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } } +#endif - template - constexpr void resize_to(size_type count, const V& value) { - if (count < size()) { - std::destroy(_begin + count, _end); - _end = _begin + count; - } else if (count > size()) { - const size_type old_size = size(); - auto construct = [&](pointer const data) { - if constexpr (std::is_same_v) { - std::uninitialized_fill(data + old_size, data + count, value); - } else { - std::uninitialized_value_construct(data + old_size, data + count); - } - }; - if (count > capacity()) { - reallocate(count, construct); - } else { - construct(_begin); + private: + class destroy_vector { + public: + constexpr explicit destroy_vector(vector& vec) + : vec_(vec) { + } + + constexpr void operator()() { + if (vec_._begin != nullptr) { + vec_.clear(); + vec_.annotate_delete(); + alloc_traits::deallocate(vec_._alloc, vec_._begin, vec_.capacity()); } - _end = _begin + count; } - } - constexpr void swap_without_allocator(vector&& other) noexcept { - using std::swap; - swap(_begin, other._begin); - swap(_end, other._end); - swap(_capacity, other._capacity); - } + private: + vector& vec_; + }; public: - // constructor - constexpr vector() noexcept(std::is_nothrow_default_constructible::value) - : _allocator(Allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { + constexpr ~vector() { + destroy_vector (*this)(); + } + + constexpr vector(const vector& x) + : _alloc(alloc_traits::select_on_container_copy_construction(x._alloc)) { + init_with_size(x._begin, x._end, x.size()); } - constexpr explicit vector(const Allocator& allocator) noexcept - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { + constexpr + vector(const vector& x, const std::type_identity_t& a) + : _alloc(a) { + init_with_size(x._begin, x._end, x.size()); } - constexpr vector(size_type count, const T& value, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_fill_n(_begin, count, value); - _capacity = _begin + count; - _end = _begin + count; + constexpr vector& operator=(const vector& x); + + constexpr vector(std::initializer_list il) { + init_with_size(il.begin(), il.end(), il.size()); } - constexpr explicit vector(size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_value_construct_n(_begin, count); - _capacity = _begin + count; - _end = _begin + count; + constexpr + vector(std::initializer_list il, const allocator_type& a) + : _alloc(a) { + init_with_size(il.begin(), il.end(), il.size()); } - template - constexpr vector(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(static_cast(std::distance(first, last)) <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - range_constructor(first, last); + constexpr vector& + operator=(std::initializer_list il) { + assign(il.begin(), il.end()); + return *this; } - constexpr vector(const vector& other) - : _allocator(other.get_allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - copy_constructor(other); + constexpr vector(vector&& x) noexcept; + + constexpr + vector(vector&& x, const std::type_identity_t& a); + + constexpr vector& operator=(vector&& x) noexcept( + std::allocator_traits::propagate_on_container_move_assignment::value || + std::allocator_traits::is_always_equal::value) + { + move_assign( + x, + std::integral_constant() + ); + return *this; } - constexpr vector(const vector& other, const Allocator& allocator) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - copy_constructor(other); + template + constexpr void + assign(InputIterator first, InputIterator last) { + assign_with_sentinel(first, last); } - constexpr vector(vector&& other) noexcept(std::is_nothrow_move_constructible::value) - : _allocator(Allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - swap(other); + template + constexpr void + assign(ForwardIterator first, ForwardIterator last) { + assign_with_size(first, last, std::distance(first, last)); } - constexpr vector(vector&& other, const Allocator& allocator) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - if constexpr (allocator_traits::is_always_equal::value) { - swap_without_allocator(std::move(other)); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr void assign_range(Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + assign_with_size(std::ranges::begin(range), std::ranges::end(range), n); + } else { - if (get_allocator() == other.get_allocator()) { - swap_without_allocator(std::move(other)); - } else { - const size_type capacity = other.capacity(); - _begin = allocator_traits::allocate(_allocator, capacity); - std::uninitialized_move(other.begin(), other.end(), begin()); - _end = _begin + other.size(); - _capacity = _begin + capacity; - } + assign_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } } +#endif - constexpr vector(std::initializer_list list, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(list.size() <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - range_constructor(list.begin(), list.end()); + constexpr void + assign(size_type n, const_reference u); + + constexpr void + assign(std::initializer_list il) { + assign(il.begin(), il.end()); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr vector(std::from_range_t, Range&& range, const Allocator& alloc = Allocator()) - : vector(std::ranges::begin(range), std::ranges::end(range), alloc) {} -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES + [[nodiscard]] constexpr allocator_type + get_allocator() const noexcept { + return this->_alloc; + } - // destructor - constexpr ~vector() { - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); + // + // Iterators + // + [[nodiscard]] constexpr iterator begin() noexcept { + return make_iter(add_alignment_assumption(this->_begin)); } - // operator= - constexpr vector& operator=(const vector& other) { - if (this == &other) [[unlikely]] { - return *this; - } + [[nodiscard]] constexpr const_iterator + begin() const noexcept { + return make_iter(add_alignment_assumption(this->_begin)); + } - clear(); - if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != other.get_allocator()) { - allocator_traits::deallocate(_allocator, _begin, capacity()); - } - } - _allocator = other.get_allocator(); - } + [[nodiscard]] constexpr iterator end() noexcept { + return make_iter(add_alignment_assumption(this->_end)); + } - assign(other.begin(), other.end()); - return *this; + [[nodiscard]] constexpr const_iterator + end() const noexcept { + return make_iter(add_alignment_assumption(this->_end)); } - constexpr vector& operator=(vector&& other) noexcept( - std::allocator_traits::propagate_on_container_move_assignment::value || - std::allocator_traits::is_always_equal::value) { - if (this == &other) [[unlikely]] { - return *this; - } + [[nodiscard]] constexpr reverse_iterator + rbegin() noexcept { + return reverse_iterator(end()); + } - clear(); - if constexpr (allocator_traits::propagate_on_container_move_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != other.get_allocator()) { - allocator_traits::deallocate(_allocator, _begin, capacity()); - } - } - _allocator = other.get_allocator(); - } + [[nodiscard]] constexpr const_reverse_iterator + rbegin() const noexcept { + return const_reverse_iterator(end()); + } - if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) { - swap_without_allocator(std::move(other)); - } else { - if (get_allocator() == other.get_allocator()) { - swap_without_allocator(std::move(other)); - } else { - assign(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end())); - other.clear(); - } - } - return *this; + [[nodiscard]] constexpr reverse_iterator + rend() noexcept { + return reverse_iterator(begin()); } - constexpr vector& operator=(std::initializer_list list) { - assign(list.begin(), list.end()); - return *this; + [[nodiscard]] constexpr const_reverse_iterator + rend() const noexcept { + return const_reverse_iterator(begin()); } - // assign - constexpr void assign(size_type count, const T& value) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error); - if (count > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_fill_n(new_begin, count, value); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _capacity = _begin + count; - } else if (size() >= count) { - std::fill_n(_begin, count, value); - std::destroy(_begin + count, _end); - } else { - std::fill_n(_begin, size(), value); - std::uninitialized_fill_n(_begin + size(), count - size(), value); - } - _end = _begin + count; + [[nodiscard]] constexpr const_iterator + cbegin() const noexcept { + return begin(); } - template - constexpr void assign(InputIterator first, InputIterator last) { - const size_type count = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error); - if (count > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_copy(first, last, new_begin); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _capacity = _begin + count; - } else if (size() >= count) { - std::copy(first, last, _begin); - std::destroy(_begin + count, _end); - } else { - std::copy(first, first + size(), _begin); - std::uninitialized_copy(first + size(), last, _begin + size()); - } - _end = _begin + count; + [[nodiscard]] constexpr const_iterator + cend() const noexcept { + return end(); } - constexpr void assign(std::initializer_list list) { - assign(list.begin(), list.end()); + [[nodiscard]] constexpr const_reverse_iterator + crbegin() const noexcept { + return rbegin(); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr void assign_range(Range&& range) { - assign(std::ranges::begin(range), std::ranges::end(range)); + [[nodiscard]] constexpr const_reverse_iterator + crend() const noexcept { + return rend(); } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - // get_allocator - constexpr allocator_type get_allocator() const { - return _allocator; + // + // [vector.capacity], capacity + // + [[nodiscard]] constexpr size_type size() const noexcept { + return static_cast(this->_end - this->_begin); } - // element access - constexpr reference at(size_type position) { - PLUGIFY_ASSERT(position < size(), "plg::vector::at(): input index is out of bounds", std::out_of_range); - return *(_begin + position); + [[nodiscard]] constexpr size_type + capacity() const noexcept { + return static_cast(this->_cap - this->_begin); } - constexpr const_reference at(size_type position) const { - PLUGIFY_ASSERT(position < size(), "plg::vector::at(): input index is out of bounds", std::out_of_range); - return *(_begin + position); + [[nodiscard]] constexpr bool + empty() const noexcept { + return this->_begin == this->_end; } - constexpr reference operator[](size_type position) noexcept { - return *(_begin + position); + [[nodiscard]] constexpr size_type + max_size() const noexcept { + return std::min( + alloc_traits::max_size(this->_alloc), + std::numeric_limits::max() + ); } - constexpr const_reference operator[](size_type position) const noexcept { - return *(_begin + position); + constexpr void reserve(size_type n); + constexpr void shrink_to_fit() noexcept; + + // + // element access + // + [[nodiscard]] constexpr reference + operator[](size_type n) noexcept { + PLUGIFY_ASSERT(n < size(), "vector[] index out of bounds"); + return this->_begin[n]; } - constexpr reference front() { - PLUGIFY_ASSERT(!empty(), "plg::vector::front(): vector is empty", std::length_error); - return *_begin; + [[nodiscard]] constexpr const_reference + operator[](size_type n) const noexcept { + PLUGIFY_ASSERT(n < size(), "vector[] index out of bounds"); + return this->_begin[n]; } - constexpr const_reference front() const { - PLUGIFY_ASSERT(!empty(), "plg::vector::front(): vector is empty", std::length_error); - return *_begin; + [[nodiscard]] constexpr reference at(size_type n) { + if (n >= size()) { + this->throw_out_of_range(); + } + return this->_begin[n]; } - constexpr reference back() { - PLUGIFY_ASSERT(!empty(), "plg::vector::back(): vector is empty", std::length_error); - return *(_end - 1); + [[nodiscard]] constexpr const_reference + at(size_type n) const { + if (n >= size()) { + this->throw_out_of_range(); + } + return this->_begin[n]; } - constexpr const_reference back() const { - PLUGIFY_ASSERT(!empty(), "plg::vector::back(): vector is empty", std::length_error); - return *(_end - 1); + [[nodiscard]] constexpr reference front() noexcept { + PLUGIFY_ASSERT(!empty(), "front() called on an empty vector"); + return *this->_begin; } - constexpr T* data() noexcept { - return _begin; + [[nodiscard]] constexpr const_reference + front() const noexcept { + PLUGIFY_ASSERT(!empty(), "front() called on an empty vector"); + return *this->_begin; } - constexpr const T* data() const noexcept { - return _begin; + [[nodiscard]] constexpr reference back() noexcept { + PLUGIFY_ASSERT(!empty(), "back() called on an empty vector"); + return *(this->_end - 1); } - // iterators - constexpr iterator begin() noexcept { - return iterator(_begin); + [[nodiscard]] constexpr const_reference + back() const noexcept { + PLUGIFY_ASSERT(!empty(), "back() called on an empty vector"); + return *(this->_end - 1); } - constexpr const_iterator begin() const noexcept { - return const_iterator(_begin); + // + // [vector.data], data access + // + [[nodiscard]] constexpr value_type* + data() noexcept { + return std::to_address(this->_begin); } - constexpr const_iterator cbegin() const noexcept { - return const_iterator(_begin); + [[nodiscard]] constexpr const value_type* + data() const noexcept { + return std::to_address(this->_begin); } - constexpr iterator end() noexcept { - return iterator(_end); + // + // [vector.modifiers], modifiers + // + constexpr void push_back(const_reference x) { + emplace_back(x); } - constexpr const_iterator end() const noexcept { - return const_iterator(_end); + constexpr void push_back(value_type&& x) { + emplace_back(std::move(x)); } - constexpr const_iterator cend() const noexcept { - return const_iterator(_end); + template + constexpr + reference + emplace_back(Args&&... args); + + template + constexpr void + emplace_back_assume_capacity(Args&&... args) { + PLUGIFY_ASSERT( + size() < capacity(), + "We assume that we have enough space to insert an element at the end of the vector" + ); + ConstructTransaction tx(*this, 1); + alloc_traits::construct(this->_alloc, std::to_address(tx.pos_), std::forward(args)...); + ++tx.pos_; } - constexpr reverse_iterator rbegin() noexcept { - return reverse_iterator(_end); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr void append_range(Range&& range) { + insert_range(end(), std::forward(range)); + } +#endif + + constexpr void pop_back() { + PLUGIFY_ASSERT(!empty(), "vector::pop_back called on an empty vector"); + this->destruct_at_end(this->_end - 1); } - constexpr const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(_end); + constexpr iterator + insert(const_iterator position, const_reference x); + + constexpr iterator + insert(const_iterator position, value_type&& x); + template + constexpr iterator + emplace(const_iterator position, Args&&... args); + + constexpr iterator + insert(const_iterator position, size_type n, const_reference x); + + template + constexpr iterator + insert(const_iterator position, InputIterator first, InputIterator last) { + return insert_with_sentinel(position, first, last); } - constexpr const_reverse_iterator crbegin() const noexcept { - return const_reverse_iterator(_end); + template + constexpr iterator + insert(const_iterator position, ForwardIterator first, ForwardIterator last) { + return insert_with_size(position, first, last, std::distance(first, last)); } - constexpr reverse_iterator rend() noexcept { - return reverse_iterator(_begin); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr iterator + insert_range(const_iterator position, Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + return insert_with_size(position, std::ranges::begin(range), std::ranges::end(range), n); + + } else { + return insert_with_sentinel(position, std::ranges::begin(range), std::ranges::end(range)); + } } +#endif - constexpr const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(_begin); + constexpr iterator + insert(const_iterator position, std::initializer_list il) { + return insert(position, il.begin(), il.end()); } - constexpr const_reverse_iterator crend() const noexcept { - return const_reverse_iterator(_begin); + constexpr iterator erase(const_iterator position); + constexpr iterator + erase(const_iterator first, const_iterator last); + + constexpr void clear() noexcept { + size_type old_size = size(); + base_destruct_at_end(this->_begin); + annotate_shrink(old_size); } - // capacity - constexpr bool empty() const { - return (_begin == _end); + constexpr void resize(size_type sz); + constexpr void + resize(size_type sz, const_reference x); + + constexpr void swap(vector&) noexcept; + + constexpr bool invariants() const; + + private: + pointer _begin = nullptr; + pointer _end = nullptr; + pointer _cap = nullptr; + PLUGIFY_NO_UNIQUE_ADDRESS + allocator_type _alloc; + + // Allocate space for n objects + // throws length_error if n > max_size() + // throws (probably bad_alloc) if memory run out + // Precondition: _begin == _end == _cap == nullptr + // Precondition: n > 0 + // Postcondition: capacity() >= n + // Postcondition: size() == 0 + constexpr void vallocate(size_type n) { + if (n > max_size()) { + this->throw_length_error(); + } + auto allocation = allocate_at_least(this->_alloc, n); + _begin = allocation.ptr; + _end = allocation.ptr; + _cap = _begin + allocation.count; + annotate_new(0); + } + + constexpr void vdeallocate() noexcept; + constexpr size_type recommend(size_type new_size) const; + constexpr void construct_at_end(size_type n); + constexpr void + construct_at_end(size_type n, const_reference x); + + template + constexpr void + init_with_size(InputIterator first, Sentinel last, size_type n) { + auto guard = make_exception_guard(destroy_vector(*this)); + + if (n > 0) { + vallocate(n); + construct_at_end(std::move(first), std::move(last), n); + } + + guard.complete(); } - constexpr size_type size() const noexcept { - return static_cast(_end - _begin); + template + constexpr void + init_with_sentinel(InputIterator first, Sentinel last) { + auto guard = make_exception_guard(destroy_vector(*this)); + + for (; first != last; ++first) { + emplace_back(*first); + } + + guard.complete(); } - constexpr size_type max_size() const noexcept { - return allocator_traits::max_size(_allocator); + template + constexpr void + assign_with_sentinel(Iterator first, Sentinel last); + + // The `Iterator` in `*_with_size` functions can be input-only only if called from + // `*_range` (since C++23). Otherwise, `Iterator` is a forward iterator. + + template + constexpr void + assign_with_size(Iterator first, Sentinel last, difference_type n); + + template + requires (!std::same_as())&&, value_type&&>) + constexpr void + insert_assign_n_unchecked(Iterator first, difference_type n, pointer position) { + for (pointer end_position = position + n; position != end_position; + ++position, (void) ++first) { + detail::temp_value tmp(this->_alloc, *first); + *position = std::move(tmp.get()); + } } - constexpr void reserve(size_type new_capacity) { - PLUGIFY_ASSERT(new_capacity <= max_size(), "plg::vector::reserve(): allocated memory size would exceed max_size()", std::length_error); - if (new_capacity > capacity()) { - reallocate(new_capacity); + template + requires (std::same_as())&&, value_type&&>) + constexpr void + insert_assign_n_unchecked(Iterator first, difference_type n, pointer position) { +#if PLUGIFY_HAS_CXX23 + if constexpr (!std::forward_iterator) { + // Handles input-only sized ranges for insert_range + std::ranges::copy_n(std::move(first), n, position); + } else +#endif + { + std::copy_n(first, n, position); } } - constexpr size_type capacity() const noexcept { - return static_cast(_capacity - _begin); + template + constexpr iterator + insert_with_sentinel(const_iterator position, InputIterator first, Sentinel last); + + template + constexpr iterator + insert_with_size(const_iterator position, Iterator first, Sentinel last, difference_type n); + + template + constexpr void + construct_at_end(InputIterator first, Sentinel last, size_type n); + + constexpr void append(size_type n); + constexpr void + append(size_type n, const_reference x); + + constexpr iterator make_iter(pointer p) noexcept { + return iterator(p); } - constexpr void shrink_to_fit() { - reallocate(size()); + constexpr const_iterator make_iter(const_pointer p) const noexcept { + return const_iterator(p); } - // modifiers - constexpr void clear() noexcept { - std::destroy(_begin, _end); - _end = _begin; - } - - constexpr iterator insert(const_iterator position, const T& value) { - return emplace(position, value); - } - - constexpr iterator insert(const_iterator position, T&& value) { - return emplace(position, std::move(value)); - } - - constexpr iterator insert(const_iterator position, size_type count, const T& value) { - const size_type sz = size(); - const size_type new_size = sz + count; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::insert(): pos out of range", std::out_of_range); - if (count != 0) { - if (new_size > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, new_size); - pointer const old_position = _begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - pointer const new_position = new_begin + position_distance; - std::uninitialized_fill_n(new_position, count, value); - std::uninitialized_move(old_position, _end, new_position + count); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _end; - } else { - pointer const pointer_position = _begin + position_distance; - std::uninitialized_fill_n(_end, count, value); - _end += count; - std::rotate(pointer_position, _end - count, _end); - } - } - return begin() + position_distance; + constexpr void + swap_out_circular_buffer(split_buffer& v); + constexpr pointer + swap_out_circular_buffer(split_buffer& v, pointer p); + constexpr void + move_range(pointer from_s, pointer from_e, pointer to); + constexpr void + move_assign(vector& c, std::true_type) noexcept(std::is_nothrow_move_assignable::value); + constexpr void + move_assign(vector& c, std::false_type) noexcept(alloc_traits::is_always_equal::value); + + constexpr void + destruct_at_end(pointer new_last) noexcept { + size_type old_size = size(); + base_destruct_at_end(new_last); + annotate_shrink(old_size); } - template - constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last) { - const size_type sz = size(); - const size_type count = static_cast(std::distance(first, last)); - const size_type new_size = sz + count; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::insert(): pos out of range", std::out_of_range); - if (count != 0) { - if (new_size > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, new_size); - pointer const old_position = _begin + position_distance; - pointer const new_position = new_begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - std::uninitialized_copy(first, last, new_position); - std::uninitialized_move(old_position, _end, new_position + count); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _end; - } else { - pointer const pointer_position = _begin + position_distance; - std::uninitialized_copy(first, last, _end); - _end += count; - std::rotate(pointer_position, _end - count, _end); - } - } - return begin() + position_distance; + template + constexpr inline pointer + emplace_back_slow_path(Args&&... args); + + // The following functions are no-ops outside of AddressSanitizer mode. + // We call annotations for every allocator, unless explicitly disabled. + // + // To disable annotations for a particular allocator, change value of + // asan_annotate_container_with_allocator to false. + // For more details, see the "Using libc++" documentation page or + // the documentation for sanitizer_annotate_contiguous_container. + + constexpr void + annotate_contiguous_container( + [[maybe_unused]] const void* old_mid, + [[maybe_unused]] const void* new_mid + ) const { + plg::annotate_contiguous_container(data(), data() + capacity(), old_mid, new_mid); } - constexpr iterator insert(const_iterator position, std::initializer_list list) { - return insert(position, list.begin(), list.end()); + constexpr void + annotate_new(size_type current_size) const noexcept { + annotate_contiguous_container(data() + capacity(), data() + current_size); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr iterator insert_range(const_iterator pos, Range&& range) { - return insert(pos - begin(), std::ranges::begin(range), std::ranges::end(range)); + constexpr void annotate_delete() const noexcept { + annotate_contiguous_container(data() + size(), data() + capacity()); } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - template - iterator emplace(const_iterator position, Args&&... args) { - const size_type sz = size(); - const size_type new_size = sz + 1; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::emplace(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::emplace(): pos out of range", std::out_of_range); - if (position == cend()) { - emplace_back(std::forward(args)...); - } else { - if (is_full()) { - const size_type new_capacity = calculate_new_capacity(); - pointer const new_begin = allocator_traits::allocate(_allocator, new_capacity); - pointer const old_position = _begin + position_distance; - pointer const new_position = new_begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - std::construct_at(new_position, std::forward(args)...); - std::uninitialized_move(old_position, _end, new_position + 1); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _begin + new_capacity; - } else { - pointer const pointer_position = _begin + position_distance; - std::construct_at(_end, std::forward(args)...); - ++_end; - std::rotate(pointer_position, _end - 1, _end); - } - } - return begin() + position_distance; + constexpr void + annotate_increase(size_type n) const noexcept { + annotate_contiguous_container(data() + size(), data() + size() + n); } - constexpr iterator erase(const_iterator position) { - iterator nonconst_position = const_iterator_cast(position); - if (nonconst_position + 1 != end()) { - std::rotate(nonconst_position, nonconst_position + 1, end()); + constexpr void + annotate_shrink(size_type old_size) const noexcept { + annotate_contiguous_container(data() + old_size, data() + size()); + } + + struct ConstructTransaction { + constexpr + explicit ConstructTransaction(vector& v, size_type n) + : v_(v) + , pos_(v._end) + , new_end_(v._end + n) { + v.annotate_increase(n); } - --_end; - std::destroy_at(_end); - return nonconst_position; - } - - constexpr iterator erase(const_iterator first, const_iterator last) { - PLUGIFY_ASSERT(first <= last, "plg::vector::erase(): called with invalid range", std::out_of_range); - iterator nonconst_first = const_iterator_cast(first); - iterator nonconst_last = const_iterator_cast(last); - if (nonconst_first != nonconst_last) { - if (nonconst_last != end()) { - std::rotate(nonconst_first, nonconst_last, end()); + + constexpr ~ConstructTransaction() { + v_._end = pos_; + if (pos_ != new_end_) { + v_.annotate_shrink(new_end_ - v_._begin); } - _end = nonconst_first.base() + static_cast(end() - nonconst_last); - std::destroy(_end, _end + static_cast(std::distance(first, last))); } - return nonconst_first; - } - constexpr void push_back(const T& value) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, value); - }); - ++_end; + vector& v_; + pointer pos_; + const const_pointer new_end_; + + ConstructTransaction(const ConstructTransaction&) = delete; + ConstructTransaction& operator=(const ConstructTransaction&) = delete; + }; + + constexpr void + base_destruct_at_end(pointer new_last) noexcept { + pointer soon_to_be_end = this->_end; + while (new_last != soon_to_be_end) { + alloc_traits::destroy(this->_alloc, std::to_address(--soon_to_be_end)); + } + this->_end = new_last; } - constexpr void push_back(T&& value) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, std::move(value)); - }); - ++_end; + constexpr void copy_assign_alloc(const vector& c) { + copy_assign_alloc( + c, + std::integral_constant() + ); } - template - constexpr reference emplace_back(Args&&... args) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::emplace_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, std::forward(args)...); - }); - ++_end; - return back(); + constexpr void + move_assign_alloc(vector& c) noexcept( + !alloc_traits::propagate_on_container_move_assignment::value + || std::is_nothrow_move_assignable::value + ) { + move_assign_alloc( + c, + std::integral_constant() + ); } - constexpr void pop_back() { - PLUGIFY_ASSERT(!empty(), "plg::vector::pop_back(): vector is empty", std::length_error); - --_end; - std::destroy_at(_end); + [[noreturn]] static void throw_length_error() { + PLUGIFY_THROW("allocated memory size would exceed max_size()", std::length_error); } - constexpr void resize(size_type count) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error); - resize_to(count, detail::initialized_value_tag{}); + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); } - constexpr void resize(size_type count, const T& value) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error); - resize_to(count, value); + constexpr void + copy_assign_alloc(const vector& c, std::true_type) { + if (this->_alloc != c._alloc) { + clear(); + annotate_delete(); + alloc_traits::deallocate(this->_alloc, this->_begin, capacity()); + this->_begin = this->_end = this->_cap = nullptr; + } + this->_alloc = c._alloc; } - constexpr vector& operator+=(const T& value) { - push_back(value); - return *this; + constexpr void + copy_assign_alloc(const vector&, std::false_type) { } - constexpr vector& operator+=(T&& value) { - push_back(std::move(value)); - return *this; + constexpr void + move_assign_alloc(vector& c, std::true_type) noexcept( + std::is_nothrow_move_assignable_v + ) { + this->_alloc = std::move(c._alloc); } - constexpr vector& operator+=(const vector& other) { - insert(end(), other.begin(), other.end()); - return *this; + constexpr void + move_assign_alloc(vector&, std::false_type) noexcept { } - constexpr vector& operator+=(vector&& other) { - if (this == &other) [[unlikely]] { - return *this; + template + requires(std::is_pointer_v) + static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(Ptr p) noexcept { + if (!std::is_constant_evaluated()) { + return static_cast(std::assume_aligned(p)); } - - insert(end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end())); - return *this; + return p; } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr void append_range(Range&& range) { - return insert(end(), std::ranges::begin(range), std::ranges::end(range)); + template + requires(!std::is_pointer_v) + static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(Ptr p) noexcept { + return p; } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - constexpr void swap(vector& other) noexcept(std::allocator_traits::propagate_on_container_swap::value || std::allocator_traits::is_always_equal::value) { - using std::swap; - if constexpr (allocator_traits::propagate_on_container_swap::value) { - swap(_allocator, other._allocator); - } - swap(_begin, other._begin); - swap(_end, other._end); - swap(_capacity, other._capacity); + constexpr void + swap_layouts(split_buffer& sb) { + auto vector_begin = _begin; + auto vector_sentinel = _end; + auto vector_cap = _cap; + + auto sb_begin = sb.begin(); + auto sb_sentinel = sb.raw_sentinel(); + auto sb_cap = sb.raw_capacity(); + + // TODO: replace with set_valid_range and set_capacity when vector supports it. + _begin = sb_begin; + _end = sb_sentinel; + _cap = sb_cap; + + sb.set_valid_range(vector_begin, vector_sentinel); + sb.set_capacity(vector_cap); } + }; + + template < + std::input_iterator InputIterator, + is_allocator Alloc> + vector(InputIterator, InputIterator, Alloc = Alloc()) + -> vector, Alloc>; + +#if PLUGIFY_HAS_CXX23 + template < + std::ranges::input_range Range, + is_allocator Alloc> + vector(std::from_range_t, Range&&, Alloc = Alloc()) + -> vector, Alloc>; +#endif + + // swap_out_circular_buffer relocates the objects in [_begin, _end) into the front of v and + // swaps the buffers of *this and v. It is assumed that v provides space for exactly (_end - + // _begin) objects in the front. This function has a strong exception guarantee. + template + constexpr void + vector::swap_out_circular_buffer(split_buffer& v) { + annotate_delete(); + auto new_begin = v.begin() - size(); + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(_begin), + std::to_address(_end), + std::to_address(new_begin) + ); + v.set_valid_range(new_begin, v.end()); + _end = _begin; // All the objects have been destroyed by relocating them. + + swap_layouts(v); + v.set_data(v.begin()); + annotate_new(size()); + } - constexpr operator std::span() noexcept { - return std::span(data(), size()); + // swap_out_circular_buffer relocates the objects in [_begin, p) into the front of v, the + // objects in [p, _end) into the back of v and swaps the buffers of *this and v. It is assumed + // that v provides space for exactly (p - _begin) objects in the front and space for at least + // (_end - p) objects in the back. This function has a strong exception guarantee if _begin == p + // || _end == p. + template + constexpr typename vector::pointer + vector::swap_out_circular_buffer( + split_buffer& v, + pointer p + ) { + annotate_delete(); + pointer ret = v.begin(); + + // Relocate [p, _end) first to avoid having a hole in [_begin, _end) + // in case something in [_begin, p) throws. + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(p), + std::to_address(_end), + std::to_address(v.end()) + ); + auto relocated_so_far = _end - p; + v.set_sentinel(v.end() + relocated_so_far); + _end = p; // The objects in [p, _end) have been destroyed by relocating them. + auto new_begin = v.begin() - (p - _begin); + + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(_begin), + std::to_address(p), + std::to_address(new_begin) + ); + v.set_valid_range(new_begin, v.end()); + _end = _begin; // All the objects have been destroyed by relocating them. + swap_layouts(v); + v.set_data(v.begin()); + annotate_new(size()); + return ret; + } + + template + constexpr void vector::vdeallocate() noexcept { + if (this->_begin != nullptr) { + clear(); + annotate_delete(); + alloc_traits::deallocate(this->_alloc, this->_begin, capacity()); + this->_begin = this->_end = this->_cap = nullptr; } + } - constexpr operator std::span() const noexcept { - return std::span(data(), size()); + // Precondition: new_size > capacity() + template + constexpr inline + typename vector::size_type + vector::recommend(size_type new_size) const { + const size_type ms = max_size(); + if (new_size > ms) { + this->throw_length_error(); + } + const size_type cap = capacity(); + if (cap >= ms / 2) { + return ms; } + return std::max(2 * cap, new_size); + } - constexpr std::span span() const noexcept { - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == size() + n + template + constexpr void vector::construct_at_end(size_type n) { + ConstructTransaction tx(*this, n); + const_pointer new_end = tx.new_end_; + for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos)); } + } - constexpr std::span span() noexcept { - return std::span(data(), size()); + // Copy constructs n objects starting at _end from x + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == old size() + n + // Postcondition: [i] == x for all i in [size() - n, n) + template + constexpr inline void + vector::construct_at_end(size_type n, const_reference x) { + ConstructTransaction tx(*this, n); + const_pointer new_end = tx.new_end_; + for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos), x); } + } + + template + template + constexpr void + vector::construct_at_end(InputIterator first, Sentinel last, size_type n) { + ConstructTransaction tx(*this, n); + tx.pos_ = uninitialized_allocator_copy( + this->_alloc, + std::move(first), + std::move(last), + tx.pos_ + ); + } - template - constexpr std::span span_size() { - PLUGIFY_ASSERT(size() == Size, "plg::vector::span_size(): const_span_size argument does not match size of vector", std::length_error); - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Postcondition: size() == size() + n + // Exception safety: strong. + template + constexpr void vector::append(size_type n) { + if (static_cast(this->_cap - this->_end) >= n) { + this->construct_at_end(n); + } else { + split_buffer v(recommend(size() + n), size(), this->_alloc); + v.construct_at_end(n); + swap_out_circular_buffer(v); } + } - template - constexpr std::span const_span_size() const { - PLUGIFY_ASSERT(size() == Size, "plg::vector::const_span_size(): const_span_size argument does not match size of vector", std::length_error); - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Postcondition: size() == size() + n + // Exception safety: strong. + template + constexpr void + vector::append(size_type n, const_reference x) { + if (static_cast(this->_cap - this->_end) >= n) { + this->construct_at_end(n, x); + } else { + split_buffer v(recommend(size() + n), size(), this->_alloc); + v.construct_at_end(n, x); + swap_out_circular_buffer(v); } + } + + template + constexpr inline + vector::vector(vector&& x) noexcept + : _alloc(std::move(x._alloc)) { + this->_begin = x._begin; + this->_end = x._end; + this->_cap = x._cap; + x._begin = x._end = x._cap = nullptr; + } - constexpr std::span byte_span() const noexcept { - return std::as_bytes(span()); + template + constexpr inline + vector::vector(vector&& x, const std::type_identity_t& a) + : _alloc(a) { + if (a == x._alloc) { + this->_begin = x._begin; + this->_end = x._end; + this->_cap = x._cap; + x._begin = x._end = x._cap = nullptr; + } else { + using Ip = std::move_iterator; + init_with_size(Ip(x.begin()), Ip(x.end()), x.size()); } + } - constexpr std::span byte_span() noexcept { - return std::as_writable_bytes(span()); + template + constexpr void + vector::move_assign(vector& c, std::false_type) noexcept( + alloc_traits::is_always_equal::value + ) { + if (this->_alloc != c._alloc) { + using Ip = std::move_iterator; + assign(Ip(c.begin()), Ip(c.end())); + } else { + move_assign(c, std::true_type()); } + } - constexpr bool contains(const T& elem) const { - return std::find(begin(), end(), elem) != end(); + template + constexpr void + vector::move_assign(vector& c, std::true_type) noexcept( + std::is_nothrow_move_assignable::value + ) { + vdeallocate(); + move_assign_alloc(c); // this can throw + this->_begin = c._begin; + this->_end = c._end; + this->_cap = c._cap; + c._begin = c._end = c._cap = nullptr; + } + + template + constexpr inline vector& + vector::operator=(const vector& x) { + if (this != std::addressof(x)) { + copy_assign_alloc(x); + assign(x._begin, x._end); } + return *this; + } - template - constexpr bool contains_if(F predicate) { - return std::find_if(begin(), end(), predicate) != end(); + template + template + constexpr void + vector::assign_with_sentinel(Iterator first, Sentinel last) { + pointer cur = _begin; + for (; first != last && cur != _end; ++first, (void) ++cur) { + *cur = *first; + } + if (cur != _end) { + destruct_at_end(cur); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } } + } - constexpr auto find(const T& value) const { - return std::find(begin(), end(), value); + template + template + constexpr void + vector::assign_with_size(Iterator first, Sentinel last, difference_type n) { + size_type new_size = static_cast(n); + if (new_size <= capacity()) { + if (new_size > size()) { +#if PLUGIFY_HAS_CXX23 + auto mid = std::ranges::copy_n(std::move(first), size(), this->_begin).in; + construct_at_end(std::move(mid), std::move(last), new_size - size()); +#else + Iterator mid = std::next(first, size()); + std::copy(first, mid, this->_begin); + construct_at_end(mid, last, new_size - size()); +#endif + } else { + pointer m = std::copy(std::move(first), last, this->_begin); + this->destruct_at_end(m); + } + } else { + vdeallocate(); + vallocate(recommend(new_size)); + construct_at_end(std::move(first), std::move(last), new_size); } + } - constexpr auto find(const T& value) { - return std::find(begin(), end(), value); + template + constexpr void + vector::assign(size_type n, const_reference u) { + if (n <= capacity()) { + size_type s = size(); + std::fill_n(this->_begin, std::min(n, s), u); + if (n > s) { + construct_at_end(n - s, u); + } else { + this->destruct_at_end(this->_begin + n); + } + } else { + vdeallocate(); + vallocate(recommend(static_cast(n))); + construct_at_end(n, u); } + } - template - constexpr auto find_if(F predicate) const { - return std::find_if(begin(), end(), predicate); + template + constexpr void vector::reserve(size_type n) { + if (n > capacity()) { + if (n > max_size()) { + this->throw_length_error(); + } + split_buffer v(n, size(), this->_alloc); + swap_out_circular_buffer(v); } + } - template - constexpr auto find_if(F predicate) { - return std::find_if(begin(), end(), predicate); + template + constexpr void vector::shrink_to_fit() noexcept { + if (capacity() > size()) { +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + split_buffer v(size(), size(), this->_alloc); + // The Standard mandates shrink_to_fit() does not increase the capacity. + // With equal capacity keep the existing buffer. This avoids extra work + // due to swapping the elements. + if (v.capacity() < capacity()) { + swap_out_circular_buffer(v); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + } +#endif // PLUGIFY_HAS_EXCEPTIONS } + } + + template + template + constexpr typename vector::pointer + vector::emplace_back_slow_path(Args&&... args) { + split_buffer v(recommend(size() + 1), size(), this->_alloc); + // v.emplace_back(std::forward(args)...); + pointer end = v.end(); + alloc_traits::construct(this->_alloc, std::to_address(end), std::forward(args)...); + v.set_sentinel(++end); + swap_out_circular_buffer(v); + return this->_end; + } - constexpr std::optional find_index(const T& value) { - const auto iter = std::find(begin(), end(), value); - if (iter == end()) { - return {}; + // This makes the compiler inline `else()` if `cond` is known to be false. Currently LLVM + // doesn't do that without the `builtin_constant_p`, since it considers `else` unlikely even + // through it's known to be run. See https://llvm.org/PR154292 + template + constexpr void + if_likely_else(bool cond, If _if, Else _else) { + if (__builtin_constant_p(cond)) { + if (cond) { + _if(); + } else { + _else(); + } + } else { + if (cond) [[likely]] { + _if(); } else { - return iter - begin(); + _else(); } } + } - constexpr std::optional find_index(const T& value) const { - const auto iter = std::find(begin(), end(), value); - if (iter == end()) { - return {}; - } else { - return iter - begin(); + template + template + constexpr inline + typename vector::reference + vector::emplace_back(Args&&... args) { + pointer end = this->_end; + if_likely_else( + end < this->_cap, + [&] { + emplace_back_assume_capacity(std::forward(args)...); + ++end; + }, + [&] { end = emplace_back_slow_path(std::forward(args)...); } + ); + + this->_end = end; + return *(end - 1); + } + + template + constexpr inline + typename vector::iterator + vector::erase(const_iterator position) { + PLUGIFY_ASSERT( + position != end(), + "vector::erase(iterator) called with a non-dereferenceable iterator" + ); + difference_type ps = position - cbegin(); + pointer p = this->_begin + ps; + this->destruct_at_end(std::move(p + 1, this->_end, p)); + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::erase(const_iterator first, const_iterator last) { + PLUGIFY_ASSERT( + first <= last, + "vector::erase(first, last) called with invalid range" + ); + pointer p = this->_begin + (first - begin()); + if (first != last) { + this->destruct_at_end(std::move(p + (last - first), this->_end, p)); + } + return make_iter(p); + } + + template + constexpr void + vector::move_range(pointer from_s, pointer from_e, pointer to) { + pointer old_last = this->_end; + difference_type n = old_last - to; + { + pointer i = from_s + n; + ConstructTransaction tx(*this, from_e - i); + for (pointer pos = tx.pos_; i < from_e; ++i, (void) ++pos, tx.pos_ = pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos), std::move(*i)); } } + std::move_backward(from_s, from_s + n, old_last); + } - template - constexpr std::optional find_index_if(F predicate) { - const auto iter = std::find_if(begin(), end(), predicate); - if (iter == end()) { - return {}; + template + constexpr typename vector::iterator + vector::insert(const_iterator position, const_reference x) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(x); } else { - return iter - begin(); + move_range(p, this->_end, p + 1); + const_pointer xr = std::pointer_traits::pointer_to(x); + if (is_pointer_in_range( + std::to_address(p), + std::to_address(_end), + std::addressof(x) + )) { + ++xr; + } + *p = *xr; + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(x); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::insert(const_iterator position, value_type&& x) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(std::move(x)); + } else { + move_range(p, this->_end, p + 1); + *p = std::move(x); + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(std::move(x)); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + template + constexpr typename vector::iterator + vector::emplace(const_iterator position, Args&&... args) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(std::forward(args)...); + } else { + detail::temp_value tmp(this->_alloc, std::forward(args)...); + move_range(p, this->_end, p + 1); + *p = std::move(tmp.get()); + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(std::forward(args)...); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::insert(const_iterator position, size_type n, const_reference x) { + pointer p = this->_begin + (position - begin()); + if (n > 0) { + if (n <= static_cast(this->_cap - this->_end)) { + size_type old_n = n; + pointer old_last = this->_end; + if (n > static_cast(this->_end - p)) { + size_type cx = n - (this->_end - p); + construct_at_end(cx, x); + n -= cx; + } + if (n > 0) { + move_range(p, old_last, p + old_n); + const_pointer xr = std::pointer_traits::pointer_to(x); + if (is_pointer_in_range( + std::to_address(p), + std::to_address(_end), + std::addressof(x) + )) { + xr += old_n; + } + std::fill_n(p, n, *xr); + } + } else { + split_buffer v( + recommend(size() + n), + p - this->_begin, + this->_alloc + ); + v.construct_at_end(n, x); + p = swap_out_circular_buffer(v, p); } } + return make_iter(p); + } + + template + template + constexpr typename vector::iterator + vector::insert_with_sentinel( + const_iterator position, + InputIterator first, + Sentinel last + ) { + difference_type off = position - begin(); + pointer p = this->_begin + off; + pointer old_last = this->_end; + for (; this->_end != this->_cap && first != last; ++first) { + emplace_back_assume_capacity(*first); + } + + if (first == last) { + (void) std::rotate(p, old_last, this->_end); + } else { + split_buffer v(_alloc); + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(_alloc, old_last, this->_end) + ); + v.construct_at_end_with_sentinel(std::move(first), std::move(last)); + split_buffer merged( + recommend(size() + v.size()), + off, + _alloc + ); // has `off` positions available at the front + uninitialized_allocator_relocate( + _alloc, + std::to_address(old_last), + std::to_address(this->_end), + std::to_address(merged.end()) + ); + guard.complete(); // Release the guard once objects in [old_last_, _end) have been + // successfully relocated. + merged.set_sentinel(merged.end() + (this->_end - old_last)); + this->_end = old_last; + uninitialized_allocator_relocate( + _alloc, + std::to_address(v.begin()), + std::to_address(v.end()), + std::to_address(merged.end()) + ); + merged.set_sentinel(merged.size() + v.size()); + v.set_sentinel(v.begin()); + p = swap_out_circular_buffer(merged, p); + } + return make_iter(p); + } - template - constexpr std::optional find_index_if(F predicate) const { - const auto iter = std::find_if(begin(), end(), predicate); - if (iter == end()) { - return {}; + template + template + constexpr typename vector::iterator + vector::insert_with_size( + const_iterator position, + Iterator first, + Sentinel last, + difference_type n + ) { + pointer p = this->_begin + (position - begin()); + if (n > 0) { + if (n <= this->_cap - this->_end) { + pointer old_last = this->_end; + difference_type dx = this->_end - p; + if (n > dx) { +#if PLUGIFY_HAS_CXX23 + if constexpr (!std::forward_iterator) { + construct_at_end(std::move(first), std::move(last), n); + std::rotate(p, old_last, this->_end); + } else +#endif + { + Iterator m = std::next(first, dx); + construct_at_end(m, last, n - dx); + if (dx > 0) { + move_range(p, old_last, p + n); + insert_assign_n_unchecked(first, dx, p); + } + } + } else { + move_range(p, old_last, p + n); + insert_assign_n_unchecked(std::move(first), n, p); + } } else { - return iter - begin(); + split_buffer v( + recommend(size() + n), + p - this->_begin, + this->_alloc + ); + v.construct_at_end_with_size(std::move(first), n); + p = swap_out_circular_buffer(v, p); } } - }; + return make_iter(p); + } + + template + constexpr void vector::resize(size_type sz) { + size_type cs = size(); + if (cs < sz) { + this->append(sz - cs); + } else if (cs > sz) { + this->destruct_at_end(this->_begin + sz); + } + } + + template + constexpr void + vector::resize(size_type sz, const_reference x) { + size_type cs = size(); + if (cs < sz) { + this->append(sz - cs, x); + } else if (cs > sz) { + this->destruct_at_end(this->_begin + sz); + } + } + + template + constexpr void vector::swap(vector& x) + noexcept + { + PLUGIFY_ASSERT( + alloc_traits::propagate_on_container_swap::value || this->_alloc == x._alloc, + "vector::swap: Either propagate_on_container_swap must be true" + " or the allocators must compare equal" + ); + std::swap(this->_begin, x._begin); + std::swap(this->_end, x._end); + std::swap(this->_cap, x._cap); + swap_allocator(this->_alloc, x._alloc); + } + + template + constexpr bool vector::invariants() const { + if (this->_begin == nullptr) { + if (this->_end != nullptr || this->_cap != nullptr) { + return false; + } + } else { + if (this->_begin > this->_end) { + return false; + } + if (this->_begin == this->_cap) { + return false; + } + if (this->_end > this->_cap) { + return false; + } + } + return true; + } // comparisons template @@ -1046,7 +1552,7 @@ namespace plg { } template - constexpr typename vector::size_type erase(vector& c, const U& value) { + constexpr vector::size_type erase(vector& c, const U& value) { auto it = std::remove(c.begin(), c.end(), value); auto r = std::distance(it, c.end()); c.erase(it, c.end()); @@ -1054,20 +1560,15 @@ namespace plg { } template - constexpr typename vector::size_type erase_if(vector& c, Pred pred) { + constexpr vector::size_type erase_if(vector& c, Pred pred) { auto it = std::remove_if(c.begin(), c.end(), pred); auto r = std::distance(it, c.end()); c.erase(it, c.end()); return r; } - // deduction guides - template::value_type>> - vector(InputIterator, InputIterator, Allocator = Allocator()) -> vector::value_type, Allocator>; - namespace pmr { template using vector = ::plg::vector>; } // namespace pmr - } // namespace plg diff --git a/test/cross_call_master/external/plugify/include/plg/version.hpp b/test/cross_call_master/external/plugify/include/plg/version.hpp index 6089f12..b8e8c00 100644 --- a/test/cross_call_master/external/plugify/include/plg/version.hpp +++ b/test/cross_call_master/external/plugify/include/plg/version.hpp @@ -13,15 +13,15 @@ #include #endif -#ifndef PLUGIFY_VECTOR_NO_STD_FORMAT -#include "plg/format.hpp" -#endif - +#include "plg/config.hpp" #include "plg/hash.hpp" -#include "plg/macro.hpp" #include "plg/string.hpp" #include "plg/vector.hpp" +#ifndef PLUGIFY_VECTOR_NO_STD_FORMAT +#include "plg/format.hpp" +#endif + // from https://github.com/Neargye/semver namespace plg { namespace detail { @@ -70,7 +70,7 @@ namespace plg { class version_parser; class prerelease_comparator; - } + } // namespace detail template class version { @@ -78,6 +78,11 @@ namespace plg { friend class detail::prerelease_comparator; public: + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value && + is_trivially_relocatable::value, version, void>; + constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase constexpr version(const version&) = default; constexpr version(version&&) = default; @@ -86,38 +91,38 @@ namespace plg { constexpr version& operator=(const version&) = default; constexpr version& operator=(version&&) = default; - constexpr I1 major() const noexcept { return major_; } - constexpr I2 minor() const noexcept { return minor_; } - constexpr I3 patch() const noexcept { return patch_; } + constexpr I1 major() const noexcept { return _major; } + constexpr I2 minor() const noexcept { return _minor; } + constexpr I3 patch() const noexcept { return _patch; } - constexpr const string& prerelease_tag() const { return prerelease_tag_; } - constexpr const string& build_metadata() const { return build_metadata_; } + constexpr const string& prerelease_tag() const { return _prerelease_tag; } + constexpr const string& build_metadata() const { return _build_metadata; } constexpr string to_string() const; private: - I1 major_ = 0; - I2 minor_ = 1; - I3 patch_ = 0; - string prerelease_tag_; - string build_metadata_; + I1 _major = 0; + I2 _minor = 1; + I3 _patch = 0; + string _prerelease_tag; + string _build_metadata; - vector prerelease_identifiers; + vector _prerelease_identifiers; constexpr std::size_t length() const noexcept { - return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 - + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) - + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); + return detail::length(_major) + detail::length(_minor) + detail::length(_patch) + 2 + + (_prerelease_tag.empty() ? 0 : _prerelease_tag.length() + 1) + + (_build_metadata.empty() ? 0 : _build_metadata.length() + 1); } constexpr void clear() noexcept { - major_ = 0; - minor_ = 1; - patch_ = 0; + _major = 0; + _minor = 1; + _patch = 0; - prerelease_tag_.clear(); - prerelease_identifiers.clear(); - build_metadata_.clear(); + _prerelease_tag.clear(); + _prerelease_identifiers.clear(); + _build_metadata.clear(); } }; @@ -126,24 +131,24 @@ namespace plg { string result; detail::resize_uninitialized{}.resize(result, length()); - auto it = result.end(); - if (!build_metadata_.empty()) { - it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); + auto* it = result.end(); + if (!_build_metadata.empty()) { + it = std::copy_backward(_build_metadata.begin(), _build_metadata.end(), it); *(--it) = '+'; } - if (!prerelease_tag_.empty()) { - it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); + if (!_prerelease_tag.empty()) { + it = std::copy_backward(_prerelease_tag.begin(), _prerelease_tag.end(), it); *(--it) = '-'; } - it = detail::to_chars(it, patch_); + it = detail::to_chars(it, _patch); *(--it) = '.'; - it = detail::to_chars(it, minor_); + it = detail::to_chars(it, _minor); *(--it) = '.'; - it = detail::to_chars(it, major_); + it = detail::to_chars(it, _major); return result; } @@ -160,7 +165,7 @@ namespace plg { [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } }; #endif - + enum class version_compare_option : std::uint8_t { exclude_prerelease, include_prerelease @@ -192,25 +197,22 @@ namespace plg { } template - constexpr bool cmp_less(T t, U u) noexcept - { + constexpr bool cmp_less(T t, U u) noexcept { if constexpr (std::is_signed_v == std::is_signed_v) - return t < u; - else if constexpr (std::is_signed_v) - return t < 0 || std::make_unsigned_t(t) < u; - else - return u >= 0 && t < std::make_unsigned_t(u); -} + return t < u; + else if constexpr (std::is_signed_v) + return t < 0 || std::make_unsigned_t(t) < u; + else + return u >= 0 && t < std::make_unsigned_t(u); + } template - constexpr bool cmp_less_equal(T t, U u) noexcept - { + constexpr bool cmp_less_equal(T t, U u) noexcept { return !cmp_less(u, t); } template - constexpr bool cmp_greater_equal(T t, U u) noexcept - { + constexpr bool cmp_greater_equal(T t, U u) noexcept { return !cmp_less(t, u); } @@ -220,28 +222,7 @@ namespace plg { } constexpr int compare(std::string_view lhs, std::string_view rhs) { -#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) - // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html - // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html - constexpr bool workaround = true; -#else - constexpr bool workaround = false; -#endif - - if constexpr (workaround) { - const auto size = std::min(lhs.size(), rhs.size()); - for (std::size_t i = 0; i < size; ++i) { - if (lhs[i] < rhs[i]) { - return -1; - } else if (lhs[i] > rhs[i]) { - return 1; - } - } - - return static_cast(lhs.size() - rhs.size()); - } else { - return lhs.compare(rhs); - } + return lhs.compare(rhs); } constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { @@ -292,28 +273,28 @@ namespace plg { class token_stream { public: constexpr token_stream() = default; - constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} + constexpr explicit token_stream(vector tokens) noexcept : _tokens(std::move(tokens)) {} constexpr void push(const token& token) noexcept { - tokens_.push_back(token); + _tokens.push_back(token); } constexpr token advance() noexcept { - const token token = get(current_); - ++current_; + const token token = get(_current); + ++_current; return token; } constexpr token peek(std::size_t k = 0) const noexcept { - return get(current_ + k); + return get(_current + k); } constexpr token previous() const noexcept { - return get(current_ - 1); + return get(_current - 1); } - constexpr bool advanceIfMatch(token& token, token_type type) noexcept { - if (get(current_).type != type) { + constexpr bool advance_if_match(token& token, token_type type) noexcept { + if (get(_current).type != type) { return false; } @@ -321,9 +302,9 @@ namespace plg { return true; } - constexpr bool advanceIfMatch(token_type type) noexcept { + constexpr bool advance_if_match(token_type type) noexcept { token token; - return advanceIfMatch(token, type); + return advance_if_match(token, type); } constexpr bool consume(token_type type) noexcept { @@ -335,20 +316,20 @@ namespace plg { } private: - std::size_t current_ = 0; - vector tokens_; + std::size_t _current = 0; + vector _tokens; constexpr token get(std::size_t i) const noexcept { - return tokens_[i]; + return _tokens[i]; } }; class lexer { public: - explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} + explicit constexpr lexer(std::string_view text) noexcept : _text{text}, _current_pos{0} {} constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { - from_chars_result result{ text_.data(), std::errc{} }; + from_chars_result result{ _text.data(), std::errc{} }; while (!is_eol()) { result = scan_token(token_stream); @@ -357,14 +338,14 @@ namespace plg { } } - token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); + token_stream.push({ token_type::eol, {}, _text.data() + _text.size() }); return result; } private: - std::string_view text_; - std::size_t current_pos_; + std::string_view _text; + std::size_t _current_pos; constexpr from_chars_result scan_token(token_stream& stream) noexcept { const char c = advance(); @@ -383,16 +364,16 @@ namespace plg { add_token(stream, token_type::plus); break; case '|': - if (advanceIfMatch('|')) { + if (advance_if_match('|')) { add_token(stream, token_type::logical_or); break; } return failure(get_prev_symbol()); case '<': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); + add_token(stream, token_type::range_operator, advance_if_match('=') ? range_operator::less_or_equal : range_operator::less); break; case '>': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); + add_token(stream, token_type::range_operator, advance_if_match('=') ? range_operator::greater_or_equal : range_operator::greater); break; case '=': add_token(stream, token_type::range_operator, range_operator::equal); @@ -417,51 +398,51 @@ namespace plg { stream.push({ type, value, lexeme}); } - constexpr char advance() noexcept { - char c = text_[current_pos_]; - current_pos_ += 1; + constexpr char advance() noexcept { + char c = _text[_current_pos]; + _current_pos += 1; return c; } - constexpr bool advanceIfMatch(char c) noexcept { + constexpr bool advance_if_match(char c) noexcept { if (is_eol()) { return false; } - if (text_[current_pos_] != c) { + if (_text[_current_pos] != c) { return false; } - current_pos_ += 1; + _current_pos += 1; return true; } constexpr const char* get_prev_symbol() const noexcept { - return text_.data() + current_pos_ - 1; + return _text.data() + _current_pos - 1; } - constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } + constexpr bool is_eol() const noexcept { return _current_pos >= _text.size(); } }; class prerelease_comparator { public: template [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { - if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { - return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); + if (lhs._prerelease_identifiers.empty() != rhs._prerelease_identifiers.empty()) { + return static_cast(rhs._prerelease_identifiers.size()) - static_cast(lhs._prerelease_identifiers.size()); } - const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); + const std::size_t count = std::min(lhs._prerelease_identifiers.size(), rhs._prerelease_identifiers.size()); for (std::size_t i = 0; i < count; ++i) { - const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); + const int compare_result = compare_identifier(lhs._prerelease_identifiers[i], rhs._prerelease_identifiers[i]); if (compare_result != 0) { return compare_result; } } - return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); + return static_cast(lhs._prerelease_identifiers.size()) - static_cast(rhs._prerelease_identifiers.size()); } private: @@ -478,45 +459,45 @@ namespace plg { class version_parser { public: - constexpr explicit version_parser(token_stream& stream) : stream_{stream} { + constexpr explicit version_parser(token_stream& stream) : _stream{stream} { } template constexpr from_chars_result parse(version& out) noexcept { out.clear(); - from_chars_result result = parse_number(out.major_); + from_chars_result result = parse_number(out._major); if (!result) { return result; } - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); + if (!_stream.consume(token_type::dot)) { + return failure(_stream.previous().lexeme); } - result = parse_number(out.minor_); + result = parse_number(out._minor); if (!result) { return result; } - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); + if (!_stream.consume(token_type::dot)) { + return failure(_stream.previous().lexeme); } - result = parse_number(out.patch_); + result = parse_number(out._patch); if (!result) { return result; } - if (stream_.advanceIfMatch(token_type::hyphen)) { - result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); + if (_stream.advance_if_match(token_type::hyphen)) { + result = parse_prerelease_tag(out._prerelease_tag, out._prerelease_identifiers); if (!result) { return result; } } - if (stream_.advanceIfMatch(token_type::plus)) { - result = parse_build_metadata(out.build_metadata_); + if (_stream.advance_if_match(token_type::plus)) { + result = parse_build_metadata(out._build_metadata); if (!result) { return result; } @@ -527,11 +508,11 @@ namespace plg { private: - token_stream& stream_; + token_stream& _stream; template constexpr from_chars_result parse_number(Int& out) { - token token = stream_.advance(); + token token = _stream.advance(); if (!is_digit(token)) { return failure(token.lexeme); @@ -542,16 +523,16 @@ namespace plg { if (first_digit == 0) { out = static_cast(result); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } - while (stream_.advanceIfMatch(token, token_type::digit)) { + while (_stream.advance_if_match(token, token_type::digit)) { result = result * 10 + std::get(token.value); } if (detail::number_in_range(result)) { out = static_cast(result); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } return failure(token.lexeme, std::errc::result_out_of_range); @@ -573,10 +554,10 @@ namespace plg { result.append(identifier); out_identifiers.push_back(make_prerelease_identifier(identifier)); - } while (stream_.advanceIfMatch(token_type::dot)); + } while (_stream.advance_if_match(token_type::dot)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr from_chars_result parse_build_metadata(string& out) { @@ -593,15 +574,15 @@ namespace plg { } result.append(identifier); - } while (stream_.advanceIfMatch(token_type::dot)); + } while (_stream.advance_if_match(token_type::dot)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr from_chars_result parse_prerelease_identifier(string& out) { string result; - token token = stream_.advance(); + token token = _stream.advance(); do { switch (token.type) { @@ -615,7 +596,7 @@ namespace plg { { const auto digit = std::get(token.value); - // numerical prerelease identifier doesn't allow leading zero + // numerical prerelease identifier doesn't allow leading zero // 1.2.3-1.alpha is valid, // 1.2.3-01b is valid as well, but // 1.2.3-01.alpha is not valid @@ -632,10 +613,10 @@ namespace plg { default: return failure(token.lexeme); } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + } while (_stream.advance_if_match(token, token_type::hyphen) || _stream.advance_if_match(token, token_type::letter) || _stream.advance_if_match(token, token_type::digit)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { @@ -651,7 +632,7 @@ namespace plg { constexpr from_chars_result parse_build_identifier(string& out) { string result; - token token = stream_.advance(); + token token = _stream.advance(); do { switch (token.type) { @@ -670,10 +651,10 @@ namespace plg { default: return failure(token.lexeme); } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + } while (_stream.advance_if_match(token, token_type::hyphen) || _stream.advance_if_match(token, token_type::letter) || _stream.advance_if_match(token, token_type::digit)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr bool is_leading_zero(int digit) noexcept { @@ -686,7 +667,7 @@ namespace plg { int digits = 0; while (true) { - const token token = stream_.peek(k); + const token token = _stream.peek(k); if (!is_alphanumeric(token)) { break; @@ -766,7 +747,7 @@ namespace plg { return success(token_stream.previous().lexeme); } - } // namespace semver::detail + } // namespace detail template [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { @@ -798,17 +779,15 @@ namespace plg { return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; } -#if __cpp_impl_three_way_comparison >= 201907L template [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); if (compare == 0) - return std::strong_ordering::equal; - if (compare > 0) - return std::strong_ordering::greater; - return std::strong_ordering::less; + return std::strong_ordering::equal; + if (compare > 0) + return std::strong_ordering::greater; + return std::strong_ordering::less; } -#endif template constexpr from_chars_result parse(std::string_view str, version& output) { @@ -824,44 +803,44 @@ namespace plg { template class range_comparator { public: - constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} + constexpr range_comparator(const version& v, range_operator op) noexcept : _v(v), _op(op) {} constexpr bool contains(const version& other) const noexcept { - switch (op_) { + switch (_op) { case range_operator::less: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) < 0; case range_operator::less_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) <= 0; case range_operator::greater: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) > 0; case range_operator::greater_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) >= 0; case range_operator::equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) == 0; } return false; } - constexpr const version& get_version() const noexcept { return v_; } + constexpr const version& get_version() const noexcept { return _v; } - constexpr range_operator get_operator() const noexcept { return op_; } + constexpr range_operator get_operator() const noexcept { return _op; } constexpr string to_string() const { string result; - switch (op_) { + switch (_op) { case range_operator::less: result += "<"; break; case range_operator::less_or_equal: result += "<="; break; case range_operator::greater: result += ">"; break; case range_operator::greater_or_equal: result += ">="; break; case range_operator::equal: result += "="; break; } - result += v_.to_string(); + result += _v.to_string(); return result; } private: - version v_; - range_operator op_; + version _v; + range_operator _op; }; class range_parser; @@ -878,40 +857,40 @@ namespace plg { } } - return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + return std::all_of(_ranges_comparators.begin(), _ranges_comparators.end(), [&](const auto& ranges_comparator) { return ranges_comparator.contains(v); }); } constexpr auto begin() const noexcept { - return ranges_comparators_.begin(); + return _ranges_comparators.begin(); } constexpr auto end() const noexcept { - return ranges_comparators_.end(); + return _ranges_comparators.end(); } constexpr std::size_t size() const noexcept { - return ranges_comparators_.size(); + return _ranges_comparators.size(); } constexpr bool empty() const noexcept { - return ranges_comparators_.empty(); + return _ranges_comparators.empty(); } constexpr string to_string() const { - return join(ranges_comparators_, " "); + return join(_ranges_comparators, " "); } private: - vector> ranges_comparators_; + vector> _ranges_comparators; constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { if (v.prerelease_tag().empty()) { return true; } - return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + return std::any_of(_ranges_comparators.begin(), _ranges_comparators.end(), [&](const auto& ranges_comparator) { const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; return has_prerelease && equal_without_prerelease; @@ -926,39 +905,39 @@ namespace plg { friend class detail::range_parser; constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { - return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { + return std::any_of(_ranges.begin(), _ranges.end(), [&](const auto& range) { return range.contains(v, option); }); } constexpr auto begin() const noexcept { - return ranges_.begin(); + return _ranges.begin(); } constexpr auto end() const noexcept { - return ranges_.end(); + return _ranges.end(); } constexpr std::size_t size() const noexcept { - return ranges_.size(); + return _ranges.size(); } constexpr bool empty() const noexcept { - return ranges_.empty(); + return _ranges.empty(); } constexpr string to_string() const { - return join(ranges_, " "); + return join(_ranges, " "); } private: - vector> ranges_; + vector> _ranges; }; namespace detail { class range_parser { public: - constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} + constexpr explicit range_parser(token_stream stream) noexcept : _stream(std::move(stream)) {} template constexpr from_chars_result parse(range_set& out) noexcept { @@ -974,59 +953,59 @@ namespace plg { ranges.push_back(range); skip_whitespaces(); - } while (stream_.advanceIfMatch(token_type::logical_or)); + } while (_stream.advance_if_match(token_type::logical_or)); - out.ranges_ = std::move(ranges); + out._ranges = std::move(ranges); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } - + private: - token_stream stream_; + token_stream _stream; template constexpr from_chars_result parse_range(detail::range& out) noexcept { do { skip_whitespaces(); - if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { + if (const auto res = parse_range_comparator(out._ranges_comparators); !res) { return res; } skip_whitespaces(); - } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); - - return success(stream_.peek().lexeme); + } while (_stream.check(token_type::range_operator) || _stream.check(token_type::digit)); + + return success(_stream.peek().lexeme); } template constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { range_operator op = range_operator::equal; token token; - if (stream_.advanceIfMatch(token, token_type::range_operator)) { + if (_stream.advance_if_match(token, token_type::range_operator)) { op = std::get(token.value); } skip_whitespaces(); version ver; - version_parser parser{ stream_ }; + version_parser parser{ _stream }; if (const auto res = parser.parse(ver); !res) { return res; } out.emplace_back(ver, op); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr void skip_whitespaces() noexcept { - while (stream_.advanceIfMatch(token_type::space)) { + while (_stream.advance_if_match(token_type::space)) { ; } } }; - } // namespace semver::detail + } // namespace detail template @@ -1039,7 +1018,7 @@ namespace plg { return detail::range_parser{ std::move(token_stream) }.parse(out); } -} // namespace semver +} // namespace plg #ifndef PLUGIFY_VECTOR_NO_STD_HASH // hash support diff --git a/test/cross_call_worker/CMakeLists.txt b/test/cross_call_worker/CMakeLists.txt index efa0c92..ab94486 100644 --- a/test/cross_call_worker/CMakeLists.txt +++ b/test/cross_call_worker/CMakeLists.txt @@ -42,8 +42,10 @@ else() endif() if(LINUX) - target_compile_definitions(${PROJECT_NAME} PRIVATE _GLIBCXX_USE_CXX11_ABI=0) + target_compile_definitions(${PROJECT_NAME} PRIVATE _GLIBCXX_USE_CXX11_ABI=1) target_link_libraries(${PROJECT_NAME} PRIVATE -static-libstdc++ -static-libgcc) + #target_compile_options(${PROJECT_NAME} PRIVATE $<$: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) + #target_link_libraries(${PROJECT_NAME} PRIVATE $<$: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE diff --git a/test/cross_call_worker/external/plugify/include/plg/allocator.hpp b/test/cross_call_worker/external/plugify/include/plg/allocator.hpp index 3c01cd5..3cc57b2 100644 --- a/test/cross_call_worker/external/plugify/include/plg/allocator.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/allocator.hpp @@ -1,85 +1,59 @@ #pragma once -#include // for std::size_t, std::ptrdiff_t -#include // for std::malloc, std::free, std::aligned_alloc -#include // for std::is_constant_evaluated -#include // for ::operator new, ::operator delete +#include // for std::size_t, std::ptrdiff_t +#include // for std::malloc, std::free, std::aligned_alloc +#include // for ::operator new, ::operator delete +#include // for std::is_constant_evaluated -#include "plg/macro.hpp" +#include "plg/config.hpp" namespace plg { - // Forward declaration for allocator template class allocator; - // Specialization for `void`, but we no longer need to define `pointer` and `const_pointer` template<> class allocator { public: using value_type = void; - // Rebind struct template struct rebind { using other = allocator; }; }; - // Define the custom allocator inheriting from std::allocator template class allocator { + static_assert(!std::is_const_v, "plg::allocator does not support const types"); + static_assert(!std::is_volatile_v, "plg::allocator does not support volatile types"); public: using value_type = T; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - // Default constructor constexpr allocator() noexcept = default; - // Copy constructor template constexpr allocator(const allocator&) noexcept {} - // Rebind struct template struct rebind { using other = allocator; }; - // Override allocate method to use custom allocation function - constexpr pointer allocate(size_type n, [[maybe_unused]] const_pointer hint = nullptr) { + [[nodiscard]] constexpr T* allocate(size_type n) { static_assert(sizeof(T) != 0, "cannot allocate incomplete types"); static_assert((alignof(T) & (alignof(T) - 1)) == 0, "alignof(T) must be a power of 2"); - if (n > max_size()) [[unlikely]] { - if (n > static_cast(-1) / sizeof(T)) { - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): bad array new length", std::bad_array_new_length); - } - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): too big", std::bad_alloc); + if (n > std::allocator_traits::max_size(*this)) { + throw_bad_array_new_length(); } - pointer ret; size_type size = n * sizeof(T); if (std::is_constant_evaluated()) { - ret = static_cast(::operator new(size)); + return static_cast(::operator new(size)); } else { - if constexpr (alignof(T) > alignof(std::max_align_t)) { - size_type aligned_size = (size + (alignof(T) - 1)) & ~(alignof(T) - 1); - ret = static_cast(aligned_allocate(alignof(T), aligned_size)); - } else { - ret = static_cast(std::malloc(size)); - } - - if (!ret) { - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): bad allocation", std::bad_alloc); - } + return malloc_allocate(size); } - - return ret; } - // Override deallocate method to use custom deallocation function - constexpr void deallocate(pointer p, [[maybe_unused]] size_type n) { + constexpr void deallocate(T* p, [[maybe_unused]] size_type n) { if (std::is_constant_evaluated()) { ::operator delete(p); } else { @@ -88,28 +62,114 @@ namespace plg { } private: - constexpr size_type max_size() noexcept { -#if __PTRDIFF_MAX__ < __SIZE_MAX__ - return static_cast(__PTRDIFF_MAX__) / sizeof(T); -#else - return static_cast(-1) / sizeof(T); -#endif // __PTRDIFF_MAX__ + static T* malloc_allocate(size_type size) { + T* ret; + if constexpr (alignof(T) > alignof(std::max_align_t)) { + size_type aligned_size = (size + (alignof(T) - 1)) & ~(alignof(T) - 1); + ret = static_cast(aligned_allocate(alignof(T), aligned_size)); + } else { + ret = static_cast(std::malloc(size)); + } + if (!ret) { + throw_bad_alloc(); + } + return ret; + } + + [[noreturn]] static void throw_bad_array_new_length() { + PLUGIFY_THROW("bad array new length", std::bad_array_new_length); } - void* aligned_allocate(size_type alignment, size_type size) { -#if _WIN32 + [[noreturn]] static void throw_bad_alloc() { + PLUGIFY_THROW("bad allocation", std::bad_alloc); + } + + static void* aligned_allocate(size_type alignment, size_type size) { +#if PLUGIFY_PLATFORM_WINDOWS return _aligned_malloc(size, alignment); #else return std::aligned_alloc(alignment, size); -#endif // _WIN32 +#endif // PLUGIFY_PLATFORM_WINDOWS } }; - // Comparison operators for compatibility template constexpr bool operator==(const allocator&, const allocator) { return true; } template constexpr bool operator!=(const allocator&, const allocator) { return false; } + template + void swap_allocator(Alloc& a1, Alloc& a2, std::true_type) { + using std::swap; + swap(a1, a2); + } + + template + void swap_allocator(Alloc&, Alloc&, std::false_type) noexcept {} + + template + void swap_allocator(Alloc& a1, Alloc& a2) { + swap_allocator(a1, a2, std::integral_constant::propagate_on_container_swap::value>()); + } + + template + struct allocation_result { + Pointer ptr; + Size count; + }; + + template + [[nodiscard]] allocation_result::pointer> + allocate_at_least(Alloc& alloc, size_t n) { + return { alloc.allocate(n), n }; + } + + template + constexpr bool is_pointer_in_range(const T* begin, const T* end, const U* ptr) { + if (std::is_constant_evaluated()) + return false; + return reinterpret_cast(begin) <= reinterpret_cast(ptr) && + reinterpret_cast(ptr) < reinterpret_cast(end); + } + + template + constexpr bool is_overlapping_range(const T* begin, const T* end, const U* begin2) { + auto size = end - begin; + auto end2 = begin2 + size; + return is_pointer_in_range(begin, end, begin2) || is_pointer_in_range(begin2, end2, begin); + } + + // asan_annotate_container_with_allocator determines whether containers with custom allocators are annotated. This is + // a public customization point to disable annotations if the custom allocator assumes that the memory isn't poisoned. + // See the https://libcxx.llvm.org/UsingLibcxx.html#turning-off-asan-annotation-in-containers for more information. +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + template + struct asan_annotate_container_with_allocator : std::true_type {}; +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + + // Annotate a contiguous range. + // [__first_storage, __last_storage) is the allocated memory region, + // __old_last_contained is the previously last allowed (unpoisoned) element, and + // __new_last_contained is the new last allowed (unpoisoned) element. + template + void annotate_contiguous_container( + [[maybe_unused]] const void* first_storage, + [[maybe_unused]] const void* last_storage, + [[maybe_unused]] const void* old_last_contained, + [[maybe_unused]] const void* new_last_contained + ) { +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + if (!std::is_constant_evaluated() + && asan_annotate_container_with_allocator::value + && first_storage != nullptr) { + __sanitizer_annotate_contiguous_container( + first_storage, + last_storage, + old_last_contained, + new_last_contained + ); + } +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + } } // namespace plg diff --git a/test/cross_call_worker/external/plugify/include/plg/concepts.hpp b/test/cross_call_worker/external/plugify/include/plg/concepts.hpp new file mode 100644 index 0000000..398018b --- /dev/null +++ b/test/cross_call_worker/external/plugify/include/plg/concepts.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include +#include + +#if PLUGIFY_HAS_CXX23 +# include +#endif + +namespace plg { +#if PLUGIFY_HAS_CXX23 + template + concept container_compatible_range = std::ranges::input_range && std::convertible_to, Type>; +#endif + + template + concept is_allocator = + // basic nested types (via allocator_traits) + requires { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::void_pointer; + typename std::allocator_traits::const_void_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; + } && + // required expressions / member calls (use allocator_traits helpers where appropriate) + requires( + Alloc& a, + typename std::allocator_traits::size_type n, + typename std::allocator_traits::pointer p, + typename std::allocator_traits::value_type& v, + const typename std::allocator_traits::value_type& cv + ) { + // allocation / deallocation + { a.allocate(n) } -> std::same_as::pointer>; + { a.deallocate(p, n) } -> std::same_as; + + // max_size: prefer allocator_traits::max_size (calls member or fallback) + { std::allocator_traits::max_size(a) } -> std::convertible_to::size_type>; + + // construct / destroy (via allocator_traits helpers; these must be well-formed) + { std::allocator_traits::construct(a, p, cv) } -> std::same_as; + { std::allocator_traits::destroy(a, p) } -> std::same_as; + + // optional helpful factory used by containers when copying them + { std::allocator_traits::select_on_container_copy_construction(a) } -> std::convertible_to; + }; + + template + concept is_char_traits = requires { + // Required type definitions + typename Traits::char_type; + typename Traits::int_type; + typename Traits::off_type; + typename Traits::pos_type; + typename Traits::state_type; + } && requires( + typename Traits::char_type c1, + typename Traits::char_type c2, + typename Traits::char_type& cr, + const typename Traits::char_type& ccr, + typename Traits::char_type* p, + const typename Traits::char_type* cp, + typename Traits::int_type i1, + typename Traits::int_type i2, + std::size_t n + ) { + // Character operations + { Traits::assign(cr, ccr) } -> std::same_as; + { Traits::eq(ccr, ccr) } -> std::convertible_to; + { Traits::lt(ccr, ccr) } -> std::convertible_to; + + // String operations + { Traits::compare(cp, cp, n) } -> std::convertible_to; + { Traits::length(cp) } -> std::convertible_to; + { Traits::find(cp, n, ccr) } -> std::convertible_to; + + // Memory operations + { Traits::move(p, cp, n) } -> std::same_as; + { Traits::copy(p, cp, n) } -> std::same_as; + { Traits::assign(p, n, c1) } -> std::same_as; + + // int_type operations + { Traits::not_eof(i1) } -> std::same_as; + { Traits::to_char_type(i1) } -> std::same_as; + { Traits::to_int_type(c1) } -> std::same_as; + { Traits::eq_int_type(i1, i2) } -> std::convertible_to; + { Traits::eof() } -> std::same_as; + }; + + // A type is trivially relocatable if a move construct + destroy of the original object is equivalent to + // `memcpy(dst, src, sizeof(T))`. + // + // Note that we don't use the __cpp_lib_trivially_relocatable Clang builtin right now because it does not + // implement the semantics of any current or future trivial relocation proposal and it can lead to + // incorrect optimizations on some platforms (Windows) and supported compilers (AppleClang). +#if __has_builtin(__cpp_lib_trivially_relocatable) + template + struct is_trivially_relocatable : std::integral_constant {}; +#else + template + struct is_trivially_relocatable : std::is_trivially_copyable {}; +#endif + + template requires(std::is_same_v) + struct is_trivially_relocatable : std::true_type {}; +} diff --git a/test/example_plugin/external/plugify/include/plg/macro.hpp b/test/cross_call_worker/external/plugify/include/plg/config.hpp similarity index 75% rename from test/example_plugin/external/plugify/include/plg/macro.hpp rename to test/cross_call_worker/external/plugify/include/plg/config.hpp index a072fec..05db47f 100644 --- a/test/example_plugin/external/plugify/include/plg/macro.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/config.hpp @@ -16,57 +16,47 @@ # define __has_builtin(x) 0 #endif -#include - -#define PLUGIFY_HAS_EXCEPTIONS (__cpp_exceptions || __EXCEPTIONS || _HAS_EXCEPTIONS) - -#ifndef PLUGIFY_EXCEPTIONS -# if PLUGIFY_HAS_EXCEPTIONS -# define PLUGIFY_EXCEPTIONS 1 -# else -# define PLUGIFY_EXCEPTIONS 0 -# endif -#endif - -#if PLUGIFY_EXCEPTIONS && (!PLUGIFY_HAS_EXCEPTIONS || !__has_include()) -# undef PLUGIFY_EXCEPTIONS -# define PLUGIFY_EXCEPTIONS 0 -#endif - -#ifndef PLUGIFY_FALLBACK_ASSERT -# define PLUGIFY_FALLBACK_ASSERT 1 +#ifndef __builtin_constant_p +# define __builtin_constant_p(x) std::is_constant_evaluated() #endif -#if PLUGIFY_FALLBACK_ASSERT && !__has_include() -# undef PLUGIFY_FALLBACK_ASSERT -# define PLUGIFY_FALLBACK_ASSERT 0 +#if __has_include() +# include #endif -#ifndef PLUGIFY_FALLBACK_ABORT -# define PLUGIFY_FALLBACK_ABORT 1 -#endif - -#if PLUGIFY_FALLBACK_ABORT && !__has_include() -# undef PLUGIFY_FALLBACK_ABORT -# define PLUGIFY_FALLBACK_ABORT 0 -#endif - -#ifndef PLUGIFY_FALLBACK_ABORT_FUNCTION -# define PLUGIFY_FALLBACK_ABORT_FUNCTION [] (auto) { } +#if __has_include() +# include +# define PLUGIFY_ASSERT(cond, mesg) assert((cond) && (mesg)) #endif -#if PLUGIFY_EXCEPTIONS +#define PLUGIFY_HAS_EXCEPTIONS __cpp_exceptions || _CPPUNWIND || __EXCEPTIONS +#if PLUGIFY_HAS_EXCEPTIONS # include # include -# define PLUGIFY_ASSERT(x, str, e) do { if (!(x)) [[unlikely]] plugify_throw(str); } while (0) -#elif PLUGIFY_FALLBACK_ASSERT -# include -# define PLUGIFY_ASSERT(x, str, ...) assert((x) && (str)) -#elif PLUGIFY_FALLBACK_ABORT +namespace plg { + template + [[noreturn]] constexpr void throw_exception(const char* msg, Args...args) { + if constexpr (std::is_constructible_v) { + throw E(msg); + } else { + throw E(std::forward(args)...); + } + } +} // namespace plg +# define PLUGIFY_THROW(str, exp, ...) ::plg::throw_exception(str, ##__VA_ARGS__); +#else # include -# define PLUGIFY_ASSERT(x, ...) do { if (!(x)) [[unlikely]] { std::abort(); } } while (0) +# include +# define PLUGIFY_THROW(str, ...) \ + std::fputs(str "\n", stderr); \ + std::abort(); +#endif + +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define PLUGIFY_INSTRUMENTED_WITH_ASAN 1 +# include #else -# define PLUGIFY_ASSERT(x, str, ...) do { if (!(x)) [[unlikely]] { PLUGIFY_FALLBACK_ABORT_FUNCTION (str); { while (true) { [] { } (); } } } } while (0) +# define PLUGIFY_INSTRUMENTED_WITH_ASAN 0 #endif # define PLUGIFY_COMPILER_MAKE_VERSION2(version, sp) ((version) * 100 + (sp)) @@ -258,12 +248,24 @@ #elif PLUGIFY_COMPILER_MSVC # pragma warning(error: 4714) # define PLUGIFY_FORCE_INLINE [[msvc::forceinline]] -# define PLUGIFY_NOINLINE __declspec(noinline) +# define PLUGIFY_NOINLINE [[msvc::noinline]] #else # define PLUGIFY_FORCE_INLINE inline # define PLUGIFY_NOINLINE #endif +#if __has_feature(nullability) +# define PLUGIFY_NO_NULL _Nonnull +#else +# define PLUGIFY_NO_NULL +#endif + +#if __has_cpp_attribute(__no_sanitize__) +# define PLUGIFY_NO_CFI __attribute__((__no_sanitize__("cfi"))) +#else +# define PLUGIFY_NO_CFI +#endif + #if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG # define PLUGIFY_RESTRICT __restrict__ #elif PLUGIFY_COMPILER_MSVC @@ -272,13 +274,68 @@ # define PLUGIFY_RESTRICT #endif -#if PLUGIFY_EXCEPTIONS -template -[[noreturn]] PLUGIFY_FORCE_INLINE constexpr void plugify_throw(const char* msg) { - if constexpr (std::is_constructible_v) { - throw E(msg); - } else { - throw E(); - } -} -#endif \ No newline at end of file +#ifndef PLUGIFY_PLATFORM_WINDOWS +# if defined(_WIN32) || defined(_WIN64) +# define PLUGIFY_PLATFORM_WINDOWS 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_APPLE +# if defined(__APPLE__) && defined(__MACH__) +# define PLUGIFY_PLATFORM_APPLE 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_LINUX +# if defined(__linux__) +# define PLUGIFY_PLATFORM_LINUX 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_ANDROID +# if defined(__ANDROID__) +# define PLUGIFY_PLATFORM_ANDROID 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_ORBIS +# if defined(__ORBIS__) +# define PLUGIFY_PLATFORM_ORBIS 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_PROSPERO +# if defined(__PROSPERO__) +# define PLUGIFY_PLATFORM_PROSPERO 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_SWITCH +# if defined(__NX__) +# define PLUGIFY_PLATFORM_SWITCH 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_BSD +# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +# define PLUGIFY_PLATFORM_BSD 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_UNIX +# if defined(__unix__) || defined(__unix) || defined(unix) || defined(__APPLE__) +# define PLUGIFY_PLATFORM_UNIX 1 +# endif +#endif + +#if !defined(PLUGIFY_PLATFORM_WINDOWS) && \ + !defined(PLUGIFY_PLATFORM_APPLE) && \ + !defined(PLUGIFY_PLATFORM_LINUX) && \ + !defined(PLUGIFY_PLATFORM_ANDROID) && \ + !defined(PLUGIFY_PLATFORM_ORBIS) && \ + !defined(PLUGIFY_PLATFORM_PROSPERO)&& \ + !defined(PLUGIFY_PLATFORM_SWITCH) && \ + !defined(PLUGIFY_PLATFORM_BSD) && \ + !defined(PLUGIFY_PLATFORM_UNIX) +# error "Unsupported platform! Please extend macro.hpp" +#endif diff --git a/test/cross_call_worker/external/plugify/include/plg/debugging.hpp b/test/cross_call_worker/external/plugify/include/plg/debugging.hpp index b52ec8c..0326fe7 100644 --- a/test/cross_call_worker/external/plugify/include/plg/debugging.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/debugging.hpp @@ -1,13 +1,19 @@ #pragma once -#include "plg/macro.hpp" - -#ifdef __cpp_lib_debugging +#include "plg/config.hpp" +#if __has_include() #include +#if defined(__cpp_lib_debugging) && __cpp_lib_debugging >= 202403L +#define PLUGIFY_HAS_STD_DEBUGGING 1 +#else +#define PLUGIFY_HAS_STD_DEBUGGING 0 +#endif +#else +#define PLUGIFY_HAS_STD_DEBUGGING 0 +#endif -#else //def __cpp_lib_debugging - +#if !PLUGIFY_HAS_STD_DEBUGGING #if PLUGIFY_PLATFORM_WINDOWS #include #include @@ -25,16 +31,7 @@ #include #endif -#endif //def __cpp_lib_debugging - namespace plg { -#ifdef __cpp_lib_debugging - - using std::breakpoint; - using std::breakpoint_if_debugging; - using std::is_debugger_present; - -#else //def __cpp_lib_debugging #if PLUGIFY_PLATFORM_WINDOWS @@ -178,7 +175,7 @@ namespace plg { } // namespace debugging } // namespace detail - PLUGIFY_NOINLINE inline bool is_debugger_present() noexcept { + inline bool is_debugger_present() noexcept { return plg::detail::debugging::parse_proc_status(); } @@ -190,7 +187,7 @@ namespace plg { #endif - PLUGIFY_FORCE_INLINE void breakpoint() noexcept { + inline void breakpoint() noexcept { #if PLUGIFY_COMPILER_MSVC __debugbreak(); #elif PLUGIFY_COMPILER_CLANG @@ -202,11 +199,17 @@ namespace plg { #endif } - PLUGIFY_FORCE_INLINE void breakpoint_if_debugging() noexcept { + inline void breakpoint_if_debugging() noexcept { if (plg::is_debugger_present()) { plg::breakpoint(); } } - -#endif //def __cpp_lib_debugging } // namespace plg + +namespace std { + using plg::breakpoint; + using plg::breakpoint_if_debugging; + using plg::is_debugger_present; +} // namespace std + +#endif // !PLUGIFY_HAS_STD_DEBUGGING diff --git a/test/cross_call_worker/external/plugify/include/plg/enum.hpp b/test/cross_call_worker/external/plugify/include/plg/enum.hpp index f8780e1..802b7c1 100644 --- a/test/cross_call_worker/external/plugify/include/plg/enum.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/enum.hpp @@ -6,7 +6,7 @@ #include #include -#include "plg/macro.hpp" +#include "plg/config.hpp" // from // https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ @@ -17,15 +17,15 @@ namespace plg { template struct static_string { constexpr static_string(std::string_view sv) noexcept { - std::copy(sv.begin(), sv.end(), content.begin()); + std::copy(sv.begin(), sv.end(), _content.begin()); } constexpr operator std::string_view() const noexcept { - return { content.data(), N }; + return { _content.data(), N }; } private: - std::array content{}; + std::array _content{}; }; constexpr auto is_pretty(char ch) noexcept { diff --git a/test/cross_call_worker/external/plugify/include/plg/expected.hpp b/test/cross_call_worker/external/plugify/include/plg/expected.hpp index d6bc137..f35fea5 100644 --- a/test/cross_call_worker/external/plugify/include/plg/expected.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/expected.hpp @@ -1,14 +1,19 @@ #pragma once -#include "plg/macro.hpp" +#include "plg/config.hpp" -#ifdef __cpp_lib_expected +#if __has_include() #include -namespace plg { - using std::expected; - using std::unexpected; -} +#if defined(__cpp_lib_expected) && __cpp_lib_expected >= 202202L +#define PLUGIFY_HAS_STD_EXPECTED 1 +#else +#define PLUGIFY_HAS_STD_EXPECTED 0 +#endif #else +#define PLUGIFY_HAS_STD_EXPECTED 0 +#endif + +#if !PLUGIFY_HAS_STD_EXPECTED #include #include #include @@ -524,27 +529,39 @@ namespace plg { // precondition: has_value() = true constexpr auto operator->() const noexcept -> T const* { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::addressof(this->val); } // precondition: has_value() = true constexpr auto operator->() noexcept -> T* { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::addressof(this->val); } // precondition: has_value() = true - constexpr auto operator*() const& noexcept -> T const& { return this->val; } + constexpr auto operator*() const& noexcept -> T const& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return this->val; + } // precondition: has_value() = true - constexpr auto operator*() & noexcept -> T& { return this->val; } + constexpr auto operator*() & noexcept -> T& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return this->val; + } // precondition: has_value() = true constexpr auto operator*() const&& noexcept -> T const&& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::move(this->val); } // precondition: has_value() = true - constexpr auto operator*() && noexcept -> T&& { return std::move(this->val); } + constexpr auto operator*() && noexcept -> T&& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return std::move(this->val); + } constexpr explicit operator bool() const noexcept { return has_val; } @@ -553,44 +570,56 @@ namespace plg { } constexpr auto value() const& -> T const& { - if (has_value()) { - return this->val; + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } - throw bad_expected_access(error()); + return this->val; } constexpr auto value() & -> T& { - if (has_value()) { - return this->val; + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } - throw bad_expected_access(error()); + return this->val; } constexpr auto value() const&& -> T const&& { - if (has_value()) { - return std::move(this->val); + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } - throw bad_expected_access(std::move(error())); + return std::move(this->val); } constexpr auto value() && -> T&& { - if (has_value()) { - return std::move(this->val); + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } - throw bad_expected_access(std::move(error())); + return std::move(this->val); } // precondition: has_value() = false - constexpr auto error() const& -> E const& { return this->unex; } + constexpr auto error() const& -> E const& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() & -> E& { return this->unex; } + constexpr auto error() & -> E& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() const&& -> E const&& { return std::move(this->unex); } + constexpr auto error() const&& -> E const&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // precondition: has_value() = false - constexpr auto error() && -> E&& { return std::move(this->unex); } + constexpr auto error() && -> E&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } template requires std::is_copy_constructible_v && std::is_convertible_v @@ -1126,27 +1155,39 @@ namespace plg { constexpr void value() const& { if (!has_value()) { - throw bad_expected_access(error()); + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } } constexpr void value() && { if (!has_value()) { - throw bad_expected_access(std::move(error())); + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } } // precondition: has_value() = false - constexpr auto error() const& -> E const& { return this->unex; } + constexpr auto error() const& -> E const& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() & -> E& { return this->unex; } + constexpr auto error() & -> E& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() const&& -> E const&& { return std::move(this->unex); } + constexpr auto error() const&& -> E const&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // precondition: has_value() = false - constexpr auto error() && -> E&& { return std::move(this->unex); } + constexpr auto error() && -> E&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // monadic template>> @@ -1426,5 +1467,27 @@ namespace plg { }; }; -}// namespace plg -#endif \ No newline at end of file +} // namespace plg + +namespace std { + template + using expected = plg::expected; + + template + concept is_expected = std::same_as, expected >; + +#if PLUGIFY_COMPILER_CLANG + template + struct unexpected : public plg::unexpected { + using plg::unexpected::unexpected; + }; + template + unexpected(U) -> unexpected; +#else + template + using unexpected = plg::unexpected; +#endif + +} // namespace std + +#endif // !PLUGIFY_HAS_STD_EXPECTED \ No newline at end of file diff --git a/test/cross_call_worker/external/plugify/include/plg/flat_map.hpp b/test/cross_call_worker/external/plugify/include/plg/flat_map.hpp deleted file mode 100644 index 7b5f7b7..0000000 --- a/test/cross_call_worker/external/plugify/include/plg/flat_map.hpp +++ /dev/null @@ -1,780 +0,0 @@ -#pragma once - -#include "plg/macro.hpp" - -#ifdef __cpp_lib_flat_map -#include -namespace plg { - template> - using flat_map = std::flat_map; -} -#else -#include "plg/vector.hpp" - -namespace plg { - namespace detail { - template < typename T, typename U, typename = void > - struct is_transparent - : std::false_type {}; - - template < typename T, typename U > - struct is_transparent> - : std::true_type {}; - - template < typename T, typename U > - inline constexpr bool is_transparent_v = is_transparent::value; - - template - constexpr bool is_sorted(Iter first, Iter last, Compare comp) { - if (first != last) { - Iter next = first; - while (++next != last) { - if (comp(*next, *first)) { - return false; - } - ++first; - } - } - return true; - } - - template - constexpr bool is_sorted_unique(Iter first, Iter last, Compare comp) { - if (first != last) { - Iter next = first; - while (++next != last) { - if (!comp(*first, *next)) { - return false; - } - ++first; - } - } - return true; - } - - template - struct pair_compare : public Compare { - pair_compare() = default; - - explicit pair_compare(const Compare& compare) - : Compare(compare) {} - - bool operator()( - const typename Pair::first_type& l, - const typename Pair::first_type& r) const { - return Compare::operator()(l, r); - } - - bool operator()(const Pair& l, const Pair& r) const { - return Compare::operator()(l.first, r.first); - } - - bool operator()( - const typename Pair::first_type& l, - const Pair& r) const { - return Compare::operator()(l, r.first); - } - - bool operator()( - const Pair& l, - const typename Pair::first_type& r) const { - return Compare::operator()(l.first, r); - } - - template - requires (is_transparent_v) - bool operator()(const K& l, const Pair& r) const { - return Compare::operator()(l, r.first); - } - - template - requires (is_transparent_v) - bool operator()(const Pair& l, const K& r) const { - return Compare::operator()(l.first, r); - } - }; - - template - struct eq_compare : public Compare { - eq_compare() = default; - - explicit eq_compare(const Compare& compare) - : Compare(compare) {} - - template - bool operator()(const L& l, const R& r) const { - return !Compare::operator()(l, r) && !Compare::operator()(r, l); - } - }; - } // namespace detail - - struct sorted_range_t {}; - inline constexpr sorted_range_t sorted_range = sorted_range_t(); - - struct sorted_unique_range_t : public sorted_range_t {}; - inline constexpr sorted_unique_range_t sorted_unique_range = sorted_unique_range_t(); - - template, typename Container = std::vector>> - class flat_map { - public: - using key_type = Key; - using mapped_type = Value; - using value_type = typename Container::value_type; - - using size_type = typename Container::size_type; - using difference_type = typename Container::difference_type; - - using key_compare = Compare; - using container_type = Container; - - using reference = typename Container::reference; - using const_reference = typename Container::const_reference; - using pointer = typename Container::pointer; - using const_pointer = typename Container::const_pointer; - - using iterator = typename Container::iterator; - using const_iterator = typename Container::const_iterator; - using reverse_iterator = typename Container::reverse_iterator; - using const_reverse_iterator = typename Container::const_reverse_iterator; - - struct value_compare : private key_compare { - value_compare() = default; - - explicit value_compare(key_compare compare) - : key_compare(std::move(compare)) {} - - bool operator()(const value_type& l, const value_type& r) const { - return key_compare::operator()(l.first, r.first); - } - }; - - public: - flat_map() = default; - ~flat_map() = default; - - explicit flat_map(const Compare& c) - : _compare(c) {} - - template - explicit flat_map(const Allocator& a) - : _data(a) {} - - template - flat_map(const Compare& c, const Allocator& a) - : _compare(c), _data(a) {} - - template - flat_map(Iterator first, Iterator last) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_unique_range, first, last); - } - - flat_map(std::initializer_list list) { - from_range(list.begin(), list.end()); - } - - flat_map(sorted_range_t, std::initializer_list list) { - from_range(sorted_range, list.begin(), list.end()); - } - - flat_map(sorted_unique_range_t, std::initializer_list list) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - flat_map(std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(list.begin(), list.end()); - } - - flat_map(sorted_range_t, std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(sorted_range, list.begin(), list.end()); - } - - flat_map(sorted_unique_range_t, std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(list.begin(), list.end()); - } - - template - flat_map(sorted_range_t, std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(sorted_range, list.begin(), list.end()); - } - - template - flat_map(sorted_unique_range_t, std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(list.begin(), list.end()); - } - - template - flat_map(sorted_range_t, std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_range, list.begin(), list.end()); - } - - template - flat_map(sorted_unique_range_t, std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(flat_map&& other, const Allocator& a) - : _compare(std::move(other._compare)), _data(std::move(other._data), a) {} - - template - flat_map(const flat_map& other, const Allocator& a) - : _compare(other._compare), _data(other._data, a) {} - - flat_map(flat_map&& other) noexcept = default; - flat_map(const flat_map& other) = default; - - flat_map& operator=(flat_map&& other) noexcept = default; - flat_map& operator=(const flat_map& other) = default; - - flat_map& operator=(std::initializer_list list) { - flat_map(list).swap(*this); - return *this; - } - - iterator begin() noexcept(noexcept(std::declval().begin())) { - return _data.begin(); - } - - const_iterator begin() const - noexcept(noexcept(std::declval().begin())) { - return _data.begin(); - } - - const_iterator cbegin() const - noexcept(noexcept(std::declval().cbegin())) { - return _data.cbegin(); - } - - iterator end() noexcept(noexcept(std::declval().end())) { - return _data.end(); - } - - const_iterator end() const - noexcept(noexcept(std::declval().end())) { - return _data.end(); - } - - const_iterator cend() const - noexcept(noexcept(std::declval().cend())) { - return _data.cend(); - } - - reverse_iterator rbegin() noexcept(noexcept(std::declval().rbegin())) { - return _data.rbegin(); - } - - const_reverse_iterator rbegin() const - noexcept(noexcept(std::declval().rbegin())) { - return _data.rbegin(); - } - - const_reverse_iterator crbegin() const - noexcept(noexcept(std::declval().crbegin())) { - return _data.crbegin(); - } - - reverse_iterator rend() noexcept(noexcept(std::declval().rend())) { - return _data.rend(); - } - - const_reverse_iterator rend() const - noexcept(noexcept(std::declval().rend())) { - return _data.rend(); - } - - const_reverse_iterator crend() const - noexcept(noexcept(std::declval().crend())) { - return _data.crend(); - } - - bool empty() const - noexcept(noexcept(std::declval().empty())) { - return _data.empty(); - } - - size_type size() const - noexcept(noexcept(std::declval().size())) { - return _data.size(); - } - - size_type max_size() const - noexcept(noexcept(std::declval().max_size())) { - return _data.max_size(); - } - - size_type capacity() const - noexcept(noexcept(std::declval().capacity())) { - return _data.capacity(); - } - - void reserve(size_type capacity) { - _data.reserve(capacity); - } - - void shrink_to_fit() { - _data.shrink_to_fit(); - } - - mapped_type& operator[](key_type&& key) { - const iterator iter = find(key); - return iter != end() - ? iter->second - : emplace(std::move(key), mapped_type()).first->second; - } - - mapped_type& operator[](const key_type& key) { - const iterator iter = find(key); - return iter != end() - ? iter->second - : emplace(key, mapped_type()).first->second; - } - - mapped_type& at(const key_type& key) { - const iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - const mapped_type& at(const key_type& key) const { - const const_iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - template - requires (detail::is_transparent_v) - mapped_type& at(const K& key) { - const iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - template - requires (detail::is_transparent_v) - const mapped_type& at(const K& key) const { - const const_iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - std::pair insert(value_type&& value) { - const iterator iter = lower_bound(value.first); - return iter == end() || _compare(value, *iter) - ? std::make_pair(_data.insert(iter, std::move(value)), true) - : std::make_pair(iter, false); - } - - std::pair insert(const value_type& value) { - const iterator iter = lower_bound(value.first); - return iter == end() || _compare(value, *iter) - ? std::make_pair(_data.insert(iter, value), true) - : std::make_pair(iter, false); - } - - iterator insert(const_iterator hint, value_type&& value) { - return (hint == begin() || _compare(*(hint - 1), value)) && (hint == end() || _compare(value, *hint)) - ? _data.insert(hint, std::move(value)) - : insert(std::move(value)).first; - } - - iterator insert(const_iterator hint, const value_type& value) { - return (hint == begin() || _compare(*(hint - 1), value)) && (hint == end() || _compare(value, *hint)) - ? _data.insert(hint, value) - : insert(value).first; - } - - template - std::pair insert_or_assign(key_type&& key, V&& value) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, std::move(key), std::forward(value)); - return {iter, true}; - } - (*iter).second = std::forward(value); - return {iter, false}; - } - - template - std::pair insert_or_assign(const key_type& key, V&& value) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, key, std::forward(value)); - return {iter, true}; - } - (*iter).second = std::forward(value); - return {iter, false}; - } - - template - void insert(Iterator first, Iterator last) { - insert_range(first, last); - } - - template - void insert(sorted_range_t, Iterator first, Iterator last) { - insert_range(sorted_range, first, last); - } - - void insert(std::initializer_list list) { - insert_range(list.begin(), list.end()); - } - - void insert(sorted_range_t, std::initializer_list list) { - insert_range(sorted_range, list.begin(), list.end()); - } - - template - std::pair emplace(Args&&... args) { - return insert(value_type(std::forward(args)...)); - } - - template - iterator emplace_hint(const_iterator hint, Args&&... args) { - return insert(hint, value_type(std::forward(args)...)); - } - - template - std::pair try_emplace(key_type&& key, Args&&... args) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, std::move(key), std::forward(args)...); - return {iter, true}; - } - return {iter, false}; - } - - template - std::pair try_emplace(const key_type& key, Args&&... args) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, key, std::forward(args)...); - return {iter, true}; - } - return {iter, false}; - } - - void clear() noexcept(noexcept(std::declval().clear())) { - _data.clear(); - } - - iterator erase(const_iterator iter) { - return _data.erase(iter); - } - - iterator erase(const_iterator first, const_iterator last) { - return _data.erase(first, last); - } - - size_type erase(const key_type& key) { - const const_iterator iter = find(key); - return iter != end() - ? (erase(iter), 1) - : 0; - } - - void swap(flat_map& other) noexcept(std::is_nothrow_swappable_v && std::is_nothrow_swappable_v) { - using std::swap; - swap(_compare, other._compare); - swap(_data, other._data); - } - - size_type count(const key_type& key) const { - const const_iterator iter = find(key); - return iter != end() ? 1 : 0; - } - - template - requires (detail::is_transparent_v) - size_type count(const K& key) const { - const const_iterator iter = find(key); - return iter != end() ? 1 : 0; - } - - iterator find(const key_type& key) { - const iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - const_iterator find(const key_type& key) const { - const const_iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - template - requires (detail::is_transparent_v) - iterator find(const K& key) { - const iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - template - requires (detail::is_transparent_v) - const_iterator find(const K& key) const { - const const_iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - bool contains(const key_type& key) const { - return find(key) != end(); - } - - template - requires (detail::is_transparent_v) - bool contains(const K& key) const { - return find(key) != end(); - } - - std::pair equal_range(const key_type& key) { - return std::equal_range(begin(), end(), key, _compare); - } - - std::pair equal_range(const key_type& key) const { - return std::equal_range(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - std::pair equal_range(const K& key) { - return std::equal_range(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - std::pair equal_range(const K& key) const { - return std::equal_range(begin(), end(), key, _compare); - } - - iterator lower_bound(const key_type& key) { - return std::lower_bound(begin(), end(), key, _compare); - } - - const_iterator lower_bound(const key_type& key) const { - return std::lower_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - iterator lower_bound(const K& key) { - return std::lower_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - const_iterator lower_bound(const K& key) const { - return std::lower_bound(begin(), end(), key, _compare); - } - - iterator upper_bound(const key_type& key) { - return std::upper_bound(begin(), end(), key, _compare); - } - - const_iterator upper_bound(const key_type& key) const { - return std::upper_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - iterator upper_bound(const K& key) { - return std::upper_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - const_iterator upper_bound(const K& key) const { - return std::upper_bound(begin(), end(), key, _compare); - } - - key_compare key_comp() const { - return _compare; - } - - value_compare value_comp() const { - return value_compare(key_comp()); - } - - private: - template - void from_range(Iter first, Iter last) { - assert(_data.empty()); - _data.insert(_data.end(), first, last); - std::sort(_data.begin(), _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void from_range(sorted_range_t, Iter first, Iter last) { - assert(_data.empty()); - assert(detail::is_sorted(first, last, value_comp())); - _data.insert(_data.end(), first, last); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void from_range(sorted_unique_range_t, Iter first, Iter last) { - assert(_data.empty()); - assert(detail::is_sorted_unique(first, last, value_comp())); - _data.insert(_data.end(), first, last); - } - - private: - template - void insert_range(Iter first, Iter last) { - const auto mid_iter = _data.insert(_data.end(), first, last); - std::sort(mid_iter, _data.end(), value_comp()); - std::inplace_merge(_data.begin(), mid_iter, _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void insert_range(sorted_range_t, Iter first, Iter last) { - assert(detail::is_sorted(first, last, value_comp())); - const auto mid_iter = _data.insert(_data.end(), first, last); - std::inplace_merge(_data.begin(), mid_iter, _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - private: - PLUGIFY_NO_UNIQUE_ADDRESS - detail::pair_compare _compare; - container_type _data; - }; - - template - void swap( - flat_map& l, - flat_map& r) noexcept(noexcept(l.swap(r))) { - l.swap(r); - } - - template - bool operator==( - const flat_map& l, - const flat_map& r) { - return l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin()); - } - - template - auto operator<=>( - const flat_map& l, - const flat_map& r) { - if (l.size() < r.size()) { - return std::partial_ordering::less; - } else if (l.size() > r.size()) { - return std::partial_ordering::greater; - } else { - if (std::lexicographical_compare(l.cbegin(), l.cend(), r.cbegin(), r.cend())) { - return std::partial_ordering::less; - } else { - return std::partial_ordering::greater; - } - } - } - - template, typename Container = plg::vector>> - using map = flat_map; - -}// namespace plg -#endif \ No newline at end of file diff --git a/test/cross_call_worker/external/plugify/include/plg/format.hpp b/test/cross_call_worker/external/plugify/include/plg/format.hpp index 94e5bdb..9abb9fe 100644 --- a/test/cross_call_worker/external/plugify/include/plg/format.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/format.hpp @@ -1,12 +1,19 @@ #pragma once -#include "plg/macro.hpp" - -#ifdef __cpp_lib_format +#include "plg/config.hpp" +#if __has_include() #include +#if defined(__cpp_lib_format) && __cpp_lib_format >= 201907L +#define PLUGIFY_HAS_STD_FORMAT 1 +#else +#define PLUGIFY_HAS_STD_FORMAT 0 +#endif +#else +#define PLUGIFY_HAS_STD_FORMAT 0 +#endif -#else // __cpp_lib_format +#if !PLUGIFY_HAS_STD_FORMAT // Define FMT_FORMAT_H externally to force a difference location for {fmt} #ifndef FMT_FORMAT_H @@ -21,6 +28,6 @@ namespace std { using namespace fmt; using namespace fmt::detail; -} +} // namespace std -#endif // __cpp_lib_format +#endif // !PLUGIFY_HAS_STD_FORMAT diff --git a/test/cross_call_worker/external/plugify/include/plg/guards.hpp b/test/cross_call_worker/external/plugify/include/plg/guards.hpp new file mode 100644 index 0000000..4691341 --- /dev/null +++ b/test/cross_call_worker/external/plugify/include/plg/guards.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include "plg/config.hpp" + +namespace plg { +#if PLUGIFY_HAS_EXCEPTIONS + template + struct exception_guard_exceptions { + exception_guard_exceptions() = delete; + + constexpr explicit exception_guard_exceptions(Rollback rollback) + : _rollback(std::move(rollback)) + , _completed(false) { + } + + constexpr exception_guard_exceptions( + exception_guard_exceptions&& other + ) noexcept(std::is_nothrow_move_constructible_v) + : _rollback(std::move(other._rollback)) + , _completed(other._completed) { + other._completed = true; + } + + exception_guard_exceptions(const exception_guard_exceptions&) = delete; + exception_guard_exceptions& operator=(const exception_guard_exceptions&) = delete; + exception_guard_exceptions& operator=(exception_guard_exceptions&&) = delete; + + constexpr void complete() noexcept { + _completed = true; + } + + constexpr ~exception_guard_exceptions() { + if (!_completed) { + _rollback(); + } + } + + private: + PLUGIFY_NO_UNIQUE_ADDRESS Rollback _rollback; + bool _completed; + }; + + template + using exception_guard = exception_guard_exceptions; +#else + template + struct exception_guard_noexceptions { + exception_guard_noexceptions() = delete; + + constexpr explicit exception_guard_noexceptions(Rollback) { + } + + constexpr exception_guard_noexceptions( + exception_guard_noexceptions&& other + ) noexcept(std::is_nothrow_move_constructible_v) + : _completed(other._completed) { + other._completed = true; + } + + exception_guard_noexceptions(const exception_guard_noexceptions&) = delete; + exception_guard_noexceptions& operator=(const exception_guard_noexceptions&) = delete; + exception_guard_noexceptions& operator=(exception_guard_noexceptions&&) = delete; + + constexpr void complete() noexcept { + _completed = true; + } + + constexpr ~exception_guard_noexceptions() { + PLUGIFY_ASSERT(_completed, "exception_guard not completed with exceptions disabled"); + } + + private: + bool _completed = false; + }; + + template + using exception_guard = exception_guard_noexceptions; +#endif + + template + constexpr exception_guard make_exception_guard(Rollback rollback) { + return exception_guard(std::move(rollback)); + } + + template + class scope_guard { + PLUGIFY_NO_UNIQUE_ADDRESS Func _func; + + public: + constexpr explicit scope_guard(Func func) + : _func(std::move(func)) { + } + + constexpr ~scope_guard() { + _func(); + } + + scope_guard(const scope_guard&) = delete; + scope_guard& operator=(const scope_guard&) = delete; + scope_guard& operator=(scope_guard&&) = delete; + scope_guard(scope_guard&&) = delete; + }; + + template + constexpr scope_guard make_scope_guard(Func func) { + return scope_guard(std::move(func)); + } +} diff --git a/test/cross_call_worker/external/plugify/include/plg/hash.hpp b/test/cross_call_worker/external/plugify/include/plg/hash.hpp index 296436a..4028e57 100644 --- a/test/cross_call_worker/external/plugify/include/plg/hash.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/hash.hpp @@ -34,16 +34,36 @@ namespace plg { } }; + // --- Hash traits depending on pointer size --- + template + struct hash_traits; + + template <> + struct hash_traits<4> { // 32-bit + static constexpr std::size_t fnv_basis = 0x811C9DC5u; + static constexpr std::size_t fnv_prime = 0x01000193u; + static constexpr std::size_t golden_ratio = 0x9e3779b9u; + }; + + template <> + struct hash_traits<8> { // 64-bit + static constexpr std::size_t fnv_basis = 0xcbf29ce484222325ULL; + static constexpr std::size_t fnv_prime = 0x100000001b3ULL; + static constexpr std::size_t golden_ratio = 0x9e3779b97f4a7c15ULL; + }; + + using active_hash_traits = hash_traits; + struct case_insensitive_hash { using is_transparent = void; // Enables heterogeneous lookup template auto operator()(const T& str_like) const noexcept { std::string_view str = str_like; - std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis - for (char c : str) { + std::size_t hash = active_hash_traits::fnv_basis; // FNV-1a + for (const char& c : str) { hash ^= static_cast(std::tolower(static_cast(c))); - hash *= 0x100000001b3; + hash *= active_hash_traits::fnv_prime; } return hash; } @@ -77,8 +97,7 @@ namespace plg { template inline void hash_combine(std::size_t& seed, const T& v) { std::hash hasher; - // 0x9e3779b97f4a7c15 is 64-bit golden ratio constant - seed ^= hasher(v) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2); + seed ^= hasher(v) + active_hash_traits::golden_ratio + (seed << 6) + (seed >> 2); } template @@ -94,5 +113,4 @@ namespace plg { return hash_combine_all(p.first, p.second); } }; - } diff --git a/test/cross_call_worker/external/plugify/include/plg/inplace_vector.hpp b/test/cross_call_worker/external/plugify/include/plg/inplace_vector.hpp new file mode 100644 index 0000000..71292c8 --- /dev/null +++ b/test/cross_call_worker/external/plugify/include/plg/inplace_vector.hpp @@ -0,0 +1,772 @@ +#pragma once + +#include "plg/config.hpp" + +#if __has_include() +#include +#if defined(__cpp_lib_inplace_vector) && __cpp_lib_inplace_vector >= 202406L +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 1 +#else +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 0 +#endif +#else +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 0 +#endif + +#if !PLUGIFY_HAS_STD_INPLACE_VECTOR +#include +#include +#include +#include +#include +#include + +#if PLUGIFY_CPP_VERSION >= 202002L +#include +#include +#endif + +#ifndef PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF +#if defined(__cpp_impl_trivially_relocatable) && defined(__cpp_lib_trivially_relocatable) +#define PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(x) [[trivially_relocatable(x)]] +#else +#define PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(x) +#endif // __cpp_impl_trivially_relocatable +#endif // PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF + +// from https://github.com/Quuxplusone/SG14 +namespace plg { + namespace detail { + + template && std::is_copy_assignable_v), + bool = (std::is_move_constructible_v && std::is_move_assignable_v)> + struct ipvbase_assignable { + // Base for copyable types + }; + + template + struct ipvbase_assignable { + // Base for immobile types like std::mutex + explicit ipvbase_assignable() = default; + ipvbase_assignable(ipvbase_assignable&&) = delete; + ipvbase_assignable(const ipvbase_assignable&) = delete; + void operator=(ipvbase_assignable&&) = delete; + void operator=(const ipvbase_assignable&) = delete; + ~ipvbase_assignable() = default; + }; + + template + struct ipvbase_assignable { + explicit ipvbase_assignable() = default; + ipvbase_assignable(const ipvbase_assignable&) = delete; + ipvbase_assignable(ipvbase_assignable&&) = default; + void operator=(const ipvbase_assignable&) = delete; + ipvbase_assignable& operator=(ipvbase_assignable&&) = default; + ~ipvbase_assignable() = default; + }; + + template + struct PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(std::is_trivially_relocatable_v) ipvbase + { + size_t _size = 0; + union { + [[maybe_unused]] char _dummy; + T _data[N]; + }; + + constexpr T *base_data() { return _data; } + constexpr const T *base_data() const { return _data; } + constexpr void set_size(size_t n) { _size = n; } + + constexpr explicit ipvbase() noexcept {} + ipvbase(const ipvbase& rhs) + noexcept(std::is_nothrow_copy_constructible_v) + { + if constexpr (std::is_trivially_copy_constructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else { + std::uninitialized_copy_n(rhs._data, rhs._size, _data); + _size = rhs._size; + } + } + ipvbase(ipvbase&& rhs) + noexcept(std::is_nothrow_move_constructible_v +#if defined(__cpp_lib_trivially_relocatable) + || std::is_trivially_relocatable_v +#endif // __cpp_lib_trivially_relocatable + ) + { + if constexpr (std::is_trivially_move_constructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); +#if defined(__cpp_lib_trivially_relocatable) + } else if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_n(rhs._data, rhs._size, _data); + _size = rhs._size; + rhs._size = 0; +#endif // __cpp_lib_trivially_relocatable + } else { + std::uninitialized_move_n(rhs._data, rhs._size, _data); + _size = rhs._size; + } + } + void operator=(const ipvbase& rhs) + noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_copy_assignable_v) + { + if constexpr (std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v && std::is_trivially_destructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else if (this == std::addressof(rhs)) { + // do nothing + } else if (rhs._size <= _size) { + std::copy(rhs._data, rhs._data + rhs._size, _data); + std::destroy(_data + rhs._size, _data + _size); + _size = rhs._size; + } else { + std::copy(rhs._data, rhs._data + _size, _data); + std::uninitialized_copy(rhs._data + _size, rhs._data + rhs._size, _data + _size); + _size = rhs._size; + } + } + void operator=(ipvbase&& rhs) + noexcept(std::is_nothrow_move_constructible_v && std::is_nothrow_move_assignable_v) + { + if constexpr (std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v && std::is_trivially_destructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else if (this == std::addressof(rhs)) { + // do nothing + } else if (rhs._size <= _size) { + std::move(rhs._data, rhs._data + rhs._size, _data); + std::destroy(_data + rhs._size, _data + _size); + _size = rhs._size; + } else { + std::move(rhs._data, rhs._data + _size, _data); +#if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate(rhs._data + _size, rhs._data + rhs._size, _data + _size); + std::swap(rhs._size, _size); + return; + } +#endif // __cpp_lib_trivially_relocatable + std::uninitialized_move(rhs._data + _size, rhs._data + rhs._size, _data + _size); + _size = rhs._size; + } + } + +#if __cpp_concepts >= 202002L + ipvbase(const ipvbase&) requires std::is_trivially_copy_constructible_v = default; + ipvbase(ipvbase&&) requires std::is_trivially_move_constructible_v = default; + ipvbase& operator=(const ipvbase&) requires std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v && std::is_trivially_destructible_v = default; + ipvbase& operator=(ipvbase&&) requires std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v && std::is_trivially_destructible_v = default; + ~ipvbase() requires std::is_trivially_destructible_v = default; +#endif // __cpp_concepts >= 202002L + +#if PLUGIFY_CPP_VERSION >= 202002L + constexpr +#endif // PLUGIFY_CPP_VERSION >= 202002L + ~ipvbase() { + std::destroy(_data, _data + _size); + } + }; + + template + struct ipvbase_zero { + static constexpr size_t _size = 0; + constexpr T *base_data() { return nullptr; } + constexpr const T *base_data() const { return nullptr; } + constexpr void set_size(size_t) { } + }; + + template + struct ipvbase_trivial { + size_t _size = 0; + union { + [[maybe_unused]] char _dummy; + T _data[N]; + }; + constexpr explicit ipvbase_trivial() {} + constexpr T *base_data() { return _data; } + constexpr const T *base_data() const { return _data; } + constexpr void set_size(size_t n) { _size = n; } + }; + + template + using ipvbase_t = std::conditional_t< + N == 0, + ipvbase_zero, + std::conditional_t< + std::is_trivially_copyable_v, + ipvbase_trivial, + ipvbase + > + >; + } // namespace detail + + template + class inplace_vector : detail::ipvbase_assignable, detail::ipvbase_t { + using detail::ipvbase_t::_size; + using detail::ipvbase_t::set_size; + public: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = T*; + using const_iterator = const T*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // [inplace.vector.cons] + + inplace_vector() = default; + inplace_vector(inplace_vector&&) = default; + inplace_vector(const inplace_vector&) = default; + inplace_vector& operator=(inplace_vector&&) = default; + inplace_vector& operator=(const inplace_vector&) = default; + inplace_vector& operator=(std::initializer_list il) + requires std::is_copy_constructible_v + { + assign(il.begin(), il.end()); + return *this; + } + + constexpr inplace_vector(std::initializer_list il) + requires std::copy_constructible : inplace_vector(il.begin(), il.end()) { } + constexpr explicit inplace_vector(size_t n) + requires std::default_initializable + { + if (n > N) { + throw_bad_alloc(); + } + std::uninitialized_value_construct_n(data(), n); + set_size(n); + } + constexpr explicit inplace_vector(size_t n, const value_type& value) + requires std::copy_constructible + { + assign(n, value); + } + + template + requires std::constructible_from::value_type> + constexpr explicit inplace_vector(InputIterator first, InputIterator last) + { + if constexpr (std::random_access_iterator) { + size_t n = static_cast(std::distance(first, last)); + if (n > N) { + throw_bad_alloc(); + } + std::uninitialized_copy_n(first, n, data()); + set_size(n); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } + } + } + + constexpr void assign(std::initializer_list il) + requires std::is_copy_constructible_v + { + assign(il.begin(), il.end()); + } + + constexpr void assign(size_t n, const value_type& value) + requires std::is_copy_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::fill_n(data(), n, value); + std::destroy(data() + n, data() + _size); + } else { + std::fill_n(data(), _size, value); + std::uninitialized_fill_n(data() + _size, n - _size, value); + } + set_size(n); + } + + template + requires std::is_constructible_v::value_type> + constexpr void assign(InputIterator first, InputIterator last) { + const size_type n = static_cast(std::distance(first, last)); + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::copy(first, last, data()); + std::destroy(data() + n, data() + _size); + } else { + std::copy(first, first + _size, data()); + std::uninitialized_copy(first + _size, last, data() + _size); + } + set_size(n); + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + constexpr explicit inplace_vector(std::from_range_t, R&& rg) { + if constexpr (std::ranges::sized_range) { + size_t n = std::ranges::size(rg); + if (n > N) { + throw_bad_alloc(); + } + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, data(), std::unreachable_sentinel); + set_size(n); + } else { + for (auto&& e : rg) { + emplace_back(decltype(e)(e)); + } + } + } + + template + requires std::convertible_to, value_type> + constexpr void assign_range(R&& rg) { + auto first = std::ranges::begin(rg); + auto last = std::ranges::end(rg); + size_t n = std::ranges::size(rg); + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::ranges::copy(first, last, data()); + std::destroy(data() + n, data() + _size); + } else { + auto mid = std::ranges::next(first, _size, last); + std::ranges::copy(first, mid, data()); + std::ranges::uninitialized_copy(mid, last, data() + _size); + } + set_size(n); + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + // iterators + + constexpr iterator begin() noexcept { return data(); } + constexpr iterator end() noexcept { return data() + _size; } + constexpr const_iterator begin() const noexcept { return data(); } + constexpr const_iterator end() const noexcept { return data() + _size; } + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + constexpr const_iterator cbegin() const noexcept { return data(); } + constexpr const_iterator cend() const noexcept { return data() + _size; } + constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + constexpr void resize(size_type n) + requires std::is_default_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (n < _size) { + std::destroy(data() + n, data() + _size); + set_size(n); + } else { + std::uninitialized_value_construct(data() + _size, data() + n); + set_size(_size + n); + } + } + + constexpr void resize(size_type n, const value_type& value) + requires std::is_copy_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (n < _size) { + std::destroy(data() + n, data() + _size); + set_size(n); + } else { + std::uninitialized_fill(data() + _size, data() + n, value); + set_size(_size + n); + } + } + + static constexpr void reserve(size_type n) { + if (n > N) { + throw_bad_alloc(); + } + } + static constexpr void shrink_to_fit() noexcept {} + + // element access + + constexpr reference operator[](size_type pos) { + PLUGIFY_ASSERT(pos < size(), "index out of bounds"); + return data()[pos]; + } + constexpr reference front() { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[0]; + } + constexpr reference back() { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[_size - 1]; + } + + constexpr const_reference operator[](size_type pos) const { + PLUGIFY_ASSERT(pos < size(), "index out of bounds"); + return data()[pos]; + } + constexpr const_reference front() const { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[0]; + } + constexpr const_reference back() const { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[_size - 1]; + } + + constexpr reference at(size_type i) { + if (i >= _size) { + throw_out_of_range(); + } + return data()[i]; + } + constexpr const_reference at(size_type i) const { + if (i >= _size) { + throw_out_of_range(); + } + return data()[i]; + } + + // [inplace.vector.data] + + constexpr T* data() noexcept { return this->base_data(); } + constexpr const T* data() const noexcept { return this->base_data(); } + constexpr size_type size() const noexcept { return _size; } + static constexpr size_type max_size() noexcept { return N; } + static constexpr size_type capacity() noexcept { return N; } + [[nodiscard]] constexpr bool empty() const noexcept { return _size == 0; }; + + // [inplace.vector.modifiers] + + template + requires std::is_constructible_v + value_type& unchecked_emplace_back(Args&&... args) { + // Precondition: (_size < N) + value_type* p = data() + _size; + p = std::construct_at(p, std::forward(args)...); + set_size(_size + 1); + return *p; + } + value_type& unchecked_push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return unchecked_emplace_back(value); + } + value_type& unchecked_push_back(value_type&& value) + requires std::is_move_constructible_v + { + return unchecked_emplace_back(static_cast(value)); + } + + template + requires std::is_constructible_v + constexpr value_type* try_emplace_back(Args&&... args) { + if (_size == N) { + return nullptr; + } + return std::addressof(unchecked_emplace_back(static_cast(args)...)); + } + constexpr value_type* try_push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return try_emplace_back(value); + } + constexpr value_type* try_push_back(value_type&& value) + requires std::is_move_constructible_v + { + return try_emplace_back(static_cast(value)); + } + + template + requires std::is_constructible_v + value_type& emplace_back(Args&&... args) { + if (_size == N) { + throw_bad_alloc(); + } + return unchecked_emplace_back(static_cast(args)...); + } + value_type& push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return emplace_back(value); + } + value_type& push_back(value_type&& value) + requires std::is_move_constructible_v + { + return emplace_back(static_cast(value)); + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + constexpr void append_range(R&& rg) { + for (auto&& e : rg) { + emplace_back(static_cast(e)); + } + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + void pop_back() { + std::destroy_at(data() + _size - 1); + set_size(_size - 1); + } + + template + requires std::is_constructible_v + iterator emplace(const_iterator pos, Args&&... args) { + auto it = iterator(pos); + emplace_back(static_cast(args)...); + std::rotate(it, end() - 1, end()); + return it; + } + iterator insert(const_iterator pos, const value_type& value) + requires std::is_copy_constructible_v + { + return emplace(pos, value); + } + iterator insert(const_iterator pos, value_type&& value) + requires std::is_move_constructible_v + { + return emplace(pos, static_cast(value)); + } + + iterator insert(const_iterator pos, size_type n, const value_type& value) + requires std::is_copy_constructible_v + { + if (N - _size < n) { + throw_bad_alloc(); + } + auto it = iterator(pos); + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::uninitialized_fill_n(it, n, value); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::uninitialized_fill_n(oldend, n, value); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + return it; + } + + template + requires (std::is_constructible_v::value_type> && !std::is_const_v) + iterator insert(const_iterator pos, InputIterator first, InputIterator last) { + auto it = iterator(pos); + auto oldend = end(); + if constexpr (std::random_access_iterator) { + size_type n = static_cast(std::distance(first, last)); + if (N - _size < n) { + throw_bad_alloc(); + } + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::uninitialized_copy_n(first, n, it); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::uninitialized_copy_n(first, n, oldend); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } + std::rotate(it, oldend, end()); + } + return it; + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + iterator insert_range(const_iterator pos, R&& rg) { + auto it = iterator(pos); + auto oldend = end(); + if constexpr (std::ranges::sized_range) { + size_type n = std::ranges::size(rg); + if (N - _size < n) { + throw_bad_alloc(); + } + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, it, std::unreachable_sentinel); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, oldend, std::unreachable_sentinel); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + } else { + auto [rgend, newend] = std::ranges::uninitialized_copy(rg, std::ranges::subrange(oldend, data() + N)); + if (rgend != std::ranges::end(rg)) { + std::destroy(oldend, newend); + throw_bad_alloc(); + } else { + set_size(newend - data()); + std::rotate(it, oldend, newend); + } + } + return it; + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + iterator insert(const_iterator pos, std::initializer_list il) + requires (std::is_copy_constructible_v && !std::is_const_v) + { + return insert(pos, il.begin(), il.end()); + } + + iterator erase(const_iterator pos) + requires (!std::is_const_v) + { + auto it = iterator(pos); + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::destroy_at(it); + std::uninitialized_relocate(it + 1, oldend, it); + set_size(_size - 1); + return it; + } + #endif + std::move(it + 1, oldend, it); + std::destroy_at(oldend - 1); + set_size(_size - 1); + return it; + } + + iterator erase(const_iterator first, const_iterator last) + requires (!std::is_const_v) + { + auto ifirst = iterator(first); + auto ilast = iterator(last); + auto n = static_cast(std::distance(ifirst, ilast)); + if (n != 0) { + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::destroy(ifirst, ilast); + std::uninitialized_relocate(ilast, oldend, ifirst); + set_size(_size - n); + return ifirst; + } + #endif // __cpp_lib_trivially_relocatable + std::destroy(std::move(ilast, oldend, ifirst), oldend); + set_size(_size - n); + } + return ifirst; + } + + constexpr void clear() noexcept { + std::destroy(data(), data() + _size); + set_size(0); + } + + constexpr void swap(inplace_vector& b) + noexcept(N == 0 || (std::is_nothrow_swappable_v && std::is_nothrow_move_constructible_v)) + requires (!std::is_const_v) + { + auto& a = *this; + if (a._size < b._size) { + b.swap(a); + } else { + std::swap_ranges(a.data(), a.data() + b._size, b.data()); + #if defined(__cpp_lib_trivially_relocatable) + size_t n = a._size; + a.set_size(b._size); + std::uninitialized_relocate(a.data() + b._size, a.data() + n, b.data() + b._size); + b.set_size(n); + #else + std::uninitialized_move(a.data() + b._size, a.data() + a._size, b.data() + b._size); + std::destroy(a.data() + b._size, a.data() + a._size); + if constexpr (N != 0) { + std::swap(a._size, b._size); + } + #endif + } + } + + friend constexpr void swap(inplace_vector& a, inplace_vector& b) noexcept(noexcept(a.swap(b))) { + a.swap(b); + } + + constexpr friend bool operator==(const inplace_vector& lhs, const inplace_vector& rhs) { + if (lhs.size() != rhs.size()) return false; + return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + } + + #if __cpp_impl_three_way_comparison >= 201907L + constexpr friend auto operator<=>(const inplace_vector& lhs, const inplace_vector& rhs) { + return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + #else + constexpr friend bool operator<(const inplace_vector& a, const inplace_vector& b) { + const T* adata = a.data(); + const T* bdata = b.data(); + size_t n = (a._size < b._size) ? a._size : b._size; + for (size_t i = 0; i < n; ++i) { + if (adata[i] < bdata[i]) { + return true; + } else if (bdata[i] < adata[i]) { + return false; + } + } + return (a._size < b._size); + } + constexpr friend bool operator>(const inplace_vector& a, const inplace_vector& b) { return (b < a); } + constexpr friend bool operator<=(const inplace_vector& a, const inplace_vector& b) { return !(b < a); } + constexpr friend bool operator>=(const inplace_vector& a, const inplace_vector& b) { return !(a < b); } + constexpr friend bool operator!=(const inplace_vector& a, const inplace_vector& b) { return !(a == b); } + #endif + + private: + [[noreturn]] static void throw_bad_alloc() { + PLUGIFY_THROW("memory size would exceed capacity()", std::bad_alloc); + } + + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); + } + }; +} // namespace plg + +namespace std { + template + using inplace_vector = plg::inplace_vector; +} // namespace std + +#endif \ No newline at end of file diff --git a/test/cross_call_worker/external/plugify/include/plg/numerics.hpp b/test/cross_call_worker/external/plugify/include/plg/numerics.hpp index 9dd82f3..f975f3d 100644 --- a/test/cross_call_worker/external/plugify/include/plg/numerics.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/numerics.hpp @@ -1,7 +1,6 @@ #pragma once -#include "plg/string.hpp" -#include "plg/vector.hpp" +#include "plg/config.hpp" namespace plg { PLUGIFY_WARN_PUSH() diff --git a/test/cross_call_worker/external/plugify/include/plg/path.hpp b/test/cross_call_worker/external/plugify/include/plg/path.hpp index afc3d6e..7c44925 100644 --- a/test/cross_call_worker/external/plugify/include/plg/path.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/path.hpp @@ -4,13 +4,15 @@ #include #include +#include "plg/config.hpp" + namespace plg { using path_view = std::basic_string_view; using path_string = std::filesystem::path::string_type; using path_char = path_string::value_type; using path_diff_t = path_string::difference_type; -#if _WIN32 +#if PLUGIFY_PLATFORM_WINDOWS #define PLUGIFY_PATH_LITERAL(x) L##x #else #define PLUGIFY_PATH_LITERAL(x) x @@ -19,15 +21,14 @@ namespace plg { template bool insensitive_equals(const path_char lhs, const path_char rhs) { if constexpr (std::is_same_v) { - return std::towlower(lhs) == rhs; // NOLINT + return std::towlower(static_cast(lhs)) == std::towlower(static_cast(rhs)); } else { - return std::tolower(lhs) == rhs; + return std::tolower(static_cast(lhs)) == std::tolower(static_cast(rhs)); } } inline bool insensitive_equals(const path_view lhs, const path_view rhs) { - return lhs.size() == rhs.size() - && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); + return lhs.size() == rhs.size() && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); } inline path_view extension_view(const std::filesystem::path& path, size_t extension_size) { @@ -47,7 +48,7 @@ namespace plg { } inline auto as_string(const std::filesystem::path& p) { -#if _WIN32 +#if PLUGIFY_PLATFORM_WINDOWS return p.string(); // returns std::string by value #else return p.native(); // returns const std::string& diff --git a/test/cross_call_worker/external/plugify/include/plg/plugin.hpp b/test/cross_call_worker/external/plugify/include/plg/plugin.hpp index 76f2286..550b623 100644 --- a/test/cross_call_worker/external/plugify/include/plg/plugin.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/plugin.hpp @@ -181,15 +181,15 @@ namespace plg { namespace plg { namespace raw { struct vector { - [[maybe_unused]] uint8_t padding[sizeof(plg::vector)]{}; + uint8_t pad[sizeof(plg::vector)]{}; }; struct string { - [[maybe_unused]] uint8_t padding[sizeof(plg::string)]{}; + uint8_t pad[sizeof(plg::string)]{}; }; struct variant { - [[maybe_unused]] uint8_t padding[sizeof(plg::any)]{}; + uint8_t pad[sizeof(plg::any)]{}; }; } // namespace raw diff --git a/test/cross_call_worker/external/plugify/include/plg/split_buffer.hpp b/test/cross_call_worker/external/plugify/include/plg/split_buffer.hpp new file mode 100644 index 0000000..0568d15 --- /dev/null +++ b/test/cross_call_worker/external/plugify/include/plg/split_buffer.hpp @@ -0,0 +1,907 @@ +#pragma once + +#include "plg/config.hpp" +#include "plg/concepts.hpp" + +namespace plg { + template class Layout> + class split_buffer; + + template + class split_buffer_pointer_layout { + protected: + using value_type = T; + using allocator_type = Allocator; + using alloc_rr = std::remove_reference_t; + using alloc_traits = std::allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using constIterator = const_pointer; + using sentinel_type = pointer; + + public: + constexpr split_buffer_pointer_layout() + : _back_cap(nullptr) { + } + + constexpr explicit split_buffer_pointer_layout(const allocator_type& alloc) + : _back_cap(nullptr) + , _alloc(alloc) { + } + + constexpr pointer front_cap() noexcept { + return _front_cap; + } + + constexpr const_pointer front_cap() const noexcept { + return _front_cap; + } + + constexpr pointer begin() noexcept { + return _begin; + } + + constexpr const_pointer begin() const noexcept { + return _begin; + } + + constexpr pointer end() noexcept { + return _end; + } + + constexpr pointer end() const noexcept { + return _end; + } + + constexpr size_type size() const noexcept { + return static_cast(_end - _begin); + } + + constexpr bool empty() const noexcept { + return _begin == _end; + } + + constexpr size_type capacity() const noexcept { + return static_cast(_back_cap - _front_cap); + } + + constexpr allocator_type& get_allocator() noexcept { + return _alloc; + } + + constexpr const allocator_type& get_allocator() const noexcept { + return _alloc; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type + // deduction, not explicit types. + constexpr sentinel_type raw_sentinel() const noexcept { + return _end; + } + + constexpr sentinel_type raw_capacity() const noexcept { + return _back_cap; + } + + constexpr void set_data(pointer new_first) noexcept { + _front_cap = new_first; + } + + constexpr void + set_valid_range(pointer new_begin, pointer new_end) noexcept { + _begin = new_begin; + _end = new_end; + } + + constexpr void + set_valid_range(pointer new_begin, size_type new_size) noexcept { + _begin = new_begin; + _end = _begin + new_size; + } + + constexpr void set_sentinel(pointer new_end) noexcept { + PLUGIFY_ASSERT(_front_cap <= new_end, "new_end cannot precede _front_cap"); + _end = new_end; + } + + constexpr void set_sentinel(size_type new_size) noexcept { + _end = _begin + new_size; + } + + constexpr void set_capacity(size_type new_capacity) noexcept { + _back_cap = _front_cap + new_capacity; + } + + constexpr void set_capacity(pointer new_capacity) noexcept { + _back_cap = new_capacity; + } + + constexpr size_type front_spare() const noexcept { + return static_cast(_begin - _front_cap); + } + + constexpr size_type back_spare() const noexcept { + return static_cast(_back_cap - _end); + } + + constexpr reference back() noexcept { + return *(_end - 1); + } + + constexpr const_reference back() const noexcept { + return *(_end - 1); + } + + constexpr void swap_without_allocator( + split_buffer_pointer_layout< + split_buffer, + value_type, + alloc_rr&>& other + ) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_back_cap, other._back_cap); + std::swap(_end, other._end); + } + + constexpr void swap(split_buffer_pointer_layout& other) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_back_cap, other._back_cap); + std::swap(_end, other._end); + swap_allocator(_alloc, other._alloc); + } + + constexpr void reset() noexcept { + _front_cap = nullptr; + _begin = nullptr; + _end = nullptr; + _back_cap = nullptr; + } + + constexpr void copy_without_alloc( + const split_buffer_pointer_layout& other + ) noexcept(std::is_nothrow_copy_assignable::value) { + _front_cap = other._front_cap; + _begin = other._begin; + _end = other._end; + _back_cap = other._back_cap; + } + + private: + pointer _front_cap = nullptr; + pointer _begin = nullptr; + pointer _end = nullptr; + pointer _back_cap = nullptr; + PLUGIFY_NO_UNIQUE_ADDRESS allocator_type _alloc; + + template + friend class split_buffer_pointer_layout; + }; + + template + class split_buffer_size_layout { + protected: + using value_type = T; + using allocator_type = Allocator; + using alloc_rr = std::remove_reference_t; + using alloc_traits = std::allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using constIterator = const_pointer; + using sentinel_type = size_type; + + public: + constexpr split_buffer_size_layout() = default; + + constexpr explicit split_buffer_size_layout(const allocator_type& alloc) + : _alloc(alloc) { + } + + constexpr pointer front_cap() noexcept { + return _front_cap; + } + + constexpr const_pointer front_cap() const noexcept { + return _front_cap; + } + + constexpr pointer begin() noexcept { + return _begin; + } + + constexpr const_pointer begin() const noexcept { + return _begin; + } + + constexpr pointer end() noexcept { + return _begin + _size; + } + + constexpr pointer end() const noexcept { + return _begin + _size; + } + + constexpr size_type size() const noexcept { + return _size; + } + + constexpr bool empty() const noexcept { + return _size == 0; + } + + constexpr size_type capacity() const noexcept { + return _cap; + } + + constexpr allocator_type& get_allocator() noexcept { + return _alloc; + } + + constexpr const allocator_type& get_allocator() const noexcept { + return _alloc; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type + // deduction, not explicit types. + constexpr sentinel_type raw_sentinel() const noexcept { + return _size; + } + + constexpr sentinel_type raw_capacity() const noexcept { + return _cap; + } + + constexpr void set_data(pointer new_first) noexcept { + _front_cap = new_first; + } + + constexpr void + set_valid_range(pointer new_begin, pointer new_end) noexcept { + // Size-based split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + _size -= new_begin - _begin; + _begin = new_begin; + set_sentinel(new_end); + } + + constexpr void + set_valid_range(pointer new_begin, size_type new_size) noexcept { + // Size-based split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + _size -= new_begin - _begin; + _begin = new_begin; + set_sentinel(new_size); + } + + constexpr void set_sentinel(pointer new_end) noexcept { + _LIBCPP_ASSERT_INTERNAL(_front_cap <= new_end, "new_end cannot precede _front_cap"); + _size += new_end - end(); + } + + constexpr void set_sentinel(size_type new_size) noexcept { + _size = new_size; + } + + constexpr void set_capacity(size_type new_capacity) noexcept { + _cap = new_capacity; + } + + constexpr void set_capacity(pointer new_capacity) noexcept { + _cap = new_capacity - _begin; + } + + constexpr size_type front_spare() const noexcept { + return static_cast(_begin - _front_cap); + } + + constexpr size_type back_spare() const noexcept { + // `_cap - _end` tells us the total number of spares when in size-mode. We need to remove + // the front_spare from the count. + return _cap - _size - front_spare(); + } + + constexpr reference back() noexcept { + return _begin[_size - 1]; + } + + constexpr const_reference back() const noexcept { + return _begin[_size - 1]; + } + + constexpr void swap_without_allocator( + split_buffer_pointer_layout< + split_buffer, + value_type, + alloc_rr&>& other + ) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_cap, other._cap); + std::swap(_size, other._size); + } + + constexpr void swap(split_buffer_size_layout& other) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_cap, other._cap); + std::swap(_size, other._size); + swap_allocator(_alloc, other._alloc); + } + + constexpr void reset() noexcept { + _front_cap = nullptr; + _begin = nullptr; + _size = 0; + _cap = 0; + } + + constexpr void copy_without_alloc( + const split_buffer_size_layout& other + ) noexcept(std::is_nothrow_copy_assignable::value) { + _front_cap = other._front_cap; + _begin = other._begin; + _cap = other._cap; + _size = other._size; + } + + private: + pointer _front_cap = nullptr; + pointer _begin = nullptr; + size_type _size = 0; + size_type _cap = 0; + PLUGIFY_NO_UNIQUE_ADDRESS allocator_type _alloc; + + template + friend class split_buffer_size_layout; + }; + + // `split_buffer` is a contiguous array data structure. It may hold spare capacity at both ends of + // the sequence. This allows for a `split_buffer` to grow from both the front and the back without + // relocating its contents until it runs out of room. This characteristic sets it apart from + // `std::vector`, which only holds spare capacity at its end. As such, `split_buffer` is useful + // for implementing both `std::vector` and `std::deque`. + // + // The sequence is stored as a contiguous chunk of memory delimited by the following "pointers" (`o` + // denotes uninitialized memory and `x` denotes a valid object): + // + // |oooooooooooooooooooxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxoooooooooooooooooooooooo| + // ^ ^ ^ ^ + // _front_cap _begin _end _back_cap + // + // The range [_front_cap, _begin) contains uninitialized memory. It is referred to as the "front + // spare capacity". The range [_begin, _end) contains valid objects. It is referred to as the "valid + // range". The range [_end, _back_cap) contains uninitialized memory. It is referred to as the "back + // spare capacity". + // + // The layout of `split_buffer` is determined by the `Layout` template template parameter. This + // `Layout` allows the above pointers to be stored as different representations, such as integer + // offsets. A layout class template must provide the following interface: + // + // template + // class layout { + // protected: + // using value_type = T; + // using allocator_type = Allocator; + // using alloc_rr = std::remove_reference_t; + // using alloc_traits = allocator_traits; + // using reference = value_type&; + // using const_reference = const value_type&; + // using size_type = typename alloc_traits::size_type; + // using difference_type = typename alloc_traits::difference_type; + // using pointer = typename alloc_traits::pointer; + // using const_pointer = typename alloc_traits::const_pointer; + // using iterator = pointer; + // using constIterator = const_pointer; + // using sentinel_type = /* type that represents the layout's sentinel */; + // + // public: + // layout() = default; + // explicit layout(const allocator_type&); + // + // pointer front_cap(); + // const_pointer front_cap() const; + // + // pointer begin(); + // const_pointer begin() const; + // + // pointer end(); + // pointer end() const; + // + // size_type size() const; + // bool empty() const; + // size_type capacity() const; + // + // allocator_type& get_allocator(); + // allocator_type const& get_allocator() const; + // + // sentinel_type raw_sentinel() const; + // sentinel_type raw_capacity() const; + // + // void set_data(pointer); + // void set_valid_range(pointer begin, pointer end); + // void set_valid_range(pointer begin, size_type size); + // void set_sentinel(pointer end); + // void set_sentinel(size_type size); + // + // void set_capacity(size_type capacity); + // void set_capacity(pointer capacity); + // + // size_type front_spare() const; + // size_type back_spare() const; + // + // reference back(); + // const_reference back() const; + // + // template + // void swap_without_allocator(_OtherLayout&); + // void swap(layout&); + // + // void reset(); + // void copy_without_alloc(layout const&); + // }; + // + template class Layout> + class split_buffer : Layout, T, Allocator> { + using base_type = Layout, T, Allocator>; + + public: + using base_type::back_spare; + using base_type::copy_without_alloc; + using base_type::front_cap; + using base_type::front_spare; + using base_type::get_allocator; + using base_type::raw_capacity; + using base_type::raw_sentinel; + using base_type::reset; + using base_type::set_capacity; + using base_type::set_data; + using base_type::set_sentinel; + using base_type::set_valid_range; + + using typename base_type::alloc_rr; + using typename base_type::alloc_traits; + using typename base_type::allocator_type; + using typename base_type::constIterator; + using typename base_type::const_pointer; + using typename base_type::const_reference; + using typename base_type::difference_type; + using typename base_type::iterator; + using typename base_type::pointer; + using typename base_type::reference; + using typename base_type::size_type; + using typename base_type::value_type; + + // A split_buffer contains the following members which may be trivially relocatable: + // - pointer: may be trivially relocatable, so it's checked + // - allocator_type: may be trivially relocatable, so it's checked + // split_buffer doesn't have any self-references, so it's trivially relocatable if its members + // are. + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value, + split_buffer, + void>; + + split_buffer(const split_buffer&) = delete; + split_buffer& operator=(const split_buffer&) = delete; + + split_buffer() = default; + + constexpr explicit split_buffer(alloc_rr& a) + : base_type(a) { + } + + constexpr explicit split_buffer(const alloc_rr& a) + : base_type(a) { + } + + constexpr split_buffer(size_type cap, size_type start, alloc_rr& a); + + constexpr + split_buffer(split_buffer&& c) noexcept(std::is_nothrow_move_constructible_v); + + constexpr split_buffer(split_buffer&& c, const alloc_rr& a); + + + constexpr split_buffer& operator=(split_buffer&& c) noexcept( + (alloc_traits::propagate_on_container_move_assignment::value + && std::is_nothrow_move_assignable_v) + || !alloc_traits::propagate_on_container_move_assignment::value + ); + + constexpr ~split_buffer(); + + using base_type::back; + using base_type::begin; + using base_type::capacity; + using base_type::empty; + using base_type::end; + using base_type::size; + + constexpr void clear() noexcept { + destruct_at_end(begin()); + } + + constexpr reference front() { + return *begin(); + } + + constexpr const_reference front() const { + return *begin(); + } + + constexpr void shrink_to_fit() noexcept; + + template + constexpr void emplace_front(Args&&... args); + template + constexpr void emplace_back(Args&&... args); + + constexpr void pop_front() { + destruct_at_begin(begin() + 1); + } + + constexpr void pop_back() { + destruct_at_end(end() - 1); + } + + constexpr void construct_at_end(size_type n); + constexpr void construct_at_end(size_type n, const_reference x); + + template + constexpr void + construct_at_end(ForwardIterator first, ForwardIterator last); + + template + constexpr void + construct_at_end_with_sentinel(Iterator first, Sentinel last); + + template + constexpr void construct_at_end_with_size(Iterator first, size_type n); + + constexpr void destruct_at_begin(pointer new_begin) { + destruct_at_begin(new_begin, std::is_trivially_destructible()); + } + + constexpr void destruct_at_begin(pointer new_begin, std::false_type); + constexpr void destruct_at_begin(pointer new_begin, std::true_type); + + constexpr void destruct_at_end(pointer new_last) noexcept { + destruct_at_end(new_last, std::false_type()); + } + + constexpr void destruct_at_end(pointer new_last, std::false_type) noexcept; + constexpr void destruct_at_end(pointer new_last, std::true_type) noexcept; + + constexpr void swap( + split_buffer& x + ) noexcept(!alloc_traits::propagate_on_container_swap::value || std::is_nothrow_swappable_v); + + constexpr bool invariants() const { + if (front_cap() == nullptr) { + if (begin() != nullptr) { + return false; + } + + if (!empty()) { + return false; + } + + if (capacity() != 0) { + return false; + } + + return true; + } else { + if (begin() < front_cap()) { + return false; + } + + if (capacity() < size()) { + return false; + } + + if (end() < begin()) { + return false; + } + + return true; + } + } + + constexpr void + swap_without_allocator(split_buffer& other) noexcept { + base_type::swap_without_allocator(other); + } + + private: + constexpr void move_assign_alloc(split_buffer& c, std::true_type) noexcept( + std::is_nothrow_move_assignable_v + ) { + get_allocator() = std::move(c.get_allocator()); + } + + constexpr void move_assign_alloc(split_buffer&, std::false_type) noexcept { + } + + struct ConstructTransaction { + constexpr explicit ConstructTransaction( + split_buffer* parent, + pointer p, + size_type n + ) noexcept + : _pos(p) + , _end(p + n) + , _parent(parent) { + } + + constexpr ~ConstructTransaction() { + _parent->set_sentinel(_pos); + } + + pointer _pos; + const pointer _end; + + private: + split_buffer* _parent; + }; + + template class L2> + friend class split_buffer; + }; + + // Default constructs n objects starting at `end()` + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == size() + n + template class Layout> + constexpr void split_buffer::construct_at_end(size_type n) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos)); + } + } + + // Copy constructs n objects starting at `end()` from x + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == old size() + n + // Postcondition: [i] == x for all i in [size() - n, n) + template class Layout> + constexpr void + split_buffer::construct_at_end(size_type n, const_reference x) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos), x); + } + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end_with_sentinel(Iterator first, Sentinel last) { + alloc_rr& a = get_allocator(); + for (; first != last; ++first) { + if (back_spare() == 0) { + size_type old_cap = capacity(); + size_type new_cap = std::max(2 * old_cap, 8); + split_buffer buf(new_cap, 0, a); + pointer buf_end = buf.end(); + pointer cur_end = end(); + for (pointer p = begin(); p != cur_end; ++p) { + alloc_traits::construct(buf.get_allocator(), std::to_address(buf_end), std::move(*p)); + buf.set_sentinel(++buf_end); + } + swap(buf); + } + + alloc_traits::construct(a, std::to_address(end()), *first); + set_sentinel(size() + 1); + } + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end(ForwardIterator first, ForwardIterator last) { + construct_at_end_with_size(first, std::distance(first, last)); + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end_with_size(ForwardIterator first, size_type n) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos, (void) ++first) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos), *first); + } + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_begin(pointer new_begin, std::false_type) { + pointer pos = begin(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (pos != new_begin) { + alloc_traits::destroy(get_allocator(), std::to_address(pos++)); + } + set_valid_range(pos, end()); + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_begin(pointer new_begin, std::true_type) { + set_valid_range(new_begin, end()); + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_end(pointer new_last, std::false_type) noexcept { + pointer cur_end = end(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (new_last != cur_end) { + alloc_traits::destroy(get_allocator(), std::to_address(--cur_end)); + } + set_sentinel(cur_end); + } + + template class Layout> + constexpr split_buffer::split_buffer(size_type cap, size_type start, alloc_rr& a) + : base_type(a) { + PLUGIFY_ASSERT(cap >= start, "can't have a start point outside the capacity"); + if (cap > 0) { + auto allocation = allocate_at_least(get_allocator(), cap); + set_data(allocation.ptr); + cap = allocation.count; + } + + pointer pos = front_cap() + start; + set_valid_range(pos, pos); + set_capacity(cap); + } + + template class Layout> + constexpr split_buffer::~split_buffer() { + clear(); + if (front_cap()) { + alloc_traits::deallocate(get_allocator(), front_cap(), capacity()); + } + } + + template class Layout> + constexpr split_buffer::split_buffer(split_buffer&& c) noexcept( + std::is_nothrow_move_constructible_v + ) + : base_type(std::move(c)) { + c.reset(); + } + + template class Layout> + constexpr split_buffer::split_buffer(split_buffer&& c, const alloc_rr& a) + : base_type(a) { + if (a == c.get_allocator()) { + set_data(c.front_cap()); + set_valid_range(c.begin(), c.end()); + set_capacity(c.capacity()); + c.reset(); + } else { + auto allocation = allocate_at_least(get_allocator(), c.size()); + set_data(allocation.ptr); + set_valid_range(front_cap(), front_cap()); + set_capacity(allocation.count); + using Ip = std::move_iterator; + construct_at_end(Ip(c.begin()), Ip(c.end())); + } + } + + template class Layout> + constexpr split_buffer& + split_buffer::operator=(split_buffer&& c) noexcept( + (alloc_traits::propagate_on_container_move_assignment::value + && std::is_nothrow_move_assignable_v) + || !alloc_traits::propagate_on_container_move_assignment::value + ) { + clear(); + shrink_to_fit(); + copy_without_alloc(c); + move_assign_alloc( + c, + std::integral_constant() + ); + c.reset(); + return *this; + } + + template class Layout> + constexpr void split_buffer::swap( + split_buffer& x + ) noexcept(!alloc_traits::propagate_on_container_swap::value || std::is_nothrow_swappable_v) { + base_type::swap(x); + } + + template class Layout> + constexpr void split_buffer::shrink_to_fit() noexcept { + if (capacity() > size()) { +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + split_buffer t(size(), 0, get_allocator()); + if (t.capacity() < capacity()) { + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(end())); + t.set_sentinel(size()); + swap_without_allocator(t); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } + } + + template class Layout> + template + constexpr void split_buffer::emplace_front(Args&&... args) { + if (front_spare() == 0) { + pointer cur_end = end(); + if (back_spare() > 0) { + // The elements are pressed up against the front of the buffer: we need to move them + // back a little bit to make `emplace_front` have amortised O(1) complexity. + difference_type d = back_spare(); + d = (d + 1) / 2; + auto new_end = cur_end + d; + set_valid_range(std::move_backward(begin(), cur_end, new_end), new_end); + } else { + size_type c = std::max(2 * capacity(), 1); + split_buffer t(c, (c + 3) / 4, get_allocator()); + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(cur_end)); + base_type::swap_without_allocator(t); + } + } + + alloc_traits::construct(get_allocator(), std::to_address(begin() - 1), std::forward(args)...); + set_valid_range(begin() - 1, size() + 1); + } + + template class Layout> + template + constexpr void split_buffer::emplace_back(Args&&... args) { + pointer cur_end = end(); + if (back_spare() == 0) { + if (front_spare() > 0) { + difference_type d = front_spare(); + d = (d + 1) / 2; + cur_end = std::move(begin(), cur_end, begin() - d); + set_valid_range(begin() - d, cur_end); + } else { + size_type c = std::max(2 * capacity(), 1); + split_buffer t(c, c / 4, get_allocator()); + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(cur_end)); + base_type::swap_without_allocator(t); + } + } + + alloc_traits::construct(get_allocator(), std::to_address(cur_end), std::forward(args)...); + set_sentinel(++cur_end); + } + + template class Layout> + inline constexpr void + swap(split_buffer& x, split_buffer& y) noexcept( + noexcept(x.swap(y)) + ) { + x.swap(y); + } +} // namespace plg diff --git a/test/cross_call_worker/external/plugify/include/plg/string.hpp b/test/cross_call_worker/external/plugify/include/plg/string.hpp index 830f168..3613b95 100644 --- a/test/cross_call_worker/external/plugify/include/plg/string.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/string.hpp @@ -1,1692 +1,3608 @@ -#pragma once - -// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc -#if PLUGIFY_COMPILER_CLANG -# pragma clang system_header -#elif PLUGIFY_COMPILER_GCC -# pragma GCC system_header -#endif +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// -#include // for std::initializer_list -#include // for std::basic_string_view -#include // for std::is_constant_evaluated, std::declval, std::false_type -#include // for std::min, std::max -#include // for std::unsigned_integral, std::signed_integral -#include // for std::distance, std::next, std::iterator_traits, std::input_iterator -#include // for std::move, std::hash -#include // for std::strong_ordering -#include // for std::allocator, std::swap, std::allocator_traits -#include // for std::numeric_limits -#include // for std::to_chars +#pragma once +// clang-format off + +/* + string synopsis + +#include +#include + +namespace std +{ + +template +class fpos +{ +private: + stateT st; +public: + fpos(streamoff = streamoff()); + + operator streamoff() const; + + stateT state() const; + void state(stateT); + + fpos& operator+=(streamoff); + fpos operator+ (streamoff) const; + fpos& operator-=(streamoff); + fpos operator- (streamoff) const; +}; + +template streamoff operator-(const fpos& x, const fpos& y); + +template bool operator==(const fpos& x, const fpos& y); +template bool operator!=(const fpos& x, const fpos& y); + +template +struct char_traits +{ + using char_type = charT; + using int_type = ...; + using off_type = streamoff; + using pos_type = streampos; + using state_type = mbstate_t; + using comparison_category = strong_ordering; // Since C++20 only for the specializations + // char, wchar_t, char8_t, char16_t, and char32_t. + + static void assign(char_type& c1, const char_type& c2) noexcept; + static constexpr bool eq(char_type c1, char_type c2) noexcept; + static constexpr bool lt(char_type c1, char_type c2) noexcept; + + static int compare(const char_type* s1, const char_type* s2, size_t n); + static size_t length(const char_type* s); + static const char_type* find(const char_type* s, size_t n, const char_type& a); + static char_type* move(char_type* s1, const char_type* s2, size_t n); + static char_type* copy(char_type* s1, const char_type* s2, size_t n); + static char_type* assign(char_type* s, size_t n, char_type a); + + static constexpr int_type not_eof(int_type c) noexcept; + static constexpr char_type to_char_type(int_type c) noexcept; + static constexpr int_type to_int_type(char_type c) noexcept; + static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept; + static constexpr int_type eof() noexcept; +}; + +template <> struct char_traits; +template <> struct char_traits; +template <> struct char_traits; // C++20 +template <> struct char_traits; +template <> struct char_traits; + +template, class Allocator = allocator > +class basic_string +{ +public: +// types: + typedef traits traits_type; + typedef typename traits_type::char_type value_type; + typedef Allocator allocator_type; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef implementation-defined iterator; + typedef implementation-defined const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static const size_type npos = -1; + + basic_string() + noexcept(std::is_nothrow_default_constructible::value); // constexpr since C++20 + explicit basic_string(const allocator_type& a); // constexpr since C++20 + basic_string(const basic_string& str); // constexpr since C++20 + basic_string(basic_string&& str) + noexcept(std::is_nothrow_move_constructible::value); // constexpr since C++20 + basic_string(const basic_string& str, size_type pos, + const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(const basic_string& str, size_type pos, size_type n, + const Allocator& a = Allocator()); // constexpr since C++20 + constexpr basic_string( + basic_string&& str, size_type pos, const Allocator& a = Allocator()); // since C++23 + constexpr basic_string( + basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); // since C++23 + template + basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); // C++17, constexpr since C++20 + template + explicit basic_string(const T& t, const Allocator& a = Allocator()); // C++17, constexpr since C++20 + basic_string(const value_type* s, const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(const value_type* s, size_type n, const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(nullptr_t) = delete; // C++23 + basic_string(size_type n, value_type c, const allocator_type& a = allocator_type()); // constexpr since C++20 + template + basic_string(InputIterator begin, InputIterator end, + const allocator_type& a = allocator_type()); // constexpr since C++20 + template R> + constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); // since C++23 + basic_string(std::initializer_list, const Allocator& = Allocator()); // constexpr since C++20 + basic_string(const basic_string&, const Allocator&); // constexpr since C++20 + basic_string(basic_string&&, const Allocator&); // constexpr since C++20 + + ~basic_string(); // constexpr since C++20 + + operator std::basic_string_view() const noexcept; // constexpr since C++20 + + basic_string& operator=(const basic_string& str); // constexpr since C++20 + template + basic_string& operator=(const T& t); // C++17, constexpr since C++20 + basic_string& operator=(basic_string&& str) + noexcept( + allocator_type::propagate_on_container_move_assignment::value || + allocator_type::is_always_equal::value ); // C++17, constexpr since C++20 + basic_string& operator=(const value_type* s); // constexpr since C++20 + basic_string& operator=(nullptr_t) = delete; // C++23 + basic_string& operator=(value_type c); // constexpr since C++20 + basic_string& operator=(std::initializer_list); // constexpr since C++20 + + iterator begin() noexcept; // constexpr since C++20 + const_iterator begin() const noexcept; // constexpr since C++20 + iterator end() noexcept; // constexpr since C++20 + const_iterator end() const noexcept; // constexpr since C++20 + + reverse_iterator rbegin() noexcept; // constexpr since C++20 + const_reverse_iterator rbegin() const noexcept; // constexpr since C++20 + reverse_iterator rend() noexcept; // constexpr since C++20 + const_reverse_iterator rend() const noexcept; // constexpr since C++20 + + const_iterator cbegin() const noexcept; // constexpr since C++20 + const_iterator cend() const noexcept; // constexpr since C++20 + const_reverse_iterator crbegin() const noexcept; // constexpr since C++20 + const_reverse_iterator crend() const noexcept; // constexpr since C++20 + + size_type size() const noexcept; // constexpr since C++20 + size_type length() const noexcept; // constexpr since C++20 + size_type max_size() const noexcept; // constexpr since C++20 + size_type capacity() const noexcept; // constexpr since C++20 + + void resize(size_type n, value_type c); // constexpr since C++20 + void resize(size_type n); // constexpr since C++20 + + template + constexpr void resize_and_overwrite(size_type n, Operation op); // since C++23 + + void reserve(size_type res_arg); // constexpr since C++20 + void reserve(); // deprecated in C++20, removed in C++26 + void shrink_to_fit(); // constexpr since C++20 + void clear() noexcept; // constexpr since C++20 + bool empty() const noexcept; // constexpr since C++20 + + const_reference operator[](size_type pos) const; // constexpr since C++20 + reference operator[](size_type pos); // constexpr since C++20 + + const_reference at(size_type n) const; // constexpr since C++20 + reference at(size_type n); // constexpr since C++20 + + basic_string& operator+=(const basic_string& str); // constexpr since C++20 + template + basic_string& operator+=(const T& t); // C++17, constexpr since C++20 + basic_string& operator+=(const value_type* s); // constexpr since C++20 + basic_string& operator+=(value_type c); // constexpr since C++20 + basic_string& operator+=(std::initializer_list); // constexpr since C++20 + + basic_string& append(const basic_string& str); // constexpr since C++20 + template + basic_string& append(const T& t); // C++17, constexpr since C++20 + basic_string& append(const basic_string& str, size_type pos, size_type n=npos); // C++14, constexpr since C++20 + template + basic_string& append(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 + basic_string& append(const value_type* s, size_type n); // constexpr since C++20 + basic_string& append(const value_type* s); // constexpr since C++20 + basic_string& append(size_type n, value_type c); // constexpr since C++20 + template + basic_string& append(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& append_range(R&& rg); // C++23 + basic_string& append(std::initializer_list); // constexpr since C++20 + + void push_back(value_type c); // constexpr since C++20 + void pop_back(); // constexpr since C++20 + reference front(); // constexpr since C++20 + const_reference front() const; // constexpr since C++20 + reference back(); // constexpr since C++20 + const_reference back() const; // constexpr since C++20 + + basic_string& assign(const basic_string& str); // constexpr since C++20 + template + basic_string& assign(const T& t); // C++17, constexpr since C++20 + basic_string& assign(basic_string&& str); // constexpr since C++20 + basic_string& assign(const basic_string& str, size_type pos, size_type n=npos); // C++14, constexpr since C++20 + template + basic_string& assign(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 + basic_string& assign(const value_type* s, size_type n); // constexpr since C++20 + basic_string& assign(const value_type* s); // constexpr since C++20 + basic_string& assign(size_type n, value_type c); // constexpr since C++20 + template + basic_string& assign(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& assign_range(R&& rg); // C++23 + basic_string& assign(std::initializer_list); // constexpr since C++20 + + basic_string& insert(size_type pos1, const basic_string& str); // constexpr since C++20 + template + basic_string& insert(size_type pos1, const T& t); // constexpr since C++20 + basic_string& insert(size_type pos1, const basic_string& str, + size_type pos2, size_type n2=npos); // constexpr since C++20 + template + basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n=npos); // C++17, constexpr since C++20 + basic_string& insert(size_type pos, const value_type* s, size_type n=npos); // C++14, constexpr since C++20 + basic_string& insert(size_type pos, const value_type* s); // constexpr since C++20 + basic_string& insert(size_type pos, size_type n, value_type c); // constexpr since C++20 + iterator insert(const_iterator p, value_type c); // constexpr since C++20 + iterator insert(const_iterator p, size_type n, value_type c); // constexpr since C++20 + template + iterator insert(const_iterator p, InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr iterator insert_range(const_iterator p, R&& rg); // C++23 + iterator insert(const_iterator p, std::initializer_list); // constexpr since C++20 + + basic_string& erase(size_type pos = 0, size_type n = npos); // constexpr since C++20 + iterator erase(const_iterator position); // constexpr since C++20 + iterator erase(const_iterator first, const_iterator last); // constexpr since C++20 + + basic_string& replace(size_type pos1, size_type n1, const basic_string& str); // constexpr since C++20 + template + basic_string& replace(size_type pos1, size_type n1, const T& t); // C++17, constexpr since C++20 + basic_string& replace(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2=npos); // C++14, constexpr since C++20 + template + basic_string& replace(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2=npos); // C++17, constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, const value_type* s, size_type n2); // constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, const value_type* s); // constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str); // constexpr since C++20 + template + basic_string& replace(const_iterator i1, const_iterator i2, const T& t); // C++17, constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, size_type n, value_type c); // constexpr since C++20 + template + basic_string& replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2); // constexpr since C++20 + template R> + constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); // C++23 + basic_string& replace(const_iterator i1, const_iterator i2, std::initializer_list); // constexpr since C++20 + + size_type copy(value_type* s, size_type n, size_type pos = 0) const; // constexpr since C++20 + basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr in C++20, removed in C++23 + basic_string substr(size_type pos = 0, size_type n = npos) const&; // since C++23 + constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; // since C++23 + void swap(basic_string& str) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); // C++17, constexpr since C++20 + + const value_type* c_str() const noexcept; // constexpr since C++20 + const value_type* data() const noexcept; // constexpr since C++20 + value_type* data() noexcept; // C++17, constexpr since C++20 + + allocator_type get_allocator() const noexcept; // constexpr since C++20 + + size_type find(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type rfind(const T& t, size_type pos = npos) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type rfind(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type rfind(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type rfind(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find_first_of(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_first_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_first_of(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find_first_of(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type find_last_of(const T& t, size_type pos = npos) const noexcept noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_last_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_last_of(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type find_last_of(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_first_not_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_first_not_of(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_last_not_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_last_not_of(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + int compare(const basic_string& str) const noexcept; // constexpr since C++20 + template + int compare(const T& t) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + int compare(size_type pos1, size_type n1, const basic_string& str) const; // constexpr since C++20 + template + int compare(size_type pos1, size_type n1, const T& t) const; // C++17, constexpr since C++20 + int compare(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2=npos) const; // C++14, constexpr since C++20 + template + int compare(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2=npos) const; // C++17, constexpr since C++20 + int compare(const value_type* s) const noexcept; // constexpr since C++20 + int compare(size_type pos1, size_type n1, const value_type* s) const; // constexpr since C++20 + int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; // constexpr since C++20 + + constexpr bool starts_with(std::basic_string_view sv) const noexcept; // C++20 + constexpr bool starts_with(charT c) const noexcept; // C++20 + constexpr bool starts_with(const charT* s) const; // C++20 + constexpr bool ends_with(std::basic_string_view sv) const noexcept; // C++20 + constexpr bool ends_with(charT c) const noexcept; // C++20 + constexpr bool ends_with(const charT* s) const; // C++20 + + constexpr bool contains(std::basic_string_view sv) const noexcept; // C++23 + constexpr bool contains(charT c) const noexcept; // C++23 + constexpr bool contains(const charT* s) const; // C++23 +}; + +template::value_type>> +basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string::value_type, + char_traits::value_type>, + Allocator>; // C++17 + +template>> + basic_string(from_range_t, R&&, Allocator = Allocator()) + -> basic_string, char_traits>, + Allocator>; // C++23 + +template> + explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) + -> basic_string; // C++17 + +template> + basic_string(std::basic_string_view, + typename see below::size_type, typename see below::size_type, + const Allocator& = Allocator()) + -> basic_string; // C++17 + +template +basic_string +operator+(const basic_string& lhs, + const basic_string& rhs); // constexpr since C++20 + +template +basic_string +operator+(const charT* lhs , const basic_string&rhs); // constexpr since C++20 + +template +basic_string +operator+(charT lhs, const basic_string& rhs); // constexpr since C++20 + +template +basic_string +operator+(const basic_string& lhs, const charT* rhs); // constexpr since C++20 + +template +basic_string +operator+(const basic_string& lhs, charT rhs); // constexpr since C++20 + +template + constexpr basic_string + operator+(const basic_string& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(basic_string&& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + const basic_string& rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + basic_string&& rhs); // Since C++26 + + +template +bool operator==(const basic_string& lhs, + const basic_string& rhs) noexcept; // constexpr since C++20 + +template +bool operator==(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator==(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 + +template +bool operator!=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator!=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator!=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator< (const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator< (const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator< (const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator> (const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator> (const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator> (const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator<=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator<=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator<=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator>=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator>=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator>=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const basic_string& rhs) noexcept; + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const charT* rhs) noexcept; + +template +void swap(basic_string& lhs, + basic_string& rhs) + noexcept(noexcept(lhs.swap(rhs))); // constexpr since C++20 + +template +std::basic_istream& +operator>>(std::basic_istream& is, basic_string& str); + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const basic_string& str); + +template +std::basic_istream& +getline(std::basic_istream& is, basic_string& str, + charT delim); + +template +std::basic_istream& +getline(std::basic_istream& is, basic_string& str); + +template +constexpr typename basic_string::size_type +erase(basic_string& c, const U& value); // C++20 +template +constexpr typename basic_string::size_type +erase_if(basic_string& c, Predicate pred); // C++20 + +typedef basic_string string; +typedef basic_string wstring; +typedef basic_string u8string; // C++20 +typedef basic_string u16string; +typedef basic_string u32string; + +int stoi (const string& str, size_t* idx = nullptr, int base = 10); +long stol (const string& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul (const string& str, size_t* idx = nullptr, int base = 10); +long long stoll (const string& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10); + +float stof (const string& str, size_t* idx = nullptr); +double stod (const string& str, size_t* idx = nullptr); +long double stold(const string& str, size_t* idx = nullptr); + +string to_string(int val); +string to_string(unsigned val); +string to_string(long val); +string to_string(unsigned long val); +string to_string(long long val); +string to_string(unsigned long long val); +string to_string(float val); +string to_string(double val); +string to_string(long double val); + +int stoi (const wstring& str, size_t* idx = nullptr, int base = 10); +long stol (const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul (const wstring& str, size_t* idx = nullptr, int base = 10); +long long stoll (const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10); + +float stof (const wstring& str, size_t* idx = nullptr); +double stod (const wstring& str, size_t* idx = nullptr); +long double stold(const wstring& str, size_t* idx = nullptr); + +wstring to_wstring(int val); +wstring to_wstring(unsigned val); +wstring to_wstring(long val); +wstring to_wstring(unsigned long val); +wstring to_wstring(long long val); +wstring to_wstring(unsigned long long val); +wstring to_wstring(float val); +wstring to_wstring(double val); +wstring to_wstring(long double val); + +template <> struct hash; +template <> struct hash; // C++20 +template <> struct hash; +template <> struct hash; +template <> struct hash; + +basic_string operator""s( const char *str, size_t len ); // C++14, constexpr since C++20 +basic_string operator""s( const wchar_t *str, size_t len ); // C++14, constexpr since C++20 +constexpr basic_string operator""s( const char8_t *str, size_t len ); // C++20 +basic_string operator""s( const char16_t *str, size_t len ); // C++14, constexpr since C++20 +basic_string operator""s( const char32_t *str, size_t len ); // C++14, constexpr since C++20 + +} // std + +*/ + +// clang-format on + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#if PLUGIFY_STRING_CONTAINERS_RANGES && (__cplusplus <= 202002L || !__has_include() || !defined(__cpp_lib_containers_ranges)) -# undef PLUGIFY_STRING_CONTAINERS_RANGES -# define PLUGIFY_STRING_CONTAINERS_RANGES 0 -#endif - -#if PLUGIFY_STRING_CONTAINERS_RANGES -# include -#endif - -#ifndef PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS -# include -#endif +#include "plg/allocator.hpp" +#include "plg/guards.hpp" +#include "plg/concepts.hpp" #ifndef PLUGIFY_STRING_NO_STD_FORMAT #include "plg/format.hpp" #endif -#include "plg/allocator.hpp" +// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc +#if PLUGIFY_COMPILER_CLANG +# pragma clang system_header +#elif PLUGIFY_COMPILER_GCC +# pragma GCC system_header +#endif +// from https://github.com/llvm/llvm-project/blob/main/libcxx/include/string namespace plg { - namespace detail { - template - concept is_allocator = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; + // basic_string + template + class basic_string; - template - concept is_char_traits = requires { - // Required type definitions - typename Traits::char_type; - typename Traits::int_type; - typename Traits::off_type; - typename Traits::pos_type; - typename Traits::state_type; - } && requires( - typename Traits::char_type c1, - typename Traits::char_type c2, - typename Traits::char_type& cr, - const typename Traits::char_type& ccr, - typename Traits::char_type* p, - const typename Traits::char_type* cp, - typename Traits::int_type i1, - typename Traits::int_type i2, - std::size_t n - ) { - // Character operations - { Traits::assign(cr, ccr) } -> std::same_as; - { Traits::eq(ccr, ccr) } -> std::convertible_to; - { Traits::lt(ccr, ccr) } -> std::convertible_to; - - // String operations - { Traits::compare(cp, cp, n) } -> std::convertible_to; - { Traits::length(cp) } -> std::convertible_to; - { Traits::find(cp, n, ccr) } -> std::convertible_to; - - // Memory operations - { Traits::move(p, cp, n) } -> std::same_as; - { Traits::copy(p, cp, n) } -> std::same_as; - { Traits::assign(p, n, c1) } -> std::same_as; - - // int_type operations - { Traits::not_eof(i1) } -> std::same_as; - { Traits::to_char_type(i1) } -> std::same_as; - { Traits::to_int_type(c1) } -> std::same_as; - { Traits::eq_int_type(i1, i2) } -> std::convertible_to; - { Traits::eof() } -> std::same_as; - }; + template + constexpr basic_string concatenate_strings( + const Allocator& alloc, + std::type_identity_t> str1, + std::type_identity_t> str2 + ); - struct uninitialized_size_tag {}; + template + inline const bool string_is_trivial_iterator_v = false; - template - constexpr bool dependent_false = false; + template + concept string_is_trivial_iterator = std::is_arithmetic_v; -#if PLUGIFY_STRING_CONTAINERS_RANGES - template - concept string_compatible_range = std::ranges::input_range && std::convertible_to, Type>; -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + concept string_view_convertible = std::is_convertible_v> && !std::is_convertible_v; - } // namespace detail + // second concept = the above, but exclude std::basic_string itself + template + concept string_view_convertible_with_exceptiom = string_view_convertible && !std::is_same_v, basic_string>; - // basic_string - // based on implementations from libc++, libstdc++ and Microsoft STL - template, detail::is_allocator Allocator = plg::allocator> + template + concept string_like = requires(T v) { + { std::string_view(v) }; + }; + + template + struct padding { + char _pad[N]; + }; + + template <> + struct padding<0> {}; + + struct uninitialized_size_tag {}; + + struct init_with_sentinel_tag {}; + + template , class Allocator = allocator> class basic_string { - private: - using allocator_traits = std::allocator_traits; public: + // using self = std::basic_string; + using self_view = std::basic_string_view; using traits_type = Traits; - using value_type = typename traits_type::char_type; + using value_type = CharT; using allocator_type = Allocator; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; + using alloc_traits = std::allocator_traits; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; using reference = value_type&; using const_reference = const value_type&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + + // A basic_string contains the following members which may be trivially relocatable: + // - pointer: is currently assumed to be trivially relocatable, but is still checked in case + // that changes + // - size_type: is always trivially relocatable, since it has to be an integral type + // - value_type: is always trivially relocatable, since it has to be trivial + // - unsigned char: is a fundamental type, so it's trivially relocatable + // - allocator_type: may or may not be trivially relocatable, so it's checked + // + // This string implementation doesn't contain any references into itself. It only contains a + // bit that says whether it is in small or large string mode, so the entire structure is + // trivially relocatable if its members are. +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + // When compiling with AddressSanitizer (ASan), basic_string cannot be trivially + // relocatable. Because the object's memory might be poisoned when its content + // is kept inside objects memory (short string optimization), instead of in allocated + // external memory. In such cases, the destructor is responsible for unpoisoning + // the memory to avoid triggering false positives. + // Therefore it's crucial to ensure the destructor is called. + // + // However, it is replaceable since implementing move-assignment as a destroy + + // move-construct will maintain the right ASAN state. + using trivially_relocatable = void; +#else + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value, + basic_string, + void>; +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + +#if PLUGIFY_INSTRUMENTED_WITH_ASAN && __has_cpp_attribute(__no_sanitize__) +# define PLUGIFY_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address"))) +// This macro disables AddressSanitizer (ASan) instrumentation for a specific function, +// allowing memory accesses that would normally trigger ASan errors to proceed without crashing. +// This is useful for accessing parts of objects memory, which should not be accessed, +// such as unused bytes in short strings, that should never be accessed +// by other parts of the program. +#else +# define PLUGIFY_INTERNAL_MEMORY_ACCESS +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + constexpr pointer asan_volatile_wrapper(pointer const& ptr) const { + if (std::is_constant_evaluated()) { + return ptr; + } + + volatile pointer copy_ptr = ptr; + + return const_cast(copy_ptr); + } + + constexpr const_pointer asan_volatile_wrapper(const const_pointer& ptr) const { + if (std::is_constant_evaluated()) { + return ptr; + } + + volatile const_pointer copy_ptr = ptr; + + return const_cast(copy_ptr); + } + +# define PLUGIFY_ASAN_VOLATILE_WRAPPER(PTR) asan_volatile_wrapper(PTR) +#else +# define PLUGIFY_ASAN_VOLATILE_WRAPPER(PTR) PTR +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + + static_assert(!std::is_array_v, "Character type of basic_string must not be an array"); + static_assert( + std::is_standard_layout_v, + "Character type of basic_string must be standard-layout" + ); + static_assert( + std::is_trivially_default_constructible_v, + "Character type of basic_string must be trivially default constructible" + ); + static_assert( + std::is_trivially_copyable_v, + "Character type of basic_string must be trivially copyable" + ); + static_assert( + std::is_same_v, + "traits_type::char_type must be the same type as CharT" + ); + static_assert( + std::is_same_v, + "Allocator::value_type must be same type as value_type" + ); + // static_assert(std::check_valid_allocator::value, ""); + using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - using sview_type = std::basic_string_view; - constexpr static size_type npos = static_cast(-1); + using alloc_result = allocation_result; private: - constexpr static auto _terminator = value_type(); - - PLUGIFY_NO_UNIQUE_ADDRESS - allocator_type _allocator; + static constexpr int char_bit = std::numeric_limits::digits + std::numeric_limits::is_signed; + static_assert(char_bit == 8, "This implementation assumes that one byte contains 8 bits"); - PLUGIFY_WARN_PUSH() + struct long_ { + constexpr long_() = default; -#if PLUGIFY_COMPILER_CLANG - PLUGIFY_WARN_IGNORE("-Wgnu-anonymous-struct") - PLUGIFY_WARN_IGNORE("-Wzero-length-array") -#elif PLUGIFY_COMPILER_GCC - PLUGIFY_WARN_IGNORE("-Wpedantic") -#elif PLUGIFY_COMPILER_MSVC - PLUGIFY_WARN_IGNORE(4201) - PLUGIFY_WARN_IGNORE(4200) -#endif + constexpr long_(alloc_result alloc, size_type size) + : _data(alloc.ptr) + , _size(size) + , _cap(alloc.count / endian_factor) + , _is_long(true) { + PLUGIFY_ASSERT(!fits_in_sso(alloc.count), "Long capacity should always be larger than the SSO"); + } - template - struct padding { - [[maybe_unused]] uint8_t pad[sizeof(CharT) - 1]; + pointer _data; + size_type _size; + size_type _cap : sizeof(size_type) * char_bit - 1; + size_type _is_long : 1; }; - template - struct padding { - // template specialization to remove the padding structure to avoid warnings on zero length arrays - // also, this allows us to take advantage of the empty-base-class optimization. - }; + static constexpr size_type min_cap = ((sizeof(long_) - 1) / sizeof(value_type) > 2 ? (sizeof(long_) - 1) / sizeof(value_type) : 2) + 1; - // size must correspond to the last byte of long_data.cap, so we don't want the compiler to insert - // padding after size if sizeof(value_type) != 1; Also ensures both layouts are the same size. - struct sso_size : padding { - PLUGIFY_PACK(struct { - uint8_t spare_size : 7; - uint8_t is_long : 1; - }); - }; + struct short_ { + constexpr short_() + : _data{} + , _spare_size(min_cap - 1) + , _is_long(false) { + } - static constexpr int char_bit = std::numeric_limits::digits + std::numeric_limits::is_signed; - static_assert(char_bit == 8, "assumes an 8 bit byte."); - - struct long_data { - pointer data; - size_type size; - PLUGIFY_PACK(struct { - size_type cap : sizeof(size_type) * char_bit - 1; - size_type is_long : 1; - }); + value_type _data[min_cap - 1]; + PLUGIFY_NO_UNIQUE_ADDRESS padding _padding; + uint8_t _spare_size : 7; + uint8_t _is_long : 1; }; - static constexpr size_type min_cap = (sizeof(long_data) - 1) / sizeof(value_type) > 2 ? (sizeof(long_data) - 1) / sizeof(value_type) : 2; + // The endian_factor is required because the field we use to store the size + // has one fewer bit than it would if it were not a bitfield. + // + // If the LSB is used to store the short-flag in the short string representation, + // we have to multiply the size by two when it is stored and divide it by two when + // it is loaded to make sure that we always store an even number. In the long string + // representation, we can ignore this because we can assume that we always allocate + // an even amount of value_types. + // + // If the MSB is used for the short-flag, the max_size() is numeric_limits::max() + // / 2. This does not impact the short string representation, since we never need the MSB + // for representing the size of a short string anyway. + + static constexpr size_type endian_factor = std::endian::native == std::endian::big ? 2 : 1; + + static_assert( + sizeof(short_) == (sizeof(value_type) * min_cap), + "short has an unexpected size." + ); + static_assert( + sizeof(short_) == sizeof(long_), + "short and long layout structures must be the same size" + ); + + union rep { + short_ s{}; + long_ l; + } _rep; + PLUGIFY_NO_UNIQUE_ADDRESS + allocator_type _alloc; + + // annotate the string with its size() at scope exit. The string has to be in a valid state + // at that point. + struct annotate_new_size { + basic_string& _str; - struct short_data { - value_type data[min_cap]; - sso_size size; + constexpr explicit annotate_new_size(basic_string& str) + : _str(str) { + } + + constexpr void operator()() { + _str.annotate_new(_str.size()); + } }; - PLUGIFY_WARN_POP() + // Construct a string with the given allocator and enough storage to hold `size` characters, + // but don't initialize the characters. The contents of the string, including the null + // terminator, must be initialized separately. + constexpr /*explicit*/ basic_string(uninitialized_size_tag, size_type size, const allocator_type& a) + : _alloc(a) { + init_internal_buffer(size); + } - static_assert(sizeof(short_data) == (sizeof(value_type) * (min_cap + 1)), "short has an unexpected size."); - static_assert(sizeof(short_data) == sizeof(long_data), "short and long layout structures must be the same size"); + template + constexpr basic_string(init_with_sentinel_tag, Iter first, Sent last, const allocator_type& a) + : _alloc(a) { + init_with_sentinel(std::move(first), std::move(last)); + } - union { - long_data _long; - short_data _short{}; - } _storage; + constexpr iterator make_iterator(pointer p) { + return iterator(p); + } - constexpr static bool fits_in_sso(size_type size) noexcept { - return size < min_cap; + constexpr const_iterator make_const_iterator(const_pointer p) const { + return const_iterator(p); } - constexpr void long_init() noexcept { - set_long(true); - set_long_data(nullptr); - set_long_size(0); - set_long_cap(0); + public: + static const size_type npos = static_cast(-1); + + constexpr basic_string() noexcept(std::is_nothrow_default_constructible_v) + : _rep(short_()) { + annotate_new(0); } - constexpr void short_init() noexcept { - set_long(false); - set_short_size(0); + constexpr /*explicit*/ basic_string(const allocator_type& a) noexcept + : _rep(short_()) + , _alloc(a) { + annotate_new(0); } - constexpr void default_init(size_type size) noexcept { - if (fits_in_sso(size)) - short_init(); - else - long_init(); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& str) + : _alloc(alloc_traits::select_on_container_copy_construction(str._alloc)) { + if (!str.is_long()) { + _rep = str._rep; + annotate_new(get_short_size()); + } else { + init_copy_ctor_external(std::to_address(str.get_long_pointer()), str.get_long_size()); + } } - constexpr auto& get_long_data() noexcept { - return _storage._long.data; + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS + basic_string(const basic_string& str, const allocator_type& a) + : _alloc(a) { + if (!str.is_long()) { + _rep = str._rep; + annotate_new(get_short_size()); + } else { + init_copy_ctor_external(std::to_address(str.get_long_pointer()), str.get_long_size()); + } } - constexpr const auto& get_long_data() const noexcept { - return _storage._long.data; + constexpr basic_string(basic_string&& str) noexcept + // Turning off ASan instrumentation for variable initialization with + // PLUGIFY_INTERNAL_MEMORY_ACCESS does not work consistently during + // initialization of r_, so we instead unpoison str's memory manually first. str's + // memory needs to be unpoisoned only in the case where it's a short string. + : _rep([](basic_string& s) -> decltype(s._rep)&& { + if (!s.is_long()) { + s.annotate_delete(); + } + return std::move(s._rep); + }(str)) + , _alloc(std::move(str._alloc)) { + str._rep = rep(); + str.annotate_new(0); + if (!is_long()) { + annotate_new(size()); + } } - constexpr auto& get_short_data() noexcept { - return _storage._short.data; + constexpr basic_string(basic_string&& str, const allocator_type& a) + : _alloc(a) { + if (str.is_long() && a != str._alloc) { // copy, not move + init(std::to_address(str.get_long_pointer()), str.get_long_size()); + } else { + if (std::is_constant_evaluated()) { + _rep = rep(); + } + if (!str.is_long()) { + str.annotate_delete(); + } + _rep = str._rep; + str._rep = rep(); + str.annotate_new(0); + if (!is_long() && this != std::addressof(str)) { + annotate_new(size()); + } + } } - constexpr const auto& get_short_data() const noexcept { - return _storage._short.data; + constexpr basic_string(const CharT* PLUGIFY_NO_NULL s) + requires(is_allocator) + { + PLUGIFY_ASSERT(s != nullptr, "basic_string(const char*) detected nullptr"); + init(s, traits_type::length(s)); } - constexpr void set_short_size(size_type size) noexcept { - _storage._short.size.spare_size = min_cap - (size & 0x7F); + constexpr basic_string(const CharT* PLUGIFY_NO_NULL s, const Allocator& a) + requires(is_allocator) + : _alloc(a) { + PLUGIFY_ASSERT(s != nullptr, "basic_string(const char*, allocator) detected nullptr"); + init(s, traits_type::length(s)); } - constexpr size_type get_short_size() const noexcept { - return min_cap - _storage._short.size.spare_size; + basic_string(std::nullptr_t) = delete; + + constexpr basic_string(const CharT* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "basic_string(const char*, n) detected nullptr"); + init(s, n); } - constexpr void set_long_size(size_type size) noexcept { - _storage._long.size = size; + constexpr basic_string(const CharT* s, size_type n, const Allocator& a) + : _alloc(a) { + PLUGIFY_ASSERT( + n == 0 || s != nullptr, + "basic_string(const char*, n, allocator) detected nullptr" + ); + init(s, n); } - constexpr size_type get_long_size() const noexcept { - return _storage._long.size; + constexpr basic_string(size_type n, CharT c) { + init(n, c); } - constexpr void set_long_cap(size_type cap) noexcept { - _storage._long.cap = (cap & 0x7FFFFFFFFFFFFFFF); + constexpr basic_string(basic_string&& str, size_type pos, const Allocator& alloc = Allocator()) + : basic_string(std::move(str), pos, npos, alloc) { } - constexpr size_type get_long_cap() const noexcept { - return _storage._long.cap; + constexpr basic_string( + basic_string&& str, + size_type pos, + size_type n, + const Allocator& alloc = Allocator() + ) + : _alloc(alloc) { + if (pos > str.size()) { + this->throw_out_of_range(); + } + + auto len = std::min(n, str.size() - pos); + if (alloc_traits::is_always_equal::value || alloc == str._alloc) { + move_assign(std::move(str), pos, len); + } else { + // Perform a copy because the allocators are not compatible. + init(str.data() + pos, len); + } } - constexpr void set_long_data(value_type* data) noexcept { - _storage._long.data = data; + constexpr basic_string(size_type n, CharT c, const Allocator& a) + requires(is_allocator) + : _alloc(a) { + init(n, c); } - constexpr bool is_long() const noexcept { - return _storage._long.is_long == true; + constexpr basic_string( + const basic_string& str, + size_type pos, + size_type n, + const Allocator& a = Allocator() + ) + : _alloc(a) { + size_type str_sz = str.size(); + if (pos > str_sz) { + this->throw_out_of_range(); + } + init(str.data() + pos, std::min(n, str_sz - pos)); } - constexpr void set_long(bool is_long) noexcept { - _storage._long.is_long = is_long; + constexpr basic_string(const basic_string& str, size_type pos, const Allocator& a = Allocator()) + : _alloc(a) { + size_type str_sz = str.size(); + if (pos > str_sz) { + this->throw_out_of_range(); + } + init(str.data() + pos, str_sz - pos); } - constexpr void set_size(size_type size) noexcept { - if (is_long()) - set_long_size(size); - else - set_short_size(size); + template T> + constexpr basic_string( + const T& t, + size_type pos, + size_type n, + const allocator_type& a = allocator_type() + ) + : _alloc(a) { + self_view sv0 = t; + self_view sv = sv0.substr(pos, n); + init(sv.data(), sv.size()); } - constexpr sview_type view() const noexcept { - return sview_type(data(), size()); + template T> + constexpr /*explicit*/ basic_string(const T& t) { + self_view sv = t; + init(sv.data(), sv.size()); } - constexpr void reallocate(size_type new_cap, bool copy_old) { - if (new_cap == get_long_cap()) - return; + template T> + constexpr /*explicit*/ basic_string(const T& t, const allocator_type& a) + : _alloc(a) { + self_view sv = t; + init(sv.data(), sv.size()); + } - auto old_len = get_long_size(); - auto old_cap = get_long_cap(); - auto& old_buffer = get_long_data(); + template + constexpr basic_string(InputIterator first, InputIterator last) { + init(first, last); + } - auto new_len = std::min(new_cap, old_len); - auto new_data = allocator_traits::allocate(_allocator, new_cap + 1); + template + constexpr basic_string(InputIterator first, InputIterator last, const allocator_type& a) + : _alloc(a) { + init(first, last); + } - if (old_buffer != nullptr) { - if (old_len != 0 && copy_old) - Traits::copy(new_data, old_buffer, new_len); - allocator_traits::deallocate(_allocator, old_buffer, old_cap + 1); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string(std::from_range_t, Range&& range, const allocator_type& a = allocator_type()) + : _alloc(a) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + init_with_size( + std::ranges::begin(range), + std::ranges::end(range), + std::ranges::distance(range) + ); + } else { + init_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } + } +#endif - set_long_data(new_data); - set_long_size(new_len); - set_long_cap(new_cap); + constexpr basic_string(std::initializer_list il) { + init(il.begin(), il.end()); } - constexpr void deallocate() { - if (is_long()) { - if (auto& buffer = get_long_data(); buffer != nullptr) { - allocator_traits::deallocate(_allocator, buffer, get_long_cap() + 1); - buffer = nullptr; - } - } + constexpr basic_string(std::initializer_list il, const Allocator& a) + : _alloc(a) { + init(il.begin(), il.end()); } - constexpr void grow_to(size_type new_cap) { - if (is_long() == true) { - reallocate(new_cap, true); - return; - } + inline constexpr ~basic_string() { + reset_internal_buffer(); + } - auto buffer = allocator_traits::allocate(_allocator, new_cap + 1); - auto len = get_short_size(); + constexpr operator self_view() const noexcept { + return self_view(begin(), end()); + } - Traits::copy(buffer, get_short_data(), len); - Traits::assign(buffer[len], _terminator); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string& operator=(const basic_string& str); - long_init(); - set_long_data(buffer); - set_long_size(len); - set_long_cap(new_cap); + template T> + constexpr basic_string& operator=(const T& t) { + self_view sv = t; + return assign(sv); } - constexpr void null_terminate() { - auto buffer = data(); - if (buffer == nullptr) [[unlikely]] - return; - Traits::assign(buffer[size()], _terminator); + constexpr basic_string& operator=(basic_string&& str + ) noexcept(alloc_traits::propagate_on_container_move_assignment::value) { + move_assign( + str, + std::integral_constant() + ); + return *this; } - constexpr bool addr_in_range(const_pointer ptr) const noexcept { - if (std::is_constant_evaluated()) - return false; - else - return data() <= ptr && ptr <= data() + size(); + constexpr basic_string& operator=(std::initializer_list il) { + return assign(il.begin(), il.size()); } - template - constexpr void internal_replace_impl(const F& func, size_type pos, size_type oldcount, size_type count) { - auto cap = capacity(); - auto sz = size(); + constexpr basic_string& operator=(const value_type* PLUGIFY_NO_NULL s) { + return assign(s); + } - auto rsz = sz - oldcount + count; + basic_string& operator=(std::nullptr_t) = delete; + constexpr basic_string& operator=(value_type c); - if (cap < rsz) - grow_to(rsz); + constexpr iterator begin() noexcept { + return make_iterator(get_pointer()); + } - if (oldcount != count) - Traits::move(data() + pos + count, data() + pos + oldcount, sz - pos - oldcount); + constexpr const_iterator begin() const noexcept { + return make_const_iterator(get_pointer()); + } - func(); + constexpr iterator end() noexcept { + return make_iterator(get_pointer() + size()); + } - set_size(rsz); - null_terminate(); + constexpr const_iterator end() const noexcept { + return make_const_iterator(get_pointer() + size()); } - constexpr void internal_replace(size_type pos, const_pointer str, size_type oldcount, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_replace_impl([&]() { Traits::copy(data() + pos, rstr.data(), count); }, pos, oldcount, count); - } else - internal_replace_impl([&]() { Traits::copy(data() + pos, str, count); }, pos, oldcount, count); + constexpr reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); } - constexpr void internal_replace(size_type pos, value_type ch, size_type oldcount, size_type count) { - internal_replace_impl([&]() { Traits::assign(data() + pos, count, ch); }, pos, oldcount, count); + constexpr const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); } - template - constexpr void internal_insert_impl(const F& func, size_type pos, size_type count) { - if (count == 0) [[unlikely]] - return; + constexpr reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - auto cap = capacity(); - auto sz = size(); - auto rsz = sz + count; + constexpr const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - if (cap < rsz) - grow_to(rsz); + constexpr const_iterator cbegin() const noexcept { + return begin(); + } - Traits::move(data() + pos + count, data() + pos, sz - pos); - func(); + constexpr const_iterator cend() const noexcept { + return end(); + } - set_size(rsz); - null_terminate(); + constexpr const_reverse_iterator crbegin() const noexcept { + return rbegin(); } - constexpr void internal_insert(size_type pos, const_pointer str, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_insert_impl([&]() { Traits::copy(data() + pos, rstr.data(), count); }, pos, count); - } else - internal_insert_impl([&]() { Traits::copy(data() + pos, str, count); }, pos, count); + constexpr const_reverse_iterator crend() const noexcept { + return rend(); } - constexpr void internal_insert(size_type pos, value_type ch, size_type count) { - internal_insert_impl([&]() { Traits::assign(data() + pos, count, ch); }, pos, count); + constexpr size_type size() const noexcept { + return is_long() ? get_long_size() : get_short_size(); } - template - constexpr void internal_append_impl(const F& func, size_type count) { - if (count == 0) [[unlikely]] - return; + constexpr size_type length() const noexcept { + return size(); + } - auto cap = capacity(); - auto sz = size(); - auto rsz = sz + count; + constexpr size_type max_size() const noexcept { + constexpr bool uses_lsb = endian_factor == 2; - if (cap < rsz) - grow_to(rsz); + if (size_type m = alloc_traits::max_size(_alloc); + m <= std::numeric_limits::max() / 2) { + size_type res = m - alignment; - func(sz); - set_size(rsz); - null_terminate(); - } + // When the endian_factor == 2, our string representation assumes that the capacity + // (including the null terminator) is always even, so we have to make sure the + // lowest bit isn't set when the string grows to max_size() + if constexpr (uses_lsb) { + res &= ~size_type(1); + } - constexpr void internal_append(const_pointer str, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_append_impl([&](size_type pos) { Traits::copy(data() + pos, rstr.data(), count); }, count); - } else - internal_append_impl([&](size_type pos) { Traits::copy(data() + pos, str, count); }, count); + // We have to allocate space for the null terminator, but max_size() doesn't include + // it. + return res - 1; + } else { + return uses_lsb ? m - alignment - 1 : (m / 2) - alignment - 1; + } } - constexpr void internal_append(value_type ch, size_type count) { - internal_append_impl([&](size_type pos) { Traits::assign(data() + pos, count, ch); }, count); + constexpr size_type capacity() const noexcept { + return (is_long() ? get_long_cap() : min_cap) - 1; } - template - constexpr void internal_assign_impl(const F& func, size_type size, bool copy_old) { - if (fits_in_sso(size)) { - if (is_long() == true) { - deallocate(); - short_init(); - } + constexpr void resize(size_type n, value_type c); - set_short_size(size); - func(get_short_data()); - null_terminate(); - } else { - if (is_long() == false) - long_init(); - if (get_long_cap() < size) - reallocate(size, copy_old); + constexpr void resize(size_type n) { + resize(n, value_type()); + } + + constexpr void reserve(size_type requested_capacity); - func(get_long_data()); - set_long_size(size); - null_terminate(); +#if PLUGIFY_HAS_CXX23 + /*template + constexpr void resize_and_overwrite(size_type n, Op op) { + size_type sz = size(); + size_type cap = capacity(); + if (n > cap) { + grow_by_without_replace(cap, n - cap, sz, sz, 0); } - } + annotate_delete(); + set_size(n); + annotate_new(n); + erase_to_end(std::move(op)(data(), auto(n))); + }*/ +#endif + + constexpr void shrink_to_fit() noexcept; + constexpr void clear() noexcept; - constexpr void internal_assign(const_pointer str, size_type size, bool copy_old = false) { - if (addr_in_range(str)) { - basic_string rstr(str, size); - internal_assign_impl([&](auto data) { Traits::copy(data, rstr.data(), size); }, size, copy_old); - } else - internal_assign_impl([&](auto data) { Traits::copy(data, str, size); }, size, copy_old); + [[nodiscard]] constexpr bool empty() const noexcept { + return size() == 0; } - constexpr void internal_assign(value_type ch, size_type count, bool copy_old = false) { - internal_assign_impl([&](auto data) { Traits::assign(data, count, ch); }, count, copy_old); + constexpr const_reference operator[](size_type pos) const noexcept { + PLUGIFY_ASSERT(pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(pos) && !fits_in_sso(pos)) { + return *(get_long_pointer() + pos); + } + return *(data() + pos); } - public: - explicit constexpr basic_string(detail::uninitialized_size_tag, size_type size, const Allocator& allocator) - : _allocator(allocator) { - PLUGIFY_ASSERT(size <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - if (fits_in_sso(size)) - short_init(); - else { - long_init(); - reallocate(size, false); + constexpr reference operator[](size_type pos) noexcept { + PLUGIFY_ASSERT(pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(pos) && !fits_in_sso(pos)) { + return *(get_long_pointer() + pos); } - set_size(size); + return *(get_pointer() + pos); } - constexpr basic_string() noexcept(std::is_nothrow_default_constructible::value) - : basic_string(Allocator()) {} + constexpr const_reference at(size_type n) const; + constexpr reference at(size_type n); - explicit constexpr basic_string(const Allocator& allocator) noexcept - : _allocator(allocator) { - short_init(); + constexpr basic_string& operator+=(const basic_string& str) { + return append(str); } - constexpr basic_string(size_type count, value_type ch, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(ch, count); + template T> + constexpr basic_string& operator+=(const T& t) { + self_view sv = t; + return append(sv); } - constexpr basic_string(const basic_string& str, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - auto len = std::min(count, str.size() - pos); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str.data() + pos, len); + constexpr basic_string& operator+=(const value_type* PLUGIFY_NO_NULL s) { + return append(s); } - constexpr basic_string(const basic_string& str, size_type pos, const Allocator& allocator = Allocator()) - : basic_string(str, pos, npos, allocator) {} - constexpr basic_string(const value_type* str, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str, count); + constexpr basic_string& operator+=(value_type c) { + push_back(c); + return *this; } - constexpr basic_string(const value_type* str, const Allocator& allocator = Allocator()) - : basic_string(str, Traits::length(str), allocator) {} - - template - constexpr basic_string(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - if constexpr (std::contiguous_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(first), len); - } else { - if constexpr (std::random_access_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - reserve(len); - } - for (auto it = first; it != last; ++it) { - push_back(*it); - } - } + constexpr basic_string& operator+=(std::initializer_list il) { + return append(il); } - constexpr basic_string(const basic_string& str, const Allocator& allocator) - : _allocator(allocator) { - auto len = str.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str.data(), len); + constexpr basic_string& append(const basic_string& str) { + return append(str.data(), str.size()); } - constexpr basic_string(const basic_string& str) - : basic_string(str, str.get_allocator()) {} - constexpr basic_string(basic_string&& str) noexcept(std::is_nothrow_move_constructible::value) - : _allocator(std::move(str._allocator)), _storage(std::move(str._storage)) { - str.short_init(); + template T> + constexpr basic_string& append(const T& t) { + self_view sv = t; + return append(sv.data(), sv.size()); } - constexpr basic_string(basic_string&& str, const Allocator& allocator) - : _allocator(allocator) { - if constexpr (allocator_traits::is_always_equal::value) { - std::swap(_storage, str._storage); - } else { - if (!str.is_long() || get_allocator() == str.get_allocator()) { - std::swap(_storage, str._storage); - } else { - internal_assign(str.data(), str.size()); - str.deallocate(); - } + constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); + + template T> + constexpr basic_string& append(const T& t, size_type pos, size_type n = npos) { + self_view sv = t; + size_type sz = sv.size(); + if (pos > sz) { + throw_out_of_range(); } - str.short_init(); + return append(sv.data() + pos, std::min(n, sz - pos)); } - constexpr basic_string(std::initializer_list list, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - auto len = list.size(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(list.begin()), len); + constexpr basic_string& append(const value_type* s, size_type n); + constexpr basic_string& append(const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& append(size_type n, value_type c); + + template + constexpr basic_string& append(InputIterator first, InputIterator last) { + const basic_string temp(first, last, _alloc); + append(temp.data(), temp.size()); + return *this; } - template - requires (std::is_convertible_v) - constexpr basic_string(const Type& t, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - auto sv = sview_type(t); - PLUGIFY_ASSERT(pos <= sv.length(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - auto ssv = sv.substr(pos, count); - auto len = ssv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(ssv.data(), len); + template + constexpr basic_string& append(ForwardIterator first, ForwardIterator last) { + size_type sz = size(); + size_type cap = capacity(); + size_type n = static_cast(std::distance(first, last)); + if (n == 0) { + return *this; + } + + if (string_is_trivial_iterator_v && !addr_in_range(*first)) { + if (cap - sz < n) { + grow_by_without_replace(cap, sz + n - cap, sz, sz, 0); + } + annotate_increase(n); + auto end = copy_non_overlapping_range(first, last, std::to_address(get_pointer() + sz)); + traits_type::assign(*end, value_type()); + set_size(sz + n); + return *this; + } else { + const basic_string temp(first, last, _alloc); + return append(temp.data(), temp.size()); + } } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string(const Type& t, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - sview_type sv(t); - auto len = sv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(sv.data(), len); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& append_range(Range&& range) { + insert_range(end(), std::forward(range)); + return *this; } +#endif - constexpr basic_string(basic_string&& str, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : basic_string(std::move(str), allocator) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - erase(pos, count); + constexpr basic_string& append(std::initializer_list il) { + return append(il.begin(), il.size()); } - constexpr basic_string(basic_string&& str, size_type pos, const Allocator& allocator = Allocator()) - : basic_string(std::move(str), pos, npos, allocator) {} + constexpr void push_back(value_type c); + constexpr void pop_back(); -#if __cplusplus > 202002L - basic_string(std::nullptr_t) = delete; -#endif + constexpr reference front() noexcept { + PLUGIFY_ASSERT(!empty(), "string::front(): string is empty"); + return *get_pointer(); + } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string(std::from_range_t, Range&& range, const Allocator& allocator = Allocator()) - : basic_string(std::ranges::begin(range), std::ranges::end(range), allocator) {} -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + constexpr const_reference front() const noexcept { + PLUGIFY_ASSERT(!empty(), "string::front(): string is empty"); + return *data(); + } - constexpr ~basic_string() { - deallocate(); + constexpr reference back() noexcept { + PLUGIFY_ASSERT(!empty(), "string::back(): string is empty"); + return *(get_pointer() + size() - 1); } - constexpr basic_string& operator=(const basic_string& str) { - return assign(str); + constexpr const_reference back() const noexcept { + PLUGIFY_ASSERT(!empty(), "string::back(): string is empty"); + return *(data() + size() - 1); } - constexpr basic_string& operator=(basic_string&& str) noexcept( - allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value) { - return assign(std::move(str)); + template T> + constexpr basic_string& assign(const T& t) { + self_view sv = t; + return assign(sv.data(), sv.size()); } - constexpr basic_string& operator=(const value_type* str) { - return assign(str, Traits::length(str)); + constexpr void move_assign(basic_string&& str, size_type pos, size_type len) { + // Pilfer the allocation from str. + PLUGIFY_ASSERT(_alloc == str._alloc, "move_assign called with wrong allocator"); + size_type old_sz = str.size(); + if (!str.is_long()) { + str.annotate_delete(); + } + _rep = str._rep; + str._rep = rep(); + str.annotate_new(0); + + Traits::move(data(), data() + pos, len); + set_size(len); + Traits::assign(data()[len], value_type()); + + if (!is_long()) { + annotate_new(len); + } else if (old_sz > len) { + annotate_shrink(old_sz); + } } - constexpr basic_string& operator=(value_type ch) { - return assign(std::addressof(ch), 1); + constexpr basic_string& assign(const basic_string& str) { + return *this = str; } - constexpr basic_string& operator=(std::initializer_list list) { - return assign(list.begin(), list.size()); + constexpr basic_string& + assign(basic_string&& str) noexcept(alloc_traits::propagate_on_container_move_assignment::value + ) { + *this = std::move(str); + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& operator=(const Type& t) { - sview_type sv(t); - return assign(sv); + constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); + + template T> + constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos) { + self_view sv = t; + size_type sz = sv.size(); + if (pos > sz) { + throw_out_of_range(); + } + return assign(sv.data() + pos, std::min(n, sz - pos)); } -#if __cplusplus > 202002L - constexpr basic_string& operator=(std::nullptr_t) = delete; -#endif + constexpr basic_string& assign(const value_type* s, size_type n); + constexpr basic_string& assign(const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& assign(size_type n, value_type c); - constexpr basic_string& assign(size_type count, value_type ch) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(ch, count); + template + constexpr basic_string& assign(InputIterator first, InputIterator last) { + assign_with_sentinel(first, last); return *this; } - constexpr basic_string& assign(const basic_string& str, size_type pos, size_type count = npos) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::assign(): pos out of range", std::out_of_range); - internal_assign(str.data(), std::min(count, str.size() - pos)); + template + constexpr basic_string& assign(ForwardIterator first, ForwardIterator last) { + if (string_is_trivial_iterator_v) { + size_type n = static_cast(std::distance(first, last)); + assign_trivial(first, last, n); + } else { + assign_with_sentinel(first, last); + } + return *this; } - constexpr basic_string& assign(const basic_string& str) { - if (this == &str) [[unlikely]] - return *this; +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& assign_range(Range&& range) { + if constexpr (string_is_trivial_iterator_v> + && (std::ranges::forward_range || std::ranges::sized_range) ) { + size_type n = static_cast(std::ranges::distance(range)); + assign_trivial(std::ranges::begin(range), std::ranges::end(range), n); - if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != str.get_allocator()) { - deallocate(); - short_init(); - } - } - _allocator = str._allocator; + } else { + assign_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } - internal_assign(str.data(), str.size()); return *this; } +#endif - constexpr basic_string& assign(basic_string&& str) noexcept( - allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value) { - if (this == &str) [[unlikely]] - return *this; + constexpr basic_string& assign(std::initializer_list il) { + return assign(il.begin(), il.size()); + } - if constexpr (allocator_traits::propagate_on_container_move_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != str.get_allocator()) { - deallocate(); - short_init(); - } - } - _allocator = std::move(str._allocator); + constexpr basic_string& insert(size_type pos1, const basic_string& str) { + return insert(pos1, str.data(), str.size()); + } + + template T> + constexpr basic_string& insert(size_type pos1, const T& t) { + self_view sv = t; + return insert(pos1, sv.data(), sv.size()); + } + + template T> + constexpr basic_string& + insert(size_type pos1, const T& t, size_type pos2, size_type n = npos) { + self_view sv = t; + size_type str_sz = sv.size(); + if (pos2 > str_sz) { + throw_out_of_range(); } + return insert(pos1, sv.data() + pos2, std::min(n, str_sz - pos2)); + } + + constexpr basic_string& + insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos); + constexpr basic_string& insert(size_type pos, const value_type* s, size_type n); + constexpr basic_string& insert(size_type pos, const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& insert(size_type pos, size_type n, value_type c); + constexpr iterator insert(const_iterator pos, value_type c); + +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr iterator insert_range(const_iterator position, Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + return insert_with_size(position, std::ranges::begin(range), std::ranges::end(range), n); - if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) { - deallocate(); - short_init(); - std::swap(_storage, str._storage); } else { - if (get_allocator() == str.get_allocator()) { - deallocate(); - short_init(); - std::swap(_storage, str._storage); - } else { - internal_assign(str.data(), str.size()); - } + basic_string temp(std::from_range, std::forward(range), _alloc); + return insert(position, temp.data(), temp.data() + temp.size()); } + } +#endif - return *this; + constexpr iterator insert(const_iterator pos, size_type n, value_type c) { + difference_type p = pos - begin(); + insert(static_cast(p), n, c); + return begin() + p; } - constexpr basic_string& assign(const value_type* str, size_type count) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(str, count); - return *this; + template + constexpr iterator insert(const_iterator pos, InputIterator first, InputIterator last) { + const basic_string temp(first, last, _alloc); + return insert(pos, temp.data(), temp.data() + temp.size()); } - constexpr basic_string& assign(const value_type* str) { - return assign(str, Traits::length(str)); + template + constexpr iterator insert(const_iterator pos, ForwardIterator first, ForwardIterator last) { + auto n = static_cast(std::distance(first, last)); + return insert_with_size(pos, first, last, n); } - template - constexpr basic_string& assign(InputIterator first, InputIterator last) { - if constexpr (std::contiguous_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(first), len); - } else { - if constexpr (std::random_access_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - reserve(len); - } - for (auto it = first; it != last; ++it) { - push_back(*it); - } - } - return *this; + constexpr iterator insert(const_iterator pos, std::initializer_list il) { + return insert(pos, il.begin(), il.end()); } - constexpr basic_string& assign(std::initializer_list list) { - auto len = list.size(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(list.begin()), len); - return *this; + constexpr basic_string& erase(size_type pos = 0, size_type n = npos); + constexpr iterator erase(const_iterator pos); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str) { + return replace(pos1, n1, str.data(), str.size()); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& assign(const Type& t) { - sview_type sv(t); - return assign(sv.data(), sv.length()); + template T> + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t) { + self_view sv = t; + return replace(pos1, n1, sv.data(), sv.size()); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& assign(const Type& t, size_type pos, size_type count = npos) { - auto sv = sview_type(t).substr(pos, count); - auto len = sv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - return assign(sv.data(), len); + constexpr basic_string& + replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos); + + template T> + constexpr basic_string& + replace(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) { + self_view sv = t; + size_type str_sz = sv.size(); + if (pos2 > str_sz) { + throw_out_of_range(); + } + return replace(pos1, n1, sv.data() + pos2, std::min(n2, str_sz - pos2)); } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string& assign_range(Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(str.size() <= max_size(), "plg::basic_string::assign_range(): resulted string size would exceed max_size()", std::length_error); - return assign(std::move(str)); + constexpr basic_string& + replace(size_type pos, size_type n1, const value_type* s, size_type n2); + constexpr basic_string& + replace(size_type pos, size_type n1, const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); + + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, const basic_string& str) { + return replace( + static_cast(i1 - begin()), + static_cast(i2 - i1), + str.data(), + str.size() + ); } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr allocator_type get_allocator() const noexcept { - return _allocator; + template T> + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t) { + self_view sv = t; + return replace(i1 - begin(), i2 - i1, sv); } - constexpr reference operator[](size_type pos) { - return data()[pos]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), s, n); } - constexpr const_reference operator[](size_type pos) const { - return data()[pos]; + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), s); } - constexpr reference at(size_type pos) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::at(): pos out of range", std::out_of_range); - return data()[pos]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, size_type n, value_type c) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), n, c); } - constexpr const_reference at(size_type pos) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::at(): pos out of range", std::out_of_range); - return data()[pos]; + template + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2) { + const basic_string temp(j1, j2, _alloc); + return replace(i1, i2, temp); } - constexpr reference front() { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::front(): vector is empty", std::length_error); - return data()[0]; +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& + replace_with_range(const_iterator i1, const_iterator i2, Range&& range) { + basic_string temp(std::from_range, std::forward(range), _alloc); + return replace(i1, i2, temp); } +#endif - constexpr const_reference front() const { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::front(): vector is empty", std::length_error); - return data()[0]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, std::initializer_list il) { + return replace(i1, i2, il.begin(), il.end()); } - constexpr reference back() { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::back(): vector is empty", std::length_error); - return data()[size() - 1]; + constexpr size_type copy(value_type* s, size_type n, size_type pos = 0) const; + + constexpr basic_string substr(size_type pos = 0, size_type n = npos) const& { + return basic_string(*this, pos, n); } - constexpr const_reference back() const { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::back(): vector is empty", std::length_error); - return data()[size() - 1]; + constexpr basic_string substr(size_type pos = 0, size_type n = npos) && { + return basic_string(std::move(*this), pos, n); + } + + constexpr void swap(basic_string& str) noexcept; + + // [string.ops] + // ------------ + + constexpr const value_type* c_str() const noexcept { + return data(); } constexpr const value_type* data() const noexcept { - return is_long() ? get_long_data() : get_short_data(); + return std::to_address(get_pointer()); } constexpr value_type* data() noexcept { - return is_long() ? get_long_data() : get_short_data(); + return std::to_address(get_pointer()); } - constexpr const value_type* c_str() const noexcept { - return data(); + constexpr allocator_type get_allocator() const noexcept { + return _alloc; } - constexpr operator sview_type() const noexcept { - return view(); + // find + + constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find(str.data(), pos, str.size()); } - constexpr iterator begin() noexcept { - return data(); + template T> + constexpr size_type find(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find(sv.data(), pos, sv.size()); } - constexpr const_iterator begin() const noexcept { - return data(); + constexpr size_type find(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find(): received nullptr"); + return operator self_view().find(s, pos, n); } - constexpr const_iterator cbegin() const noexcept { - return data(); + constexpr size_type + find(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find(): received nullptr"); + return operator self_view().find(s, pos, traits_type::length(s)); } - constexpr iterator end() noexcept { - return data() + size(); + constexpr size_type find(value_type c, size_type pos = 0) const noexcept { + return operator self_view().find(c, pos); } - constexpr const_iterator end() const noexcept { - return data() + size(); + // rfind + + constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().rfind(str.data(), pos, str.size()); } - constexpr const_iterator cend() const noexcept { - return data() + size(); + template T> + constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().rfind(sv.data(), pos, sv.size()); } - constexpr reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); + constexpr size_type rfind(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::rfind(): received nullptr"); + return operator self_view().rfind(s, pos, n); } - constexpr const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); + constexpr size_type + rfind(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::rfind(): received nullptr"); + return operator self_view().rfind(s, pos, traits_type::length(s)); } - constexpr const_reverse_iterator crbegin() const noexcept { - return const_reverse_iterator(cend()); + constexpr size_type rfind(value_type c, size_type pos = npos) const noexcept { + return operator self_view().rfind(c, pos); } - constexpr reverse_iterator rend() noexcept { - return reverse_iterator(begin()); + // find_first_of + + constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find_first_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find_first_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_first_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_first_of(): received nullptr"); + return operator self_view().find_first_of(s, pos, n); + } + + constexpr size_type + find_first_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_first_of(): received nullptr"); + return operator self_view().find_first_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_first_of(value_type c, size_type pos = 0) const noexcept { + return find(c, pos); + } + + // find_last_of + + constexpr size_type + find_last_of(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().find_last_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_last_of(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().find_last_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_last_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_last_of(): received nullptr"); + return operator self_view().find_last_of(s, pos, n); + } + + constexpr size_type + find_last_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_last_of(): received nullptr"); + return operator self_view().find_last_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_last_of(value_type c, size_type pos = npos) const noexcept { + return rfind(c, pos); + } + + // find_first_not_of + + constexpr size_type + find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find_first_not_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find_first_not_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_first_not_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_first_not_of(): received nullptr"); + return operator self_view().find_first_not_of(s, pos, n); + } + + constexpr size_type + find_first_not_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_first_not_of(): received nullptr"); + return operator self_view().find_first_not_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept { + return operator self_view().find_first_not_of(c, pos); + } + + // find_last_not_of + + constexpr size_type + find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().find_last_not_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().find_last_not_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_last_not_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_last_not_of(): received nullptr"); + return operator self_view().find_last_not_of(s, pos, n); + } + + constexpr size_type + find_last_not_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_last_not_of(): received nullptr"); + return operator self_view().find_last_not_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept { + return operator self_view().find_last_not_of(c, pos); + } + + // compare + + constexpr int compare(const basic_string& str) const noexcept { + return compare(self_view(str)); + } + + template T> + constexpr int compare(const T& t) const noexcept { + self_view sv = t; + size_t lhs_sz = size(); + size_t rhs_sz = sv.size(); + int result = traits_type::compare(data(), sv.data(), std::min(lhs_sz, rhs_sz)); + if (result != 0) { + return result; + } + if (lhs_sz < rhs_sz) { + return -1; + } + if (lhs_sz > rhs_sz) { + return 1; + } + return 0; + } + + template T> + constexpr int compare(size_type pos1, size_type n1, const T& t) const { + self_view sv = t; + return compare(pos1, n1, sv.data(), sv.size()); + } + + constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const { + return compare(pos1, n1, str.data(), str.size()); + } + + constexpr int compare( + size_type pos1, + size_type n1, + const basic_string& str, + size_type pos2, + size_type n2 = npos + ) const { + return compare(pos1, n1, self_view(str), pos2, n2); + } + + template T> + inline constexpr int + compare(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) const { + self_view sv = t; + return self_view(*this).substr(pos1, n1).compare(sv.substr(pos2, n2)); + } + + constexpr int compare(const value_type* PLUGIFY_NO_NULL s) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::compare(): received nullptr"); + return compare(0, npos, s, traits_type::length(s)); + } + + constexpr int + compare(size_type pos1, size_type n1, const value_type* PLUGIFY_NO_NULL s) const { + PLUGIFY_ASSERT(s != nullptr, "string::compare(): received nullptr"); + return compare(pos1, n1, s, traits_type::length(s)); + } + + constexpr int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; + + // starts_with + + constexpr bool starts_with(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).starts_with(sv); + } + + constexpr bool starts_with(value_type c) const noexcept { + return !empty() && Traits::eq(front(), c); + } + + constexpr bool starts_with(const value_type* PLUGIFY_NO_NULL s) const noexcept { + return starts_with(self_view(s)); + } + + // ends_with + + constexpr bool ends_with(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).ends_with(sv); + } + + constexpr bool ends_with(value_type c) const noexcept { + return !empty() && Traits::eq(back(), c); + } + + constexpr bool ends_with(const value_type* PLUGIFY_NO_NULL s) const noexcept { + return ends_with(self_view(s)); + } + + // contains + + constexpr bool contains(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).contains(sv); + } + + constexpr bool contains(value_type c) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).contains(c); + } + + constexpr bool contains(const value_type* PLUGIFY_NO_NULL s) const { + return self_view(typename self_view::assume_valid(), data(), size()).contains(s); + } + + [[nodiscard]] constexpr bool invariants() const; + + private: + [[nodiscard]] constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS bool is_long() const noexcept { + if (std::is_constant_evaluated() && __builtin_constant_p(_rep.l._is_long)) { + return _rep.l._is_long; + } + return _rep.s._is_long; + } + + static constexpr bool fits_in_sso(size_type sz) { + return sz < min_cap; + } + + template + constexpr void assign_trivial(Iterator first, Sentinel last, size_type n); + + template + constexpr void assign_with_sentinel(Iterator first, Sentinel last); + + // Copy [first, last) into [dest, dest + (last - first)). Assumes that the ranges don't + // overlap. + template + static constexpr value_type* + copy_non_overlapping_range(ForwardIter first, Sent last, value_type* dest) { + if constexpr (std::contiguous_iterator + && std::is_same_v> + && std::is_same_v) { + PLUGIFY_ASSERT( + !is_overlapping_range(std::to_address(first), std::to_address(last), dest), + "copy_non_overlapping_range called with an overlapping range!" + ); + traits_type::copy(dest, std::to_address(first), last - first); + return dest + (last - first); + } else { + for (; first != last; ++first) { + traits_type::assign(*dest++, *first); + } + return dest; + } + } + + template + constexpr iterator + insert_from_safe_copy(size_type n, size_type ip, ForwardIterator first, Sentinel last) { + size_type sz = size(); + size_type cap = capacity(); + value_type* p; + if (cap - sz >= n) { + annotate_increase(n); + p = std::to_address(get_pointer()); + size_type n_move = sz - ip; + if (n_move != 0) { + traits_type::move(p + ip + n, p + ip, n_move); + } + } else { + grow_by_without_replace(cap, sz + n - cap, sz, ip, 0, n); + p = std::to_address(get_long_pointer()); + } + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + copy_non_overlapping_range(std::move(first), std::move(last), p + ip); + + return begin() + ip; + } + + template + constexpr iterator + insert_with_size(const_iterator pos, Iterator first, Sentinel last, size_type n); + + // internal buffer accessors + // ------------------------- + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void set_short_size(size_type s) noexcept { + PLUGIFY_ASSERT( + s < min_cap, + "s should never be greater than or equal to the short string capacity" + ); + _rep.s._spare_size = (min_cap - 1) - s; + _rep.s._is_long = false; + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS size_type get_short_size() const noexcept { + PLUGIFY_ASSERT(!_rep.s._is_long, "String has to be short when trying to get the short size"); + return (min_cap - 1) - _rep.s._spare_size; + } + + constexpr void set_long_size(size_type s) noexcept { + _rep.l._size = s; + } + + constexpr size_type get_long_size() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long size"); + return _rep.l._size; + } + + constexpr void set_size(size_type s) noexcept { + if (is_long()) { + set_long_size(s); + } else { + set_short_size(s); + } } - constexpr const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); + constexpr size_type get_long_cap() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long capacity"); + return _rep.l._cap * endian_factor; + } + + constexpr pointer get_long_pointer() noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long pointer"); + return PLUGIFY_ASAN_VOLATILE_WRAPPER(_rep.l._data); + } + + constexpr const_pointer get_long_pointer() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long pointer"); + return PLUGIFY_ASAN_VOLATILE_WRAPPER(_rep.l._data); + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS pointer get_short_pointer() noexcept { + return PLUGIFY_ASAN_VOLATILE_WRAPPER( + std::pointer_traits::pointer_to(_rep.s._data[0]) + ); + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS const_pointer get_short_pointer() const noexcept { + return PLUGIFY_ASAN_VOLATILE_WRAPPER( + std::pointer_traits::pointer_to(_rep.s._data[0]) + ); + } + + constexpr pointer get_pointer() noexcept { + return is_long() ? get_long_pointer() : get_short_pointer(); + } + + constexpr const_pointer get_pointer() const noexcept { + return is_long() ? get_long_pointer() : get_short_pointer(); + } + + // Internal buffer management + // -------------------------- + // + // These functions are only responsible for managing the buffer itself, not the value inside + // the buffer. As such, none of these facilities ensure that there is a null terminator at + // `data()[size()]`. + + // Allocate a buffer of capacity size with alloc and return it + static constexpr long_ allocate_long_buffer(Allocator& alloc, size_type capacity) { + auto buffer = allocate_at_least(alloc, recommend(capacity) + 1); + + if (std::is_constant_evaluated()) { + for (size_type i = 0; i != buffer.count; ++i) { + std::construct_at(std::addressof(buffer.ptr[i])); + } + } + + return long_(buffer, capacity); + } + + // Deallocate the long buffer if it exists and clear the short buffer so we are an empty + // string + constexpr void reset_internal_buffer() { + annotate_delete(); + if (is_long()) { + alloc_traits::deallocate(_alloc, get_long_pointer(), get_long_cap()); + } + _rep.s = short_(); + } + + // Replace the current buffer with alloc; the first size elements constitute a string + constexpr void replace_internal_buffer(long_ alloc) { + reset_internal_buffer(); + _rep.l = alloc; + } + + // Initialize the internal buffer to hold size elements + // The elements and null terminator have to be set by the caller + constexpr pointer init_internal_buffer(size_type size) { + if (std::is_constant_evaluated()) { + _rep = rep(); + } + + if (size > max_size()) { + throw_length_error(); + } + + if (fits_in_sso(size)) { + set_short_size(size); + annotate_new(size); + return get_short_pointer(); + } else { + _rep.l = allocate_long_buffer(_alloc, size); + annotate_new(size); + return get_long_pointer(); + } + } + + // ASan annotation helpers + // ----------------------- + + // The following functions are no-ops outside of AddressSanitizer mode. + constexpr void annotate_contiguous_container( + const void* old_mid, + const void* new_mid + ) const { + if (!is_long()) { + return; + } + + plg::annotate_contiguous_container( + data(), + data() + capacity() + 1, + old_mid, + new_mid + ); } - constexpr const_reverse_iterator crend() const noexcept { - return const_reverse_iterator(cbegin()); + constexpr void annotate_new(size_type current_size) const noexcept { + annotate_contiguous_container(data() + capacity() + 1, data() + current_size + 1); } - constexpr bool empty() const noexcept { - return size() == 0; + constexpr void annotate_delete() const noexcept { + annotate_contiguous_container(data() + size() + 1, data() + capacity() + 1); } - constexpr size_type size() const noexcept { - return is_long() ? get_long_size() : get_short_size(); + constexpr void annotate_increase(size_type n) const noexcept { + annotate_contiguous_container(data() + size() + 1, data() + size() + 1 + n); } - constexpr size_type length() const noexcept { - return size(); + constexpr void annotate_shrink(size_type old_size) const noexcept { + annotate_contiguous_container(data() + old_size + 1, data() + size() + 1); } - constexpr size_type max_size() const noexcept { - // const size_type alignment = 16; - // size_type m = allocator_traits::max_size(_allocator); - // if (m <= std::numeric_limits::max() / 2) - // return m - alignment; - // else - //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; - return (allocator_traits::max_size(_allocator) - 1) / 2; - } + // Disable ASan annotations and enable them again when going out of scope. It is assumed + // that the string is in a valid state at that point, so `size()` can be called safely. + struct [[nodiscard]] annotation_guard { + annotation_guard(const annotation_guard&) = delete; + annotation_guard& operator=(const annotation_guard&) = delete; - constexpr size_type capacity() const noexcept { - return is_long() ? get_long_cap() : min_cap; - } + constexpr annotation_guard(basic_string& str) + : str(str) { + str.annotate_delete(); + } - constexpr void reserve(size_type cap) { - PLUGIFY_ASSERT(cap <= max_size(), "plg::basic_string::reserve(): allocated memory size would exceed max_size()", std::length_error); - if (cap <= capacity()) - return; + constexpr ~annotation_guard() { + str.annotate_new(str.size()); + } - auto new_cap = std::max(cap, size()); - if (new_cap == capacity()) - return; + basic_string& str; + }; - grow_to(new_cap); + template + static constexpr size_type align_it(size_type s) noexcept { + return (s + (a - 1)) & ~(a - 1); } - void reserve() { - shrink_to_fit(); - } + enum { alignment = 8 }; - constexpr void shrink_to_fit() { - if (is_long() == false) - return; + static constexpr size_type recommend(size_type s) noexcept { + if (s < min_cap) { + return min_cap - 1; + } + const size_type boundary = sizeof(value_type) < alignment ? alignment / sizeof(value_type) : endian_factor; + size_type guess = align_it(s + 1) - 1; + if (guess == min_cap) { + guess += endian_factor; + } - reallocate(size(), true); + PLUGIFY_ASSERT(guess >= s, "recommendation is below the requested size"); + return guess; + } + + inline constexpr void init(const value_type* s, size_type sz); + inline constexpr void init(size_type n, value_type c); + + // Slow path for the (inlined) copy constructor for 'long' strings. + // Always externally instantiated and not inlined. + // Requires that s is zero terminated. + // The main reason for this function to exist is because for unstable, we + // want to allow inlining of the copy constructor. However, we don't want + // to call the init() functions as those are marked as inline which may + // result in over-aggressive inlining by the compiler, where our aim is + // to only inline the fast path code directly in the ctor. + PLUGIFY_NOINLINE constexpr void init_copy_ctor_external(const value_type* s, size_type sz); + + template + inline constexpr void init(InputIterator first, InputIterator last); + + template + inline constexpr void init(ForwardIterator first, ForwardIterator last); + + template + constexpr void init_with_sentinel(InputIterator first, Sentinel last); + template + constexpr void init_with_size(InputIterator first, Sentinel last, size_type sz); + + constexpr void grow_by_without_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add = 0 + ); + constexpr void grow_by_and_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add, + const value_type* p_new_stuff + ); + + // assign_no_alias is invoked for assignment operations where we + // have proof that the input does not alias the current instance. + // For example, operator=(basic_string) performs a 'self' check. + template + PLUGIFY_NOINLINE constexpr basic_string& assign_no_alias(const value_type* s, size_type n); + + constexpr void erase_to_end(size_type pos) { + PLUGIFY_ASSERT( + pos <= capacity(), + "Trying to erase at position outside the strings capacity!" + ); + null_terminate_at(std::to_address(get_pointer()), pos); + } + + // erase_external_with_move is invoked for erase() invocations where + // `n ~= npos`, likely requiring memory moves on the string data. + PLUGIFY_NOINLINE constexpr void erase_external_with_move(size_type pos, size_type n); + + constexpr void copy_assign_alloc(const basic_string& str) { + copy_assign_alloc( + str, + std::integral_constant() + ); + } + + constexpr void copy_assign_alloc(const basic_string& str, std::true_type) { + if (_alloc == str._alloc) { + _alloc = str._alloc; + } else { + if (!str.is_long()) { + reset_internal_buffer(); + _alloc = str._alloc; + } else { + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + auto alloc = str._alloc; + replace_internal_buffer(allocate_long_buffer(alloc, str.size())); + _alloc = std::move(alloc); + } + } } - constexpr void clear() noexcept { - set_size(0); + constexpr void copy_assign_alloc(const basic_string&, std::false_type) noexcept { } - constexpr basic_string& insert(size_type pos, size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - insert(std::next(cbegin(), pos), count, ch); - return *this; + constexpr void + move_assign(basic_string& str, std::false_type) noexcept(alloc_traits::is_always_equal::value); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void + move_assign(basic_string& str, std::true_type) noexcept; + + constexpr void move_assign_alloc( + basic_string& str + ) noexcept(!alloc_traits::propagate_on_container_move_assignment::value || std::is_nothrow_move_assignable_v) { + move_assign_alloc( + str, + std::integral_constant() + ); } - constexpr basic_string& insert(size_type pos, const value_type* str) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - auto len = Traits::length(str); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, str, len); - return *this; + constexpr void move_assign_alloc( + basic_string& c, + std::true_type + ) noexcept(std::is_nothrow_move_assignable_v) { + _alloc = std::move(c._alloc); } - constexpr basic_string& insert(size_type pos, const value_type* str, size_type count) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - internal_insert(pos, str, count); - return *this; + constexpr void move_assign_alloc(basic_string&, std::false_type) noexcept { } - constexpr basic_string& insert(size_type pos, const basic_string& str) { - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - internal_insert(pos, const_pointer(str.data()), str.size()); + PLUGIFY_NOINLINE constexpr basic_string& assign_external(const value_type* s); + PLUGIFY_NOINLINE constexpr basic_string& assign_external(const value_type* s, size_type n); + + // Assigns the value in s, guaranteed to be n < min_cap in length. + inline constexpr basic_string& assign_short(const value_type* s, size_type n) { + size_type old_size = size(); + if (n > old_size) { + annotate_increase(n - old_size); + } + pointer p; + if (is_long()) { + set_long_size(n); + p = get_long_pointer(); + } else { + set_short_size(n); + p = get_short_pointer(); + } + traits_type::move(std::to_address(p), s, n); + traits_type::assign(p[n], value_type()); + if (old_size > n) { + annotate_shrink(old_size); + } return *this; } - constexpr basic_string& insert(size_type pos, const basic_string& str, size_type pos_str, size_type count = npos) { - PLUGIFY_ASSERT(pos <= size() && pos_str <= str.size(), "plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range); - count = std::min(count, str.length() - pos_str); - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - return insert(pos, str.data() + pos_str, count); + constexpr basic_string& null_terminate_at(value_type* p, size_type newsz) { + size_type old_size = size(); + if (newsz > old_size) { + annotate_increase(newsz - old_size); + } + set_size(newsz); + traits_type::assign(p[newsz], value_type()); + if (old_size > newsz) { + annotate_shrink(old_size); + } + return *this; } - constexpr iterator insert(const_iterator pos, value_type ch) { - return insert(pos, 1, ch); + template + constexpr bool addr_in_range(const T& v) const { + return is_pointer_in_range(data(), data() + size() + 1, std::addressof(v)); } - constexpr iterator insert(const_iterator pos, size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - auto spos = std::distance(cbegin(), pos); - internal_insert(spos, ch, count); - return std::next(begin(), spos); + [[noreturn]] static void throw_length_error() { + PLUGIFY_THROW("constructed string size would exceed max_size()", std::length_error); } - template - constexpr iterator insert(const_iterator pos, InputIterator first, InputIterator last) { - auto spos = std::distance(cbegin(), pos); - auto len = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(spos, const_pointer(first), len); - return std::next(begin(), spos); - } - - constexpr iterator insert(const_iterator pos, std::initializer_list list) { - PLUGIFY_ASSERT(size() + list.size() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - auto spos = std::distance(cbegin(), pos); - internal_insert(spos, const_pointer(list.begin()), list.size()); - return std::next(begin(), spos); - } - - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& insert(size_type pos, const Type& t) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - sview_type sv(t); - PLUGIFY_ASSERT(size() + sv.length() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, const_pointer(sv.data()), sv.length()); - return *this; + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& insert(size_type pos, const Type& t, size_type pos_str, size_type count = npos) { - auto sv = sview_type(t); - PLUGIFY_ASSERT(pos <= size() && pos_str <= sv.length(), "plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range); - auto ssv = sv.substr(pos_str, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, const_pointer(ssv.data()), ssv.length()); - return *this; - } + friend constexpr basic_string + concatenate_strings<>(const Allocator&, std::type_identity_t, std::type_identity_t); -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr iterator insert_range(const_iterator pos, Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error); - return insert(pos - begin(), str); - } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + friend inline constexpr bool + operator==(const basic_string&, const CharT2*) noexcept; + }; - constexpr basic_string& erase(size_type pos = 0, size_type count = npos) { - auto sz = size(); - auto buffer = data(); + template < + std::input_iterator InputIterator, + class CharT = std::iter_value_t, + is_allocator Allocator = allocator> + basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string, Allocator>; + + template > + explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) + -> basic_string; + + template < + class CharT, + is_char_traits Traits, + is_allocator Allocator = allocator, + class Sz = typename std::allocator_traits::size_type> + basic_string(std::basic_string_view, Sz, Sz, const Allocator& = Allocator()) + -> basic_string; + +#if PLUGIFY_HAS_CXX23 + template < + std::ranges::input_range Range, + is_allocator Allocator = std::allocator>> + basic_string(std::from_range_t, Range&&, Allocator = Allocator()) -> basic_string< + std::ranges::range_value_t, + std::char_traits>, + Allocator>; +#endif - PLUGIFY_ASSERT(pos <= sz, "plg::basic_string::erase(): pos out of range", std::out_of_range); + template + constexpr void basic_string::init(const value_type* s, size_type sz) { + pointer p = init_internal_buffer(sz); + traits_type::copy(std::to_address(p), s, sz); + traits_type::assign(p[sz], value_type()); + } - count = std::min(count, sz - pos); + template + PLUGIFY_NOINLINE constexpr void + basic_string::init_copy_ctor_external(const value_type* s, size_type sz) { + pointer p = init_internal_buffer(sz); + traits_type::copy(std::to_address(p), s, sz + 1); + } - auto left = sz - (pos + count); - if (left != 0) - Traits::move(buffer + pos, buffer + pos + count, left); + template + constexpr void basic_string::init(size_type n, value_type c) { + pointer p = init_internal_buffer(n); + traits_type::assign(std::to_address(p), n, c); + traits_type::assign(p[n], value_type()); + } - auto new_size = pos + left; - set_size(new_size); - null_terminate(); + template + template + constexpr void + basic_string::init(InputIterator first, InputIterator last) { + init_with_sentinel(std::move(first), std::move(last)); + } - return *this; + template + template + constexpr void + basic_string::init_with_sentinel(InputIterator first, Sentinel last) { + _rep = rep(); + annotate_new(0); + +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + for (; first != last; ++first) { + push_back(*first); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + reset_internal_buffer(); + throw; } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr iterator erase(const_iterator position) { - auto pos = std::distance(cbegin(), position); - erase(pos, 1); - return begin() + pos; - } + template + template + constexpr void + basic_string::init(ForwardIterator first, ForwardIterator last) { + size_type sz = static_cast(std::distance(first, last)); + init_with_size(first, last, sz); + } - constexpr iterator erase(const_iterator first, const_iterator last) { - auto pos = std::distance(cbegin(), first); - auto len = std::distance(first, last); - erase(pos, len); - return begin() + pos; - } + template + template + constexpr void basic_string::init_with_size( + InputIterator first, + Sentinel last, + size_type sz + ) { + pointer p = init_internal_buffer(sz); + +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + auto end = copy_non_overlapping_range(std::move(first), std::move(last), std::to_address(p)); + traits_type::assign(*end, value_type()); +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + reset_internal_buffer(); + throw; + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr void push_back(value_type ch) { - PLUGIFY_ASSERT(size() + 1 <= max_size(), "plg::basic_string::push_back(): resulted string size would exceed max_size()", std::length_error); - append(1, ch); - } + template + constexpr void basic_string::grow_by_and_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add, + const value_type* p_new_stuff + ) { + size_type ms = max_size(); + if (delta_cap > ms - old_cap) { + throw_length_error(); + } + pointer old_p = get_pointer(); + size_type cap = old_cap < ms / 2 - alignment + ? recommend(std::max(old_cap + delta_cap, 2 * old_cap)) + : ms; + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + long_ buffer = allocate_long_buffer(_alloc, cap); + if (n_copy != 0) { + traits_type::copy(std::to_address(buffer._data), std::to_address(old_p), n_copy); + } + if (n_add != 0) { + traits_type::copy(std::to_address(buffer._data) + n_copy, p_new_stuff, n_add); + } + size_type sec_cp_sz = old_sz - n_del - n_copy; + if (sec_cp_sz != 0) { + traits_type::copy( + std::to_address(buffer._data) + n_copy + n_add, + std::to_address(old_p) + n_copy + n_del, + sec_cp_sz + ); + } + buffer._size = n_copy + n_add + sec_cp_sz; + traits_type::assign(buffer._data[buffer._size], value_type()); + replace_internal_buffer(buffer); + } - constexpr void pop_back() { - erase(end() - 1); - } + template + constexpr void basic_string::grow_by_without_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add + ) { + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + size_type ms = max_size(); + if (delta_cap > ms - old_cap) { + this->throw_length_error(); + } + pointer old_p = get_pointer(); + size_type cap = old_cap < ms / 2 - alignment + ? recommend(std::max(old_cap + delta_cap, 2 * old_cap)) + : ms; + long_ buffer = allocate_long_buffer(_alloc, cap); + if (n_copy != 0) { + traits_type::copy(std::to_address(buffer._data), std::to_address(old_p), n_copy); + } + size_type sec_cp_sz = old_sz - n_del - n_copy; + if (sec_cp_sz != 0) { + traits_type::copy( + std::to_address(buffer._data) + n_copy + n_add, + std::to_address(old_p) + n_copy + n_del, + sec_cp_sz + ); + } + + // This is -1 to make sure the caller sets the size properly, since old versions of this + // function didn't set the size at all. + buffer._size = npos; + replace_internal_buffer(buffer); + set_long_size(old_sz - n_del + n_add); + } - constexpr basic_string& append(size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ch, count); - return *this; - } + // assign - constexpr basic_string& append(const basic_string& str) { - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(str.data(), str.size()); + template + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_no_alias(const value_type* s, size_type n) { + const auto cap = is_short ? min_cap : get_long_cap(); + const auto size = is_short ? get_short_size() : get_long_size(); + if (n >= cap) { + grow_by_and_replace(cap - 1, n - cap + 1, size, 0, size, n, s); return *this; } - constexpr basic_string& append(const basic_string& str, size_type pos, size_type count = npos) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::append(): pos out of range", std::out_of_range); - auto ssv = sview_type(str).substr(pos, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ssv.data(), ssv.length()); - return *this; + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + pointer p; + if (is_short) { + p = get_short_pointer(); + set_short_size(n); + } else { + p = get_long_pointer(); + set_long_size(n); } + traits_type::copy(std::to_address(p), s, n); + traits_type::assign(p[n], value_type()); + return *this; + } - constexpr basic_string& append(const value_type* str, size_type count) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(str, count); + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_external(const value_type* s, size_type n) { + const auto cap = capacity(); + const auto sz = size(); + if (cap >= n) { + if (n > sz) { + annotate_increase(n - sz); + } + value_type* p = std::to_address(get_pointer()); + traits_type::move(p, s, n); + return null_terminate_at(p, n); + } else { + grow_by_and_replace(cap, n - cap, sz, 0, sz, n, s); return *this; } + } - constexpr basic_string& append(const value_type* str) { - auto len = Traits::length(str); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - return append(str, len); - } + template + constexpr basic_string& + basic_string::assign(const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::assign received nullptr"); + return (__builtin_constant_p(n) && fits_in_sso(n)) ? assign_short(s, n) + : assign_external(s, n); + } - template - constexpr basic_string& append(InputIterator first, InputIterator last) { - auto len = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(const_pointer(first), len); - return *this; - } + template + constexpr basic_string& + basic_string::assign(size_type n, value_type c) { + size_type cap = capacity(); + size_type old_size = size(); + if (cap < n) { + grow_by_without_replace(cap, n - cap, old_size, 0, old_size); + annotate_increase(n); + } else if (n > old_size) { + annotate_increase(n - old_size); + } + value_type* p = std::to_address(get_pointer()); + traits_type::assign(p, n, c); + return null_terminate_at(p, n); + } - constexpr basic_string& append(std::initializer_list list) { - PLUGIFY_ASSERT(size() + list.size() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(const_pointer(list.begin()), list.size()); - return *this; - } + template + constexpr basic_string& + basic_string::operator=(value_type c) { + size_type old_size = size(); + if (old_size == 0) { + annotate_increase(1); + } + pointer p; + if (is_long()) { + p = get_long_pointer(); + set_long_size(1); + } else { + p = get_short_pointer(); + set_short_size(1); + } + traits_type::assign(*p, c); + traits_type::assign(*++p, value_type()); + if (old_size > 1) { + annotate_shrink(old_size); + } + return *this; + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& append(const Type& t) { - sview_type sv(t); - PLUGIFY_ASSERT(size() + sv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(sv.data(), sv.size()); + template + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string& + basic_string::operator=(const basic_string& str) { + if (this == std::addressof(str)) { return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& append(const Type& t, size_type pos, size_type count = npos) { - sview_type sv(t); - PLUGIFY_ASSERT(pos <= sv.length(), "plg::basic_string::append(): pos out of range", std::out_of_range); - auto ssv = sv.substr(pos, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ssv.data(), ssv.length()); - return *this; - } + copy_assign_alloc(str); -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string& append_range(Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error); - return append(str); + if (is_long()) { + return assign_no_alias(str.data(), str.size()); } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr basic_string& operator+=(const basic_string& str) { - return append(str); + if (str.is_long()) { + return assign_no_alias(str.data(), str.size()); } - constexpr basic_string& operator+=(value_type ch) { - push_back(ch); - return *this; - } + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + _rep = str._rep; - constexpr basic_string& operator+=(const value_type* str) { - return append(str); - } + return *this; + } - constexpr basic_string& operator+=(std::initializer_list list) { - return append(list); + template + inline constexpr void + basic_string::move_assign(basic_string& str, std::false_type) noexcept( + alloc_traits::is_always_equal::value + ) { + if (_alloc != str._alloc) { + assign(str); + } else { + move_assign(str, std::true_type()); } + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& operator+=(const Type& t) { - return append(sview_type(t)); + template + inline constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void + basic_string::move_assign(basic_string& str, std::true_type) noexcept { + annotate_delete(); + if (is_long()) { + reset_internal_buffer(); + } + size_type str_old_size = str.size(); + bool str_was_short = !str.is_long(); + + move_assign_alloc(str); + _rep = str._rep; + str.set_short_size(0); + traits_type::assign(str.get_short_pointer()[0], value_type()); + + if (str_was_short && this != std::addressof(str)) { + str.annotate_shrink(str_old_size); + } else { + // ASan annotations: was long, so object memory is unpoisoned as new. + // Or is same as *this, and annotate_delete() was called. + str.annotate_new(0); + } + + // ASan annotations: Guard against `std::string s; s = std::move(s);` + // You can find more here: https://en.cppreference.com/w/cpp/utility/move + // Quote: "Unless otherwise specified, all standard library objects that have been moved + // from are placed in a "valid but unspecified state", meaning the object's class + // invariants hold (so functions without preconditions, such as the assignment operator, + // can be safely used on the object after it was moved from):" + // Quote: "v = std::move(v); // the value of v is unspecified" + if (!is_long() && std::addressof(str) != this) { + // If it is long string, delete was never called on original str's buffer. + annotate_new(get_short_size()); } + } - constexpr int compare(const basic_string& str) const noexcept { - return view().compare(str.view()); - } + template + template + constexpr void + basic_string::assign_with_sentinel(InputIterator first, Sentinel last) { + const basic_string temp(init_with_sentinel_tag(), std::move(first), std::move(last), _alloc); + assign(temp.data(), temp.size()); + } - constexpr int compare(size_type pos1, size_type count1, const basic_string& str) const { - return view().compare(pos1, count1, str.view()); + template + template + constexpr void + basic_string::assign_trivial(Iterator first, Sentinel last, size_type n) { + PLUGIFY_ASSERT( + string_is_trivial_iterator_v, + "The iterator type given to `assign_trivial` must be trivial" + ); + + size_type old_size = size(); + size_type cap = capacity(); + if (cap < n) { + // Unlike `append` functions, if the input range points into the string itself, there is + // no case that the input range could get invalidated by reallocation: + // 1. If the input range is a subset of the string itself, its size cannot exceed the + // capacity of the string, + // thus no reallocation would happen. + // 2. In the exotic case where the input range is the byte representation of the string + // itself, the string + // object itself stays valid even if reallocation happens. + size_type sz = size(); + grow_by_without_replace(cap, n - cap, sz, 0, sz); + annotate_increase(n); + } else if (n > old_size) { + annotate_increase(n - old_size); + } + pointer p = get_pointer(); + for (; first != last; ++p, (void) ++first) { + traits_type::assign(*p, *first); + } + traits_type::assign(*p, value_type()); + set_size(n); + if (n < old_size) { + annotate_shrink(old_size); } + } - constexpr int compare(size_type pos1, size_type count1, const basic_string& str, size_type pos2, size_type count2 = npos) const { - return view().compare(pos1, count1, str.view(), pos2, count2); + template + constexpr basic_string& + basic_string::assign(const basic_string& str, size_type pos, size_type n) { + size_type sz = str.size(); + if (pos > sz) { + this->throw_out_of_range(); } + return assign(str.data() + pos, std::min(n, sz - pos)); + } - constexpr int compare(const value_type* str) const { - return view().compare(str); - } + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_external(const value_type* s) { + return assign_external(s, traits_type::length(s)); + } - constexpr int compare(size_type pos1, size_type count1, const value_type* str) const { - return view().compare(pos1, count1, str); + template + constexpr basic_string& + basic_string::assign(const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::assign received nullptr"); + if (auto len = traits_type::length(s); __builtin_constant_p(len) && fits_in_sso(len)) { + return assign_short(s, len); } + return assign_external(s); + } - constexpr int compare(size_type pos1, size_type count1, const value_type* str, size_type count2) const { - return view().compare(pos1, count1, str, count2); - } + // append - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(const Type& t) const noexcept(noexcept(std::is_nothrow_convertible_v)) { - return view().compare(sview_type(t)); + template + constexpr basic_string& + basic_string::append(const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::append received nullptr"); + size_type cap = capacity(); + size_type sz = size(); + if (cap - sz < n) { + grow_by_and_replace(cap, sz + n - cap, sz, sz, 0, n, s); + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(size_type pos1, size_type count1, const Type& t) const { - return view().compare(pos1, count1, sview_type(t)); + if (n == 0) { + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(size_type pos1, size_type count1, const Type& t, size_type pos2, size_type count2 = npos) const { - return view().compare(pos1, count1, sview_type(t), pos2, count2); - } + annotate_increase(n); + value_type* p = std::to_address(get_pointer()); + traits_type::copy(p + sz, s, n); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr bool starts_with(sview_type sv) const noexcept { - return view().starts_with(sv); + template + constexpr basic_string& + basic_string::append(size_type n, value_type c) { + if (n == 0) { + return *this; } - constexpr bool starts_with(Char ch) const noexcept { - return view().starts_with(ch); + size_type cap = capacity(); + size_type sz = size(); + if (cap - sz < n) { + grow_by_without_replace(cap, sz + n - cap, sz, sz, 0); } + annotate_increase(n); + pointer p = get_pointer(); + traits_type::assign(std::to_address(p) + sz, n, c); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr bool starts_with(const Char* str) const { - return view().starts_with(str); - } + template + constexpr void basic_string::push_back(value_type c) { + bool is_short = !is_long(); + size_type cap; + size_type sz; + if (is_short) { + cap = min_cap - 1; + sz = get_short_size(); + } else { + cap = get_long_cap() - 1; + sz = get_long_size(); + } + if (sz == cap) { + grow_by_without_replace(cap, 1, sz, sz, 0); + is_short = false; // the string is always long after grow_by + } + annotate_increase(1); + pointer p; + if (is_short) { + p = get_short_pointer() + sz; + set_short_size(sz + 1); + } else { + p = get_long_pointer() + sz; + set_long_size(sz + 1); + } + traits_type::assign(*p, c); + traits_type::assign(*++p, value_type()); + } - constexpr bool ends_with(sview_type sv) const noexcept { - return view().ends_with(sv); + template + constexpr basic_string& + basic_string::append(const basic_string& str, size_type pos, size_type n) { + size_type sz = str.size(); + if (pos > sz) { + this->throw_out_of_range(); } + return append(str.data() + pos, std::min(n, sz - pos)); + } - constexpr bool ends_with(Char ch) const noexcept { - return view().ends_with(ch); - } + template + constexpr basic_string& + basic_string::append(const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::append received nullptr"); + return append(s, traits_type::length(s)); + } - constexpr bool ends_with(const Char* str) const { - return view().ends_with(str); - } + // insert - constexpr bool contains(sview_type sv) const noexcept { - return view().contains(sv); + template + constexpr basic_string& + basic_string::insert(size_type pos, const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::insert received nullptr"); + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } + size_type cap = capacity(); - constexpr bool contains(Char ch) const noexcept { - return view().contains(ch); + if (cap - sz < n) { + grow_by_and_replace(cap, sz + n - cap, sz, pos, 0, n, s); + return *this; } - constexpr bool contains(const Char* str) const { - return view().contains(str); + if (n == 0) { + return *this; } - constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - return replace(pos, count, str, 0, str.length()); + annotate_increase(n); + value_type* p = std::to_address(get_pointer()); + size_type n_move = sz - pos; + if (n_move != 0) { + if (is_pointer_in_range(p + pos, p + sz, s)) { + s += n; + } + traits_type::move(p + pos + n, p + pos, n_move); } + traits_type::move(p + pos, s, n); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const basic_string& str) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - return replace(pos, count, str, 0, str.length()); + template + constexpr basic_string& + basic_string::insert(size_type pos, size_type n, value_type c) { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } - constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2 = npos) { - PLUGIFY_ASSERT(pos <= size() && pos2 <= str.size(), "plg::basic_string::replace(): pos or pos_str out of range", std::out_of_range); - count2 = std::min(count2, str.length() - pos2); - auto ssv = sview_type(str).substr(pos2, count2); - return replace(pos, count, ssv.data(), ssv.length()); + if (n == 0) { + return *this; } - template - constexpr basic_string& replace(const_iterator first, const_iterator last, InputIterator first2, InputIterator last2) { - return replace(first, last, const_pointer(first2), std::distance(first2, last2)); - } + size_type cap = capacity(); + value_type* p; + if (cap - sz >= n) { + annotate_increase(n); + p = std::to_address(get_pointer()); + size_type n_move = sz - pos; + if (n_move != 0) { + traits_type::move(p + pos + n, p + pos, n_move); + } + } else { + grow_by_without_replace(cap, sz + n - cap, sz, pos, 0, n); + p = std::to_address(get_long_pointer()); + } + traits_type::assign(p + pos, n, c); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr basic_string& replace(size_type pos, size_type count, const value_type* str, size_type count2) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - count = std::min(count, length() - pos); - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - internal_replace(pos, const_pointer(str), count, count2); - return *this; + template + template + constexpr typename basic_string::iterator + basic_string::insert_with_size( + const_iterator pos, + Iterator first, + Sentinel last, + size_type n + ) { + size_type ip = static_cast(pos - begin()); + if (n == 0) { + return begin() + ip; + } + + if (string_is_trivial_iterator_v && !addr_in_range(*first)) { + return insert_from_safe_copy(n, ip, std::move(first), std::move(last)); + } else { + const basic_string temp(init_with_sentinel_tag(), std::move(first), std::move(last), _alloc); + return insert_from_safe_copy(n, ip, temp.begin(), temp.end()); } + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const value_type* str, size_type count2) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - return replace(pos, count, str, count2); - } + template + constexpr basic_string& basic_string::insert( + size_type pos1, + const basic_string& str, + size_type pos2, + size_type n + ) { + size_type str_sz = str.size(); + if (pos2 > str_sz) { + this->throw_out_of_range(); + } + return insert(pos1, str.data() + pos2, std::min(n, str_sz - pos2)); + } - constexpr basic_string& replace(size_type pos, size_type count, const value_type* str) { - return replace(pos, count, str, Traits::length(str)); - } + template + constexpr basic_string& + basic_string::insert(size_type pos, const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::insert received nullptr"); + return insert(pos, s, traits_type::length(s)); + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const value_type* str) { - return replace(first, last, str, Traits::length(str)); + template + constexpr typename basic_string::iterator + basic_string::insert(const_iterator pos, value_type c) { + size_type ip = static_cast(pos - begin()); + size_type sz = size(); + size_type cap = capacity(); + value_type* p; + if (cap == sz) { + grow_by_without_replace(cap, 1, sz, ip, 0, 1); + p = std::to_address(get_long_pointer()); + } else { + annotate_increase(1); + p = std::to_address(get_pointer()); + size_type n_move = sz - ip; + if (n_move != 0) { + traits_type::move(p + ip + 1, p + ip, n_move); + } } + traits_type::assign(p[ip], c); + traits_type::assign(p[++sz], value_type()); + set_size(sz); + return begin() + static_cast(ip); + } - constexpr basic_string& replace(size_type pos, size_type count, size_type count2, value_type ch) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - count = std::min(count, length() - pos); - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - internal_replace(pos, ch, count, count2); + // replace + + template + constexpr basic_string& + basic_string::replace( + size_type pos, + size_type n1, + const value_type* s, + size_type n2 + ) { + PLUGIFY_ASSERT(n2 == 0 || s != nullptr, "string::replace received nullptr"); + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); + } + n1 = std::min(n1, sz - pos); + size_type cap = capacity(); + if (cap - sz + n1 < n2) { + grow_by_and_replace(cap, sz - n1 + n2 - cap, sz, pos, n1, n2, s); return *this; } - constexpr basic_string& replace(const_iterator first, const_iterator last, size_type count2, value_type ch) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - internal_replace(pos, ch, count, count2); - return *this; + value_type* p = std::to_address(get_pointer()); + if (n1 != n2) { + if (n2 > n1) { + annotate_increase(n2 - n1); + } + size_type n_move = sz - pos - n1; + if (n_move != 0) { + if (n1 > n2) { + traits_type::move(p + pos, s, n2); + traits_type::move(p + pos + n2, p + pos + n1, n_move); + return null_terminate_at(p, sz + (n2 - n1)); + } + if (is_pointer_in_range(p + pos + 1, p + sz, s)) { + if (p + pos + n1 <= s) { + s += n2 - n1; + } else { // p + pos < s < p + pos + n1 + traits_type::move(p + pos, s, n1); + pos += n1; + s += n2; + n2 -= n1; + n1 = 0; + } + } + traits_type::move(p + pos + n2, p + pos + n1, n_move); + } } + traits_type::move(p + pos, s, n2); + return null_terminate_at(p, sz + (n2 - n1)); + } - constexpr basic_string& replace(const_iterator first, const_iterator last, std::initializer_list list) { - return replace(first, last, const_pointer(list.begin()), list.size()); + template + constexpr basic_string& + basic_string::replace(size_type pos, size_type n1, size_type n2, value_type c) { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); + } + n1 = std::min(n1, sz - pos); + size_type cap = capacity(); + value_type* p; + if (cap - sz + n1 >= n2) { + p = std::to_address(get_pointer()); + if (n1 != n2) { + if (n2 > n1) { + annotate_increase(n2 - n1); + } + size_type n_move = sz - pos - n1; + if (n_move != 0) { + traits_type::move(p + pos + n2, p + pos + n1, n_move); + } + } + } else { + grow_by_without_replace(cap, sz - n1 + n2 - cap, sz, pos, n1, n2); + p = std::to_address(get_long_pointer()); } + traits_type::assign(p + pos, n2, c); + return null_terminate_at(p, sz - (n1 - n2)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(size_type pos, size_type count, const Type& t) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - sview_type sv(t); - return replace(pos, count, sv.data(), sv.length()); - } + template + constexpr basic_string& + basic_string::replace( + size_type pos1, + size_type n1, + const basic_string& str, + size_type pos2, + size_type n2 + ) { + size_type str_sz = str.size(); + if (pos2 > str_sz) { + this->throw_out_of_range(); + } + return replace(pos1, n1, str.data() + pos2, std::min(n2, str_sz - pos2)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(const_iterator first, const_iterator last, const Type& t) { - sview_type sv(t); - return replace(first, last, sv.data(), sv.length()); - } + template + constexpr basic_string& + basic_string::replace(size_type pos, size_type n1, const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::replace received nullptr"); + return replace(pos, n1, s, traits_type::length(s)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(size_type pos, size_type count, const Type& t, size_type pos2, size_type count2 = npos) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - auto sv = sview_type(t).substr(pos2, count2); - return replace(pos, count, sv.data(), sv.length()); - } + // erase -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr iterator replace_with_range(const_iterator first, const_iterator last, Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - return replace(first, last, str);// replace checks for max_size() + // 'externally instantiated' erase() implementation, called when n != npos. + // Does not check pos against size() + template + PLUGIFY_NOINLINE constexpr void + basic_string::erase_external_with_move(size_type pos, size_type n) { + if (n == 0) { + return; } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr basic_string substr(size_type pos = 0, size_type count = npos) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::substr(): pos out of range", std::out_of_range); - return basic_string(*this, pos, count); + size_type sz = size(); + value_type* p = std::to_address(get_pointer()); + n = std::min(n, sz - pos); + size_type n_move = sz - pos - n; + if (n_move != 0) { + traits_type::move(p + pos, p + pos + n, n_move); } + null_terminate_at(p, sz - n); + } - constexpr size_type copy(value_type* str, size_type count, size_type pos = 0) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::copy(): pos out of range", std::out_of_range); - return view().copy(str, count, pos); + template + constexpr basic_string& + basic_string::erase(size_type pos, size_type n) { + if (pos > size()) { + this->throw_out_of_range(); } - - constexpr void resize(size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::resize(): resulted string size would exceed max_size()", std::length_error); - auto cap = capacity(); - auto sz = size(); - auto rsz = count + sz; - - if (sz < rsz) { - if (cap < rsz) - grow_to(rsz); - Traits::assign(data() + sz, count, ch); - } - set_size(rsz); - null_terminate(); + if (n == npos) { + erase_to_end(pos); + } else { + erase_external_with_move(pos, n); } + return *this; + } - constexpr void resize(size_type count) { - resize(count, _terminator); - } + template + inline constexpr typename basic_string::iterator + basic_string::erase(const_iterator pos) { + PLUGIFY_ASSERT(pos != end(), "string::erase(iterator) called with a non-dereferenceable iterator"); + iterator b = begin(); + size_type r = static_cast(pos - b); + erase(r, 1); + return b + static_cast(r); + } - template - constexpr void resize_and_overwrite(size_type, Operation) { - static_assert(detail::dependent_false, "plg::basic_string::resize_and_overwrite(count, op) not implemented!"); - } + template + inline constexpr typename basic_string::iterator + basic_string::erase(const_iterator first, const_iterator last) { + PLUGIFY_ASSERT(first <= last, "string::erase(first, last) called with invalid range"); + iterator b = begin(); + size_type r = static_cast(first - b); + erase(r, static_cast(last - first)); + return b + static_cast(r); + } - constexpr void swap(basic_string& other) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value) { - using std::swap; - if constexpr (allocator_traits::propagate_on_container_swap::value) { - swap(_allocator, other._allocator); - } - swap(_storage, other._storage); - } + template + inline constexpr void basic_string::pop_back() { + PLUGIFY_ASSERT(!empty(), "string::pop_back(): string is already empty"); + erase_to_end(size() - 1); + } - constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept { - return view().find(sview_type(str), pos); + template + inline constexpr void basic_string::clear() noexcept { + size_type old_size; + if (is_long()) { + old_size = get_long_size(); + traits_type::assign(*get_long_pointer(), value_type()); + set_long_size(0); + } else { + old_size = get_short_size(); + traits_type::assign(*get_short_pointer(), value_type()); + set_short_size(0); } + annotate_shrink(old_size); + } - constexpr size_type find(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find(str, pos, count); + template + constexpr void basic_string::resize(size_type n, value_type c) { + size_type sz = size(); + if (n > sz) { + append(n - sz, c); + } else { + erase_to_end(n); } + } - constexpr size_type find(const value_type* str, size_type pos = 0) const noexcept { - return view().find(str, pos); + template + constexpr void basic_string::reserve(size_type requested_capacity) { + if (requested_capacity > max_size()) { + this->throw_length_error(); } - constexpr size_type find(value_type ch, size_type pos = 0) const noexcept { - return view().find(ch, pos); + // Make sure reserve(n) never shrinks. This is technically only required in C++20 + // and later (since P0966R1), however we provide consistent behavior in all Standard + // modes because this function is instantiated in the shared library. + if (requested_capacity <= capacity()) { + return; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find(sview_type(t), pos); - } + [[maybe_unused]] annotation_guard g(*this); + long_ buffer = allocate_long_buffer(_alloc, requested_capacity); + buffer._size = size(); + traits_type::copy(std::to_address(buffer._data), data(), buffer._size + 1); + replace_internal_buffer(buffer); + } - constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept { - return view().rfind(sview_type(str), pos); + template + inline constexpr void basic_string::shrink_to_fit() noexcept { + size_type target_capacity = recommend(size()); + if (target_capacity == capacity()) { + return; } - constexpr size_type rfind(const value_type* str, size_type pos, size_type count) const noexcept { - return view().rfind(str, pos, count); - } + PLUGIFY_ASSERT(is_long(), "Trying to shrink small string"); - constexpr size_type rfind(const value_type* str, size_type pos = npos) const noexcept { - return view().rfind(str, pos); - } + // We're a long string and we're shrinking into the small buffer. + const auto ptr = get_long_pointer(); + const auto size = get_long_size(); + const auto cap = get_long_cap(); - constexpr size_type rfind(value_type ch, size_type pos = npos) const noexcept { - return view().rfind(ch, pos); + if (fits_in_sso(target_capacity)) { + [[maybe_unused]] annotation_guard g(*this); + set_short_size(size); + traits_type::copy(std::to_address(get_short_pointer()), std::to_address(ptr), size + 1); + alloc_traits::deallocate(_alloc, ptr, cap); + return; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type rfind(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().rfind(sview_type(t), pos); - } +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + [[maybe_unused]] annotation_guard g(*this); + long_ buffer = allocate_long_buffer(_alloc, size); - constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept { - return view().find_first_of(sview_type(str), pos); - } + // The Standard mandates shrink_to_fit() does not increase the capacity. + // With equal capacity keep the existing buffer. This avoids extra work + // due to swapping the elements. + if (buffer._cap * endian_factor - 1 >= capacity()) { + alloc_traits::deallocate(_alloc, buffer._data, buffer._cap * endian_factor); + return; + } - constexpr size_type find_first_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_first_of(str, pos, count); - } + traits_type::copy( + std::to_address(buffer._data), + std::to_address(get_long_pointer()), + size + 1 + ); + replace_internal_buffer(buffer); +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + return; + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr size_type find_first_of(const value_type* str, size_type pos = 0) const noexcept { - return view().find_first_of(str, pos); + template + constexpr typename basic_string::const_reference + basic_string::at(size_type n) const { + if (n >= size()) { + this->throw_out_of_range(); } + return (*this)[n]; + } - constexpr size_type find_first_of(value_type ch, size_type pos = 0) const noexcept { - return view().find_first_of(ch, pos); + template + constexpr typename basic_string::reference + basic_string::at(size_type n) { + if (n >= size()) { + this->throw_out_of_range(); } + return (*this)[n]; + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_first_of(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find_first_of(sview_type(t), pos); + template + constexpr typename basic_string::size_type + basic_string::copy(value_type* s, size_type n, size_type pos) const { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } + size_type rlen = std::min(n, sz - pos); + traits_type::copy(s, data() + pos, rlen); + return rlen; + } - constexpr size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept { - return view().find_first_not_of(sview_type(str), pos); + template + inline constexpr void basic_string::swap(basic_string& str) noexcept { + PLUGIFY_ASSERT( + alloc_traits::propagate_on_container_swap::value || alloc_traits::is_always_equal::value || _alloc == str._alloc, + "swapping non-equal allocators" + ); + if (!is_long()) { + annotate_delete(); } - - constexpr size_type find_first_not_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_first_not_of(str, pos, count); + if (this != std::addressof(str) && !str.is_long()) { + str.annotate_delete(); } - - constexpr size_type find_first_not_of(const value_type* str, size_type pos = 0) const noexcept { - return view().find_first_not_of(str, pos); + std::swap(_rep, str._rep); + swap_allocator(_alloc, str._alloc); + if (!is_long()) { + annotate_new(get_short_size()); } - - constexpr size_type find_first_not_of(value_type ch, size_type pos = 0) const noexcept { - return view().find_first_not_of(ch, pos); + if (this != std::addressof(str) && !str.is_long()) { + str.annotate_new(str.get_short_size()); } + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_first_not_of(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find_first_not_of(sview_type(t), pos); + // compare + + template + inline constexpr int basic_string::compare( + size_type pos1, + size_type n1, + const value_type* s, + size_type n2 + ) const { + PLUGIFY_ASSERT(n2 == 0 || s != nullptr, "string::compare(): received nullptr"); + size_type sz = size(); + if (pos1 > sz || n2 == npos) { + this->throw_out_of_range(); + } + size_type rlen = std::min(n1, sz - pos1); + int r = traits_type::compare(data() + pos1, s, std::min(rlen, n2)); + if (r == 0) { + if (rlen < n2) { + r = -1; + } else if (rlen > n2) { + r = 1; + } } + return r; + } - constexpr size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept { - return view().find_last_of(sview_type(str), pos); - } + // invariants - constexpr size_type find_last_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_last_of(str, pos, count); + template + inline constexpr bool basic_string::invariants() const { + if (size() > capacity()) { + return false; } - - constexpr size_type find_last_of(const value_type* str, size_type pos = npos) const noexcept { - return view().find_last_of(str, pos); + if (capacity() < min_cap - 1) { + return false; } - - constexpr size_type find_last_of(value_type ch, size_type pos = npos) const noexcept { - return view().find_last_of(ch, pos); + if (data() == nullptr) { + return false; } - - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_last_of(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().find_last_of(sview_type(t), pos); + if (!Traits::eq(data()[size()], value_type())) { + return false; } + return true; + } - constexpr size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept { - return view().find_last_not_of(sview_type(str), pos); - } + // operator== - constexpr size_type find_last_not_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_last_not_of(str, pos, count); - } + template + inline constexpr bool operator==( + const basic_string& lhs, + const basic_string& rhs + ) noexcept { + size_t lhs_sz = lhs.size(); + return lhs_sz == rhs.size() && Traits::compare(lhs.data(), rhs.data(), lhs_sz) == 0; + } - constexpr size_type find_last_not_of(const value_type* str, size_type pos = npos) const noexcept { - return view().find_last_not_of(str, pos); - } + template + inline constexpr bool operator==( + const basic_string& lhs, + const CharT* PLUGIFY_NO_NULL rhs + ) noexcept { + PLUGIFY_ASSERT(rhs != nullptr, "operator==(basic_string, char*): received nullptr"); - constexpr size_type find_last_not_of(value_type ch, size_type pos = npos) const noexcept { - return view().find_last_not_of(ch, pos); - } + using String = basic_string; - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_last_not_of(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().find_last_not_of(sview_type(t), pos); + size_t rhs_len = Traits::length(rhs); + if (__builtin_constant_p(rhs_len) && !String::fits_in_sso(rhs_len)) { + if (!lhs.is_long()) { + return false; + } } - - friend constexpr basic_string operator+(const basic_string& lhs, const basic_string& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::copy(buffer + lhs_sz, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; + if (rhs_len != lhs.size()) { + return false; } + return lhs.compare(0, String::npos, rhs, rhs_len) == 0; + } - friend constexpr basic_string operator+(basic_string&& lhs, const basic_string& rhs) { - return std::move(lhs.append(rhs)); - } + template + constexpr auto operator<=>( + const basic_string& lhs, + const basic_string& rhs + ) noexcept { + return std::basic_string_view(lhs) + <=> std::basic_string_view(rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, basic_string&& rhs) { - return std::move(rhs.insert(0, lhs)); - } + template + constexpr auto operator<=>(const basic_string& lhs, const CharT* rhs) { + return std::basic_string_view(lhs) + <=> std::basic_string_view(rhs); + } - friend constexpr basic_string operator+(basic_string&& lhs, basic_string&& rhs) { - return std::move(lhs.append(rhs)); - } + // operator + + + template + constexpr basic_string concatenate_strings( + const Allocator& alloc, + std::type_identity_t> str1, + std::type_identity_t> str2 + ) { + using String = basic_string; + String r( + uninitialized_size_tag(), + str1.size() + str2.size(), + String::alloc_traits::select_on_container_copy_construction(alloc) + ); + auto ptr = std::to_address(r.get_pointer()); + Traits::copy(ptr, str1.data(), str1.size()); + Traits::copy(ptr + str1.size(), str2.data(), str2.size()); + Traits::assign(ptr[str1.size() + str2.size()], CharT()); + return r; + } - friend constexpr basic_string operator+(const Char* lhs, const basic_string& rhs) { - auto lhs_sz = Traits::length(lhs); - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(rhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs, lhs_sz); - Traits::copy(buffer + lhs_sz, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; - } + template + constexpr basic_string operator+( + const basic_string& lhs, + const basic_string& rhs + ) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const Char* lhs, basic_string&& rhs) { - return std::move(rhs.insert(0, lhs)); - } + template + constexpr basic_string + operator+(const CharT* lhs, const basic_string& rhs) { + return concatenate_strings(rhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(Char lhs, const basic_string& rhs) { - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), rhs_sz + 1, basic_string::allocator_traits::select_on_container_copy_construction(rhs._allocator)); - auto buffer = ret.data(); - Traits::assign(buffer, 1, lhs); - Traits::copy(buffer + 1, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; - } + // extern template string operator+ , allocator >(char + // const*, string const&); + + template + constexpr basic_string + operator+(CharT lhs, const basic_string& rhs) { + return concatenate_strings( + rhs.get_allocator(), + std::basic_string_view(std::addressof(lhs), 1), + rhs + ); + } - friend constexpr basic_string operator+(Char lhs, basic_string&& rhs) { - rhs.insert(rhs.begin(), lhs); - return std::move(rhs); - } + template + constexpr basic_string + operator+(const basic_string& lhs, const CharT* rhs) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, const Char* rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = Traits::length(rhs); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::copy(buffer + lhs_sz, rhs, rhs_sz); - ret.null_terminate(); - return ret; - } + template + constexpr basic_string + operator+(const basic_string& lhs, CharT rhs) { + return concatenate_strings( + lhs.get_allocator(), + lhs, + std::basic_string_view(std::addressof(rhs), 1) + ); + } +#if PLUGIFY_HAS_CXX26 + + template + constexpr basic_string operator+( + const basic_string& lhs, + std::type_identity_t> rhs + ) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(basic_string&& lhs, const Char* rhs) { - return std::move(lhs.append(rhs)); - } + template + constexpr basic_string operator+( + std::type_identity_t> lhs, + const basic_string& rhs + ) { + return concatenate_strings(rhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, Char rhs) { - auto lhs_sz = lhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + 1, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::assign(buffer + lhs_sz, 1, rhs); - ret.null_terminate(); - return ret; - } +#endif // PLUGIFY_HAS_CXX26 - friend constexpr basic_string operator+(basic_string&& lhs, Char rhs) { - lhs.push_back(rhs); - return std::move(lhs); - } - }; + template + inline constexpr basic_string operator+( + basic_string&& lhs, + const basic_string& rhs + ) { + return std::move(lhs.append(rhs)); + } - template - constexpr bool operator==(const basic_string& lhs, const basic_string& rhs) noexcept { - return lhs.compare(rhs) == 0; + template + inline constexpr basic_string operator+( + const basic_string& lhs, + basic_string&& rhs + ) { + return std::move(rhs.insert(0, lhs)); } - template - constexpr bool operator==(const basic_string& lhs, const Char* rhs) { - return lhs.compare(rhs) == 0; + template + inline constexpr basic_string + operator+(basic_string&& lhs, basic_string&& rhs) { + return std::move(lhs.append(rhs)); } - template - constexpr std::strong_ordering operator<=>(const basic_string& lhs, const basic_string& rhs) noexcept { - return lhs.compare(rhs) <=> 0; + template + inline constexpr basic_string + operator+(const CharT* lhs, basic_string&& rhs) { + return std::move(rhs.insert(0, lhs)); } - template - constexpr std::strong_ordering operator<=>(const basic_string& lhs, const Char* rhs) { - return lhs.compare(rhs) <=> 0; + template + inline constexpr basic_string + operator+(CharT lhs, basic_string&& rhs) { + rhs.insert(rhs.begin(), lhs); + return std::move(rhs); } - // swap - template - constexpr void swap(basic_string& lhs, basic_string& rhs) noexcept(noexcept(lhs.swap(rhs))) { - lhs.swap(rhs); + template + inline constexpr basic_string + operator+(basic_string&& lhs, const CharT* rhs) { + return std::move(lhs.append(rhs)); } - // erasure - template - constexpr typename basic_string::size_type erase(basic_string& c, const U& value) { - auto it = std::remove(c.begin(), c.end(), value); - auto r = std::distance(it, c.end()); - c.erase(it, c.end()); - return r; + template + inline constexpr basic_string + operator+(basic_string&& lhs, CharT rhs) { + lhs.push_back(rhs); + return std::move(lhs); } - template - constexpr typename basic_string::size_type erase_if(basic_string& c, Pred pred) { - auto it = std::remove_if(c.begin(), c.end(), pred); - auto r = std::distance(it, c.end()); - c.erase(it, c.end()); - return r; +#if PLUGIFY_HAS_CXX26 + + template + constexpr basic_string operator+( + basic_string&& lhs, + std::type_identity_t> rhs + ) { + return std::move(lhs.append(rhs)); + } + + template + constexpr basic_string operator+( + std::type_identity_t> lhs, + basic_string&& rhs + ) { + return std::move(rhs.insert(0, lhs)); } - // deduction guides - template::value_type>> - basic_string(InputIterator, InputIterator, Allocator = Allocator()) -> basic_string::value_type, std::char_traits::value_type>, Allocator>; +#endif // PLUGIFY_HAS_CXX26 - template> - explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) -> basic_string; + // swap + + template + inline constexpr void swap( + basic_string& lhs, + basic_string& rhs + ) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); + } - template> - basic_string(std::basic_string_view, typename basic_string::size_type, typename basic_string::size_type, const Allocator& = Allocator()) -> basic_string; + template + inline constexpr typename basic_string::size_type + erase(basic_string& str, const Up& v) { + auto old_size = str.size(); + str.erase(std::remove(str.begin(), str.end(), v), str.end()); + return old_size - str.size(); + } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template>> - basic_string(std::from_range_t, Range&&, Allocator = Allocator()) -> basic_string, std::char_traits>, Allocator>; -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + inline constexpr typename basic_string::size_type + erase_if(basic_string& str, Predicate pred) { + auto old_size = str.size(); + str.erase(std::remove_if(str.begin(), str.end(), pred), str.end()); + return old_size - str.size(); + } // basic_string typedef-names using string = basic_string; @@ -1702,8 +3618,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtol(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return static_cast(ret); } @@ -1713,8 +3630,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtol(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1724,8 +3642,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoll(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1735,8 +3654,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoul(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1746,8 +3666,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoull(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1757,8 +3678,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtof(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1768,8 +3690,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtod(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1779,19 +3702,22 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtold(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } namespace detail { - template - PLUGIFY_FORCE_INLINE constexpr S to_string(V v) { + template + constexpr S to_string(V v) { // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers. // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented), // so we need +1 here. - constexpr std::size_t bufSize = std::numeric_limits::digits10 + 2; // +1 for minus, +1 for digits10 + constexpr std::size_t bufSize = std::numeric_limits::digits10 + 2; // +1 for minus, + // +1 for + // digits10 char buf[bufSize]; const auto res = std::to_chars(buf, buf + bufSize, v); return S(buf, res.ptr); @@ -1800,7 +3726,12 @@ namespace plg { typedef int (*wide_printf)(wchar_t* __restrict, std::size_t, const wchar_t* __restrict, ...); #if PLUGIFY_COMPILER_MSVC - inline int truncate_snwprintf(wchar_t* __restrict buffer, std::size_t count, const wchar_t* __restrict format, ...) { + inline int truncate_snwprintf( + wchar_t* __restrict buffer, + std::size_t count, + const wchar_t* __restrict format, + ... + ) { int r; va_list args; va_start(args, format); @@ -1810,16 +3741,19 @@ namespace plg { } #endif - PLUGIFY_FORCE_INLINE constexpr wide_printf get_swprintf() noexcept { + constexpr wide_printf get_swprintf() noexcept { #if PLUGIFY_COMPILER_MSVC - return static_cast(truncate_snwprintf); + return static_cast< + int(__cdecl*)(wchar_t* __restrict, std::size_t, const wchar_t* __restrict, ...)>( + truncate_snwprintf + ); #else return swprintf; #endif } - template - PLUGIFY_FORCE_INLINE constexpr S as_string(P sprintf_like, const typename S::value_type* fmt, V v) { + template + constexpr S as_string(P sprintf_like, const typename S::value_type* fmt, V v) { typedef typename S::size_type size_type; S s; s.resize(s.capacity()); @@ -1832,7 +3766,7 @@ namespace plg { s.resize(used); break; } - available = used; // Assume this is advice of how much space we need. + available = used; // Assume this is advice of how much space we need. } else { available = available * 2 + 1; } @@ -1840,7 +3774,7 @@ namespace plg { } return s; } - }// namespace detail + } // namespace detail inline string to_string(int val) { return detail::to_string(val); } inline string to_string(unsigned val) { return detail::to_string(val); } @@ -1861,49 +3795,61 @@ namespace plg { inline wstring to_wstring(float val) { return detail::as_string(detail::get_swprintf(), L"%f", val); } inline wstring to_wstring(double val) { return detail::as_string(detail::get_swprintf(), L"%f", val); } inline wstring to_wstring(long double val) { return detail::as_string(detail::get_swprintf(), L"%Lf", val); } -#endif // PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS +#endif // PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS #ifndef PLUGIFY_STRING_NO_STD_HASH // hash support namespace detail { - template, Allocator>> + template < + typename Char, + typename Allocator, + typename String = basic_string, Allocator> + > struct string_hash_base { constexpr std::size_t operator()(const String& str) const noexcept { - return std::hash{}(typename String::sview_type(str)); + return std::hash{}(typename String::self_view(str)); } }; - }// namespace detail -#endif // PLUGIFY_STRING_NO_STD_HASH + } // namespace detail +#endif // PLUGIFY_STRING_NO_STD_HASH #ifndef PLUGIFY_STRING_NO_STD_FORMAT // format support namespace detail { - template + template static constexpr const Char* format_string() { - if constexpr (std::is_same_v || std::is_same_v) + if constexpr (std::is_same_v || std::is_same_v) { return "{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return L"{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return u"{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return U"{}"; + } return ""; } - template, Allocator>> + template < + typename Char, + typename Allocator, + typename String = basic_string, Allocator> + > struct string_formatter_base { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } - template + template auto format(const String& str, FormatContext& ctx) const { return std::format_to(ctx.out(), format_string(), str.c_str()); } }; } -#endif // PLUGIFY_STRING_NO_STD_FORMAT +#endif // PLUGIFY_STRING_NO_STD_FORMAT inline namespace literals { inline namespace string_literals { @@ -1916,6 +3862,7 @@ namespace plg { #elif PLUGIFY_COMPILER_MSVC PLUGIFY_WARN_IGNORE(4455) #endif + // suffix for basic_string literals constexpr string operator""s(const char* str, std::size_t len) { return string{str, len}; } constexpr u8string operator""s(const char8_t* str, std::size_t len) { return u8string{str, len}; } @@ -1924,29 +3871,34 @@ namespace plg { constexpr wstring operator""s(const wchar_t* str, std::size_t len) { return wstring{str, len}; } PLUGIFY_WARN_POP() - }// namespace string_literals - }// namespace literals -}// namespace plg + } // namespace string_literals + } // namespace literals +} // namespace plg #ifndef PLUGIFY_STRING_NO_STD_HASH // hash support namespace std { - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; -}// namespace std -#endif // PLUGIFY_STRING_NO_STD_HASH + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; +} // namespace std +#endif // PLUGIFY_STRING_NO_STD_HASH #ifndef PLUGIFY_STRING_NO_STD_FORMAT // format support @@ -1955,24 +3907,29 @@ namespace fmt { #else namespace std { #endif - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; -}// namespace std -#endif // PLUGIFY_STRING_NO_STD_FORMAT + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; +} // namespace std +#endif // PLUGIFY_STRING_NO_STD_FORMAT -template +template std::ostream& operator<<(std::ostream& os, const plg::basic_string& str) { os << str.c_str(); return os; @@ -1982,30 +3939,24 @@ std::ostream& operator<<(std::ostream& os, const plg::basic_string namespace plg { - namespace detail { - // Concept to match string-like types including char* and const char* - template - concept is_string_like = requires(T v) { - { std::string_view(v) }; - }; - } - - template + template constexpr string join(const Range& range, std::string_view separator) { string result; auto it = range.cbegin(); auto end = range.cend(); - if (it == end) return result; + if (it == end) { + return result; + } // First pass: compute total size size_t total_size = 0; size_t count = 0; for (auto tmp = it; tmp != end; ++tmp) { - using Elem = std::decay_t; - if constexpr (detail::is_string_like) { + using elem = std::decay_t; + if constexpr (string_like) { total_size += std::string_view(*tmp).size(); } else { total_size += std::formatted_size("{}", *tmp); @@ -2020,9 +3971,7 @@ namespace plg { auto in = std::back_inserter(result); // Second pass: actual formatting - /*if (it != end)*/ { - std::format_to(in, "{}", *it++); - } + /*if (it != end)*/ { std::format_to(in, "{}", *it++); } while (it != end) { std::format_to(in, "{}{}", separator, *it++); } @@ -2030,14 +3979,16 @@ namespace plg { return result; } - template + template constexpr string join(const Range& range, Proj&& proj, std::string_view separator) { string result; auto it = range.cbegin(); auto end = range.cend(); - if (it == end) return result; + if (it == end) { + return result; + } // First pass: compute total size size_t total_size = 0; @@ -2045,9 +3996,8 @@ namespace plg { for (auto tmp = it; tmp != end; ++tmp) { auto&& projected = std::invoke(std::forward(proj), *tmp); - using Elem = std::decay_t; - - if constexpr (detail::is_string_like) { + using elem = std::decay_t; + if constexpr (string_like) { total_size += std::string_view(*projected).size(); } else { total_size += std::formatted_size("{}", projected); @@ -2073,5 +4023,5 @@ namespace plg { return result; } -} // namespace plugify -#endif // PLUGIFY_STRING_NO_STD_FORMAT \ No newline at end of file +} // namespace plugify +#endif // PLUGIFY_STRING_NO_STD_FORMAT \ No newline at end of file diff --git a/test/cross_call_worker/external/plugify/include/plg/uninitialized.hpp b/test/cross_call_worker/external/plugify/include/plg/uninitialized.hpp new file mode 100644 index 0000000..9cc3400 --- /dev/null +++ b/test/cross_call_worker/external/plugify/include/plg/uninitialized.hpp @@ -0,0 +1,157 @@ +#pragma once + +namespace plg { + template + struct has_construct_impl : std::false_type {}; + + template + struct has_construct_impl< + decltype((void) std::declval().construct(std::declval()...)), + Alloc, + Args...> : std::true_type {}; + + template + struct has_construct : has_construct_impl {}; + + // __has_destroy + template + struct has_destroy : std::false_type {}; + + template + struct has_destroy().destroy(std::declval()))> + : std::true_type {}; + + template + struct allocator_has_trivial_move_construct : std::negation> {}; + + template + struct allocator_has_trivial_move_construct, Type> : std::true_type {}; + + template + struct allocator_has_trivial_destroy : std::negation> {}; + + template + struct allocator_has_trivial_destroy, U> : std::true_type {}; + + template + struct allocator_has_trivial_copy_construct + : std::negation> {}; + + template + struct allocator_has_trivial_copy_construct, Type> : std::true_type {}; + + // Destroy all elements in [__first, __last) from left to right using allocator destruction. + template + void allocator_destroy(Alloc& alloc, Iter first, Sent last) { + for (; first != last; ++first) + std::allocator_traits::destroy(alloc, std::to_address(first)); + } + + template + class AllocatorDestroyRangeReverse { + public: + AllocatorDestroyRangeReverse(Alloc& alloc, Iter& first, Iter& last) + : _alloc(alloc), _first(first), _last(last) {} + + void operator()() const { + allocator_destroy(_alloc, std::reverse_iterator(_last), std::reverse_iterator(_first)); + } + + private: + Alloc& _alloc; + Iter& _first; + Iter& _last; + }; + + // Copy-construct [first1, last1) in [first2, first2 + N), where N is + // distance(first1, last1). + // + // The caller has to ensure that first2 can hold at least N uninitialized elements. If an + // exception is thrown the already copied elements are destroyed in reverse order of their + // construction. + template + Iter2 uninitialized_allocator_copy_impl( + Alloc& alloc, + Iter1 first1, + Sent1 last1, + Iter2 first2 + ) { + auto destruct_first = first2; + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(alloc, destruct_first, first2) + ); + while (first1 != last1) { + std::allocator_traits::construct(alloc, std::to_address(first2), *first1); + ++first1; + ++first2; + } + guard.complete(); + return first2; + } + + template < + class Alloc, + class In, + class RawTypeIn = std::remove_const_t, + class Out> + // using RawTypeIn because of the allocator extension + requires (std::is_trivially_copy_constructible_v && + std::is_trivially_copy_assignable_v && + std::is_same_v, std::remove_const_t> && + allocator_has_trivial_copy_construct::value) + Out* uninitialized_allocator_copy_impl(Alloc&, In* first1, In* last1, Out* first2) { + return std::copy(first1, last1, const_cast(first2)); + } + + template + Iter2 uninitialized_allocator_copy(Alloc& alloc, Iter1 first1, Sent1 last1, Iter2 first2) { + return uninitialized_allocator_copy_impl(alloc, std::move(first1), std::move(last1), std::move(first2)); + } + + // __uninitialized_allocator_relocate relocates the objects in [__first, __last) into + // __result. + // Relocation means that the objects in [__first, __last) are placed into __result as-if by + // move-construct and destroy, except that the move constructor and destructor may never be + // called if they are known to be equivalent to a memcpy. + // + // Preconditions: __result doesn't contain any objects and [__first, __last) contains + // objects Postconditions: __result contains the objects from [__first, __last) and + // [__first, __last) doesn't contain any objects + // + // The strong exception guarantee is provided if any of the following are true: + // - is_nothrow_move_constructible + // - is_copy_constructible + // - is_trivially_relocatable + template + void uninitialized_allocator_relocate(Alloc& alloc, T* first, T* last, T* result) { + if (std::is_constant_evaluated() || + !is_trivially_relocatable::value || + !allocator_has_trivial_move_construct::value || + !allocator_has_trivial_destroy::value + ) { + auto destruct_first = result; + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(alloc, destruct_first, result) + ); + auto iter = first; + while (iter != last) { + std::allocator_traits::construct( + alloc, + result, +#if PLUGIFY_HAS_EXCEPTIONS + std::move_if_noexcept(*iter) +#else + std::move(*iter) +#endif // PLUGIFY_HAS_EXCEPTIONS + ); + ++iter; + ++result; + } + guard.complete(); + allocator_destroy(alloc, first, last); + } else { + // Casting to void* to suppress clang complaining that this is technically UB. + std::memcpy(static_cast(result), first, sizeof(T) * static_cast(last - first)); + } + } +}; // namespace plg diff --git a/test/cross_call_worker/external/plugify/include/plg/variant.hpp b/test/cross_call_worker/external/plugify/include/plg/variant.hpp index e9ee06b..9e7ada0 100644 --- a/test/cross_call_worker/external/plugify/include/plg/variant.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/variant.hpp @@ -1,11 +1,9 @@ #pragma once -#include #include #include // swap #include // used for index_type #include -#include #ifndef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE # include @@ -20,39 +18,41 @@ #define PLG_FWD(x) static_cast(x) #define PLG_MOV(x) static_cast< std::remove_reference_t&& >(x) -#include "plg/macro.hpp" +#include "plg/config.hpp" +#include "plg/concepts.hpp" // from https://github.com/groundswellaudio/swl-variant namespace plg { -#if PLUGIFY_EXCEPTIONS +#if PLUGIFY_HAS_EXCEPTIONS class bad_variant_access : public std::exception { - const char* message = ""; // llvm test requires a well formed what() on default init - public : + public: explicit bad_variant_access(const char* str) noexcept : message{str} {} bad_variant_access() noexcept = default; bad_variant_access(const bad_variant_access&) noexcept = default; bad_variant_access& operator=(const bad_variant_access&) noexcept = default; const char* what() const noexcept override { return message; } + private: + const char* message = ""; // llvm test requires a well formed what() on default init }; -#endif // PLUGIFY_EXCEPTIONS +#endif // PLUGIFY_HAS_EXCEPTIONS namespace detail { //struct variant_tag{}; struct emplacer_tag{}; - } - + } // namespace detail + template struct in_place_type_t : private detail::emplacer_tag {}; - + template struct in_place_index_t : private detail::emplacer_tag {}; - + template inline static constexpr in_place_index_t in_place_index; - + template inline static constexpr in_place_type_t in_place_type; - + namespace detail { template constexpr int find_first_true(bool (&&arr)[N]) { @@ -186,7 +186,6 @@ namespace plg { template<> struct node_trait { - template static constexpr auto elem_size = not(std::is_same_v) ? 2 : 1; @@ -343,9 +342,7 @@ namespace plg { // Ts... must be sorted in ascending size template using smallest_suitable_integer_type = - type_pack_element<(static_cast(Num > std::numeric_limits::max()) + ...), - Ts... - >; + type_pack_element<(static_cast((Num > std::numeric_limits::max())) + ...), Ts...>; // why do we need this again? i think something to do with GCC? namespace swap_trait { @@ -356,7 +353,7 @@ namespace plg { template inline constexpr bool nothrow = noexcept(swap(std::declval(), std::declval())); - } + } // namespace swap_trait #ifndef PLUGIFY_VARIANT_NO_STD_HASH template @@ -500,13 +497,13 @@ namespace plg { #undef CAT2 #undef INJECTSEQ - } // inline namespace v1 + } // namespace v1 struct variant_npos_t { template constexpr bool operator==(T idx) const noexcept { return idx == std::numeric_limits::max(); } }; - } + } // namespace detail inline static constexpr detail::variant_npos_t variant_npos; @@ -556,6 +553,8 @@ namespace plg { static constexpr bool trivial_dtor = std::is_trivially_destructible_v; public: + using trivially_relocatable = std::conditional_t...>, variant, void>; + template using alternative = std::remove_reference_t().template get())>; @@ -578,12 +577,12 @@ namespace plg { requires std::is_default_constructible_v> : _storage{in_place_index<0>}, _current{0} {} - + // copy constructor (trivial) constexpr variant(const variant&) requires trivial_copy_ctor = default; - + // note : both the copy and move constructor cannot be meaningfully constexpr without std::construct_at // copy constructor constexpr variant(const variant& o) @@ -591,7 +590,7 @@ namespace plg { : _storage{detail::dummy_type{}} { construct_from(o); } - + // move constructor (trivial) constexpr variant(variant&&) requires trivial_move_ctor @@ -636,7 +635,7 @@ namespace plg { explicit constexpr variant(in_place_index_t tag, std::initializer_list list, Args&&... args) : _storage{tag, list, PLG_FWD(args)...}, _current{Index} {} - + template requires ( detail::appears_exactly_once @@ -684,12 +683,12 @@ namespace plg { }); return *this; } - + // move assignment(trivial) constexpr variant& operator=(variant&& o) requires (trivial_move_assign and trivial_move_ctor and trivial_dtor) = default; - + // move assignment constexpr variant& operator=(variant&& o) noexcept((std::is_nothrow_move_constructible_v && ...) && (std::is_nothrow_move_assignable_v && ...)) @@ -705,7 +704,7 @@ namespace plg { }); return *this; } - + // generic assignment template requires detail::has_non_ambiguous_match @@ -714,14 +713,14 @@ namespace plg { && std::is_nothrow_constructible_v, T&&>) { using related_type = detail::best_overload_match; constexpr auto new_index = index_of; - + if (_current == new_index) unsafe_get() = PLG_FWD(t); else { constexpr bool do_simple_emplace = std::is_nothrow_constructible_v or not std::is_nothrow_move_constructible_v; - + if constexpr (do_simple_emplace) emplace(PLG_FWD(t)); else { @@ -729,12 +728,12 @@ namespace plg { emplace(PLG_MOV(tmp)); } } - + return *this; } - + // ================================== modifiers (20.7.3.5) - + template requires (std::is_constructible_v && detail::appears_exactly_once) constexpr T& emplace(Args&&... args) { @@ -789,7 +788,7 @@ namespace plg { full._current = npos; }; - switch(static_cast(index() == npos) + static_cast(o.index() == npos) * 2) { + switch (static_cast(index() == npos) + static_cast(o.index() == npos) * 2) { case 0 : break; case 1 : @@ -806,7 +805,7 @@ namespace plg { } } - assert(not(valueless_by_exception() && o.valueless_by_exception())); + PLUGIFY_ASSERT(not(valueless_by_exception() && o.valueless_by_exception()), ""); detail::visit_with_index(o, [&o, this](auto&& elem, auto index_cst) { if (index() == index_cst) { @@ -827,7 +826,7 @@ namespace plg { // we could refactor this detail::destruct>(elem); - o.template emplace_no_dtor<(unsigned)(this_index) >(PLG_MOV(tmp)); + o.template emplace_no_dtor(this_index)>(PLG_MOV(tmp)); }); }); } @@ -838,28 +837,28 @@ namespace plg { template constexpr auto& unsafe_get() & noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return _storage.template get(); } template constexpr auto&& unsafe_get() && noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return PLG_MOV(_storage.template get()); } template constexpr const auto& unsafe_get() const & noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return _storage.template get(); } template constexpr const auto&& unsafe_get() const && noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return PLG_MOV(_storage.template get()); } @@ -876,7 +875,7 @@ namespace plg { return; } } - assert(not o.valueless_by_exception()); + PLUGIFY_ASSERT(not o.valueless_by_exception(), ""); detail::visit_with_index(PLG_FWD(o), PLG_FWD(fn)); } @@ -938,7 +937,7 @@ namespace plg { // destroy the current element without checking for valueless constexpr void reset_no_check() { - assert(index() < size); + PLUGIFY_ASSERT(index() < size, ""); if constexpr (not trivial_dtor) { detail::visit_with_index(*this, [](auto& elem, auto index_cst) { detail::destruct>(elem); @@ -973,8 +972,8 @@ namespace plg { template constexpr bool holds_alternative(const variant& v) noexcept { static_assert((std::is_same_v || ...), "Requested type is not contained in the variant"); - constexpr auto Index = variant::template index_of; - return v.index() == Index; + constexpr auto index = variant::template index_of; + return v.index() == index; } // ========= get by index @@ -982,7 +981,9 @@ namespace plg { template constexpr auto& get(variant& v) { static_assert(Idx < sizeof...(Ts), "Index exceeds the variant size. "); - PLUGIFY_ASSERT(v.index() == Idx, "plg::variant:get(): Bad variant access in get.", bad_variant_access); + if (v.index() != Idx) { + PLUGIFY_THROW("bad variant access in get", bad_variant_access); + } return (v.template unsafe_get()); } @@ -1061,8 +1062,9 @@ namespace plg { template constexpr decltype(auto) visit(Fn&& fn, Vs&&... vs) { if constexpr ((std::decay_t::can_be_valueless || ...)) - PLUGIFY_ASSERT(!(vs.valueless_by_exception() || ...), "plg::variant:visit(): Bad variant access in visit.", bad_variant_access); - + if ((vs.valueless_by_exception() || ...)) { + PLUGIFY_THROW("bad variant access in visit", bad_variant_access); + } if constexpr (sizeof...(Vs) == 1) return detail::visit(PLG_FWD(fn), PLG_FWD(vs)...); else @@ -1151,10 +1153,9 @@ namespace plg { struct monostate{}; constexpr bool operator==(monostate, monostate) noexcept { return true; } - constexpr bool operator> (monostate, monostate) noexcept { return false; } - constexpr bool operator< (monostate, monostate) noexcept { return false; } - constexpr bool operator<=(monostate, monostate) noexcept { return true; } - constexpr bool operator>=(monostate, monostate) noexcept { return true; } + constexpr std::strong_ordering operator<=>(monostate, monostate) noexcept { + return std::strong_ordering::equal; + } // ===================================== specialized algorithms (20.7.10) @@ -1239,7 +1240,7 @@ namespace std { template<> struct hash { - constexpr std::size_t operator()(plg::monostate) const noexcept { return static_cast(-1); } + constexpr std::size_t operator()(plg::monostate) const noexcept { return static_cast(66740831); } }; } // namespace std #endif // PLUGIFY_VARIANT_NO_STD_HASH diff --git a/test/cross_call_worker/external/plugify/include/plg/vector.hpp b/test/cross_call_worker/external/plugify/include/plg/vector.hpp index 11aada1..cd26021 100644 --- a/test/cross_call_worker/external/plugify/include/plg/vector.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/vector.hpp @@ -1,1032 +1,1538 @@ #pragma once +#include +#include +#include +#include +#include +#include #include -#include -#include +#include #include #include -#include -#include -#include -#include #include - -#include -#include -#include - -#if PLUGIFY_VECTOR_CONTAINERS_RANGES && (__cplusplus <= 202002L || !__has_include() || !defined(__cpp_lib_containers_ranges)) -# undef PLUGIFY_VECTOR_CONTAINERS_RANGES -# define PLUGIFY_VECTOR_CONTAINERS_RANGES 0 -#endif - -#if PLUGIFY_VECTOR_CONTAINERS_RANGES -# include -#endif +#include +#include +#include #include "plg/allocator.hpp" +#include "plg/guards.hpp" +#include "plg/split_buffer.hpp" +#include "plg/uninitialized.hpp" + +// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc +#if PLUGIFY_COMPILER_CLANG +# pragma clang system_header +#elif PLUGIFY_COMPILER_GCC +# pragma GCC system_header +#endif +// from https://github.com/llvm/llvm-project/blob/main/libcxx/include/vector namespace plg { namespace detail { - template - concept is_alloc = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; - - struct initialized_value_tag {}; + template + struct temp_value { + using allocator_traits = std::allocator_traits; -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template - concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; -#endif - } // namespace detail + union { + T v; + }; + PLUGIFY_NO_UNIQUE_ADDRESS Alloc& a; - template - struct vector_iterator { - using allocator_traits = std::allocator_traits; - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename allocator_traits::value_type; - using difference_type = std::ptrdiff_t; - using pointer = typename allocator_traits::pointer; - using reference = value_type&; - protected: - pointer _current; - public: - constexpr vector_iterator() = default; - constexpr vector_iterator(const vector_iterator& other) = default; - constexpr vector_iterator(vector_iterator&& other) = default; - constexpr vector_iterator(pointer ptr) - : _current(ptr) {} - constexpr vector_iterator& operator=(const vector_iterator& other) = default; - constexpr vector_iterator& operator=(vector_iterator&& other) = default; - constexpr ~vector_iterator() = default; - public: - constexpr reference operator*() const noexcept { - return *_current; - } - constexpr pointer operator->() const noexcept { - return _current; - } - constexpr vector_iterator& operator++() noexcept { - ++_current; - return *this; - } - constexpr vector_iterator operator++(int) const noexcept { - return vector_iterator(_current++); - } - constexpr vector_iterator& operator--() noexcept { - --_current; - return *this; - } - constexpr vector_iterator operator--(int) const noexcept { - return vector_iterator(_current--); - } - constexpr vector_iterator& operator+=(const difference_type n) noexcept { - _current += n; - return *this; - } - constexpr vector_iterator operator+(const difference_type n) const noexcept { - vector_iterator temp = *this; - return temp += n; - } - constexpr vector_iterator& operator-=(const difference_type n) noexcept { - _current -= n; - return *this; - } - constexpr vector_iterator operator-(const difference_type n) const noexcept { - vector_iterator temp = *this; - return temp -= n; - } - constexpr reference operator[](const difference_type n) const noexcept { - return _current[n]; - } - template - constexpr friend typename vector_iterator::difference_type operator-(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; - operator const pointer() const noexcept { - return _current; - } -#endif // __cpp_impl_three_way_comparison - pointer base() const noexcept { - return _current; - } - }; + constexpr T* addr() { + return std::addressof(v); + } - template - constexpr typename vector_iterator::difference_type operator-(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - using difference_type = typename vector_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } -#if __cpp_impl_three_way_comparison - template - constexpr auto operator<=>(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); - } -#endif // __cpp_impl_three_way_comparison + constexpr T& get() { + return *addr(); + } - template - struct vector_const_iterator { - using allocator_traits = std::allocator_traits; - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename allocator_traits::value_type; - using difference_type = std::ptrdiff_t; - using pointer = typename allocator_traits::const_pointer; - using reference = const value_type&; - protected: - pointer _current; - public: - constexpr vector_const_iterator() = default; - constexpr vector_const_iterator(const vector_const_iterator& other) = default; - constexpr vector_const_iterator(vector_const_iterator&& other) = default; - constexpr vector_const_iterator(pointer ptr) - : _current(ptr) {} - constexpr vector_const_iterator(const vector_iterator& other) // allow only iterator to const_iterator conversion - : _current(other.base()) {} - constexpr vector_const_iterator& operator=(const vector_const_iterator& other) = default; - constexpr vector_const_iterator& operator=(vector_const_iterator&& other) = default; - constexpr ~vector_const_iterator() = default; - public: - constexpr reference operator*() const noexcept { - return *_current; - } - constexpr pointer operator->() const noexcept { - return _current; - } - constexpr vector_const_iterator& operator++() noexcept { - ++_current; - return *this; - } - constexpr vector_const_iterator operator++(int) noexcept { - return vector_const_iterator(_current++); - } - constexpr vector_const_iterator& operator--() noexcept { - --_current; - return *this; - } - constexpr vector_const_iterator operator--(int) noexcept { - return vector_const_iterator(_current--); - } - constexpr vector_const_iterator& operator+=(const difference_type n) noexcept { - _current += n; - return *this; - } - constexpr vector_const_iterator operator+(const difference_type n) const noexcept { - vector_const_iterator temp = *this; - return temp += n; - } - constexpr vector_const_iterator& operator-=(const difference_type n) noexcept { - _current -= n; - return *this; - } - constexpr vector_const_iterator operator-(const difference_type n) const noexcept { - vector_const_iterator temp = *this; - return temp -= n; - } - constexpr reference operator[](const difference_type n) const noexcept { - return _current[n]; - } - template - constexpr friend typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; -#endif // __cpp_impl_three_way_comparison - template - constexpr friend typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; - operator const pointer() const noexcept { - return _current; - } -#endif // __cpp_impl_three_way_comparison - pointer base() const noexcept { - return _current; - } - }; + template + PLUGIFY_NO_CFI constexpr + explicit temp_value(Alloc& alloc, Args&&... args) + : a(alloc) { + allocator_traits::construct(a, addr(), std::forward(args)...); + } - template - constexpr typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - using difference_type = typename vector_const_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } - template - constexpr auto operator<=>(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); - } - template - constexpr typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - using difference_type = typename vector_const_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } - template - constexpr auto operator<=>(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); + constexpr ~temp_value() { + allocator_traits::destroy(a, addr()); + } + }; } - // vector - // based on implementations from libc++, libstdc++ and Microsoft STL - template> + template > class vector { - using allocator_traits = std::allocator_traits; + template + using split_buffer = split_buffer; public: + // + // Types + // using value_type = T; using allocator_type = Allocator; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; + using alloc_traits = std::allocator_traits; using reference = value_type&; using const_reference = const value_type&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; - using iterator = vector_iterator; - using const_iterator = vector_const_iterator; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - protected: - PLUGIFY_NO_UNIQUE_ADDRESS - allocator_type _allocator; - pointer _begin; - pointer _end; - pointer _capacity; + //static_assert(std::check_valid_allocator::value, ""); + static_assert( + std::is_same_v, + "Allocator::value_type must be same type as value_type" + ); - private: - constexpr static size_type growth_factor = 2; // When resizing, what number to scale by + // + // [vector.cons], construct/copy/destroy + // + constexpr vector() noexcept(std::is_nothrow_default_constructible_v) = default; - constexpr void copy_constructor(const vector& other) { - const size_type capacity = other.capacity(); - _begin = allocator_traits::allocate(_allocator, capacity); - std::uninitialized_copy(other.begin(), other.end(), begin()); - _end = _begin + other.size(); - _capacity = _begin + capacity; + constexpr explicit vector(const allocator_type& a) noexcept + : _alloc(a) { } - template - constexpr void range_constructor(InputIterator first, InputIterator last) { - const size_type count = static_cast(std::distance(first, last)); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_copy(first, last, _begin); - _capacity = _begin + count; - _end = _begin + count; + constexpr explicit vector(size_type n) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n); + } + guard.complete(); } - constexpr bool is_full() const { - return _end == _capacity; + constexpr + explicit vector(size_type n, const allocator_type& a) + : _alloc(a) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n); + } + guard.complete(); } - constexpr size_type calculate_new_capacity() const { - const size_type old_capacity = capacity(); - return old_capacity == 0 ? 1 : growth_factor * old_capacity; + constexpr vector(size_type n, const value_type& x) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n, x); + } + guard.complete(); } - constexpr iterator const_iterator_cast(const_iterator iter) noexcept { - return begin() + (iter - cbegin()); + constexpr + vector(size_type n, const value_type& x, const allocator_type& a) + : _alloc(a) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n, x); + } + guard.complete(); } - constexpr void reallocate(size_type new_capacity) { - reallocate(new_capacity, [](pointer const) {}); + template + constexpr + vector(InputIterator first, InputIterator last) { + init_with_sentinel(first, last); } - template - constexpr void reallocate(size_type new_capacity, const F& construct) { - const size_type old_size = size(); - const size_type old_capacity = capacity(); - PLUGIFY_ASSERT(new_capacity >= old_size, "plg::vector::reallocate(): resulted vector size would exceed size()", std::length_error); - if (new_capacity == old_capacity) - return; - - pointer const new_begin = allocator_traits::allocate(_allocator, new_capacity); - construct(new_begin); - std::uninitialized_move(_begin, _end, new_begin); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + old_size; - _capacity = _begin + new_capacity; - } + template + constexpr + vector(InputIterator first, InputIterator last, const allocator_type& a) + : _alloc(a) { + init_with_sentinel(first, last); + } + + template + constexpr + vector(ForwardIterator first, ForwardIterator last) { + size_type n = static_cast(std::distance(first, last)); + init_with_size(first, last, n); + } + + template + constexpr + vector(ForwardIterator first, ForwardIterator last, const allocator_type& a) + : _alloc(a) { + size_type n = static_cast(std::distance(first, last)); + init_with_size(first, last, n); + } + +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr vector( + std::from_range_t, + Range&& range, + const allocator_type& alloc = allocator_type() + ) : _alloc(alloc) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + init_with_size(std::ranges::begin(range), std::ranges::end(range), n); - template - constexpr void emplace_at_end(const F& construct) { - if (is_full()) { - reallocate(calculate_new_capacity(), construct); } else { - construct(_begin); + init_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } } +#endif - template - constexpr void resize_to(size_type count, const V& value) { - if (count < size()) { - std::destroy(_begin + count, _end); - _end = _begin + count; - } else if (count > size()) { - const size_type old_size = size(); - auto construct = [&](pointer const data) { - if constexpr (std::is_same_v) { - std::uninitialized_fill(data + old_size, data + count, value); - } else { - std::uninitialized_value_construct(data + old_size, data + count); - } - }; - if (count > capacity()) { - reallocate(count, construct); - } else { - construct(_begin); + private: + class destroy_vector { + public: + constexpr explicit destroy_vector(vector& vec) + : vec_(vec) { + } + + constexpr void operator()() { + if (vec_._begin != nullptr) { + vec_.clear(); + vec_.annotate_delete(); + alloc_traits::deallocate(vec_._alloc, vec_._begin, vec_.capacity()); } - _end = _begin + count; } - } - constexpr void swap_without_allocator(vector&& other) noexcept { - using std::swap; - swap(_begin, other._begin); - swap(_end, other._end); - swap(_capacity, other._capacity); - } + private: + vector& vec_; + }; public: - // constructor - constexpr vector() noexcept(std::is_nothrow_default_constructible::value) - : _allocator(Allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { + constexpr ~vector() { + destroy_vector (*this)(); + } + + constexpr vector(const vector& x) + : _alloc(alloc_traits::select_on_container_copy_construction(x._alloc)) { + init_with_size(x._begin, x._end, x.size()); } - constexpr explicit vector(const Allocator& allocator) noexcept - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { + constexpr + vector(const vector& x, const std::type_identity_t& a) + : _alloc(a) { + init_with_size(x._begin, x._end, x.size()); } - constexpr vector(size_type count, const T& value, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_fill_n(_begin, count, value); - _capacity = _begin + count; - _end = _begin + count; + constexpr vector& operator=(const vector& x); + + constexpr vector(std::initializer_list il) { + init_with_size(il.begin(), il.end(), il.size()); } - constexpr explicit vector(size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_value_construct_n(_begin, count); - _capacity = _begin + count; - _end = _begin + count; + constexpr + vector(std::initializer_list il, const allocator_type& a) + : _alloc(a) { + init_with_size(il.begin(), il.end(), il.size()); } - template - constexpr vector(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(static_cast(std::distance(first, last)) <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - range_constructor(first, last); + constexpr vector& + operator=(std::initializer_list il) { + assign(il.begin(), il.end()); + return *this; } - constexpr vector(const vector& other) - : _allocator(other.get_allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - copy_constructor(other); + constexpr vector(vector&& x) noexcept; + + constexpr + vector(vector&& x, const std::type_identity_t& a); + + constexpr vector& operator=(vector&& x) noexcept( + std::allocator_traits::propagate_on_container_move_assignment::value || + std::allocator_traits::is_always_equal::value) + { + move_assign( + x, + std::integral_constant() + ); + return *this; } - constexpr vector(const vector& other, const Allocator& allocator) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - copy_constructor(other); + template + constexpr void + assign(InputIterator first, InputIterator last) { + assign_with_sentinel(first, last); } - constexpr vector(vector&& other) noexcept(std::is_nothrow_move_constructible::value) - : _allocator(Allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - swap(other); + template + constexpr void + assign(ForwardIterator first, ForwardIterator last) { + assign_with_size(first, last, std::distance(first, last)); } - constexpr vector(vector&& other, const Allocator& allocator) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - if constexpr (allocator_traits::is_always_equal::value) { - swap_without_allocator(std::move(other)); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr void assign_range(Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + assign_with_size(std::ranges::begin(range), std::ranges::end(range), n); + } else { - if (get_allocator() == other.get_allocator()) { - swap_without_allocator(std::move(other)); - } else { - const size_type capacity = other.capacity(); - _begin = allocator_traits::allocate(_allocator, capacity); - std::uninitialized_move(other.begin(), other.end(), begin()); - _end = _begin + other.size(); - _capacity = _begin + capacity; - } + assign_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } } +#endif - constexpr vector(std::initializer_list list, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(list.size() <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - range_constructor(list.begin(), list.end()); + constexpr void + assign(size_type n, const_reference u); + + constexpr void + assign(std::initializer_list il) { + assign(il.begin(), il.end()); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr vector(std::from_range_t, Range&& range, const Allocator& alloc = Allocator()) - : vector(std::ranges::begin(range), std::ranges::end(range), alloc) {} -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES + [[nodiscard]] constexpr allocator_type + get_allocator() const noexcept { + return this->_alloc; + } - // destructor - constexpr ~vector() { - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); + // + // Iterators + // + [[nodiscard]] constexpr iterator begin() noexcept { + return make_iter(add_alignment_assumption(this->_begin)); } - // operator= - constexpr vector& operator=(const vector& other) { - if (this == &other) [[unlikely]] { - return *this; - } + [[nodiscard]] constexpr const_iterator + begin() const noexcept { + return make_iter(add_alignment_assumption(this->_begin)); + } - clear(); - if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != other.get_allocator()) { - allocator_traits::deallocate(_allocator, _begin, capacity()); - } - } - _allocator = other.get_allocator(); - } + [[nodiscard]] constexpr iterator end() noexcept { + return make_iter(add_alignment_assumption(this->_end)); + } - assign(other.begin(), other.end()); - return *this; + [[nodiscard]] constexpr const_iterator + end() const noexcept { + return make_iter(add_alignment_assumption(this->_end)); } - constexpr vector& operator=(vector&& other) noexcept( - std::allocator_traits::propagate_on_container_move_assignment::value || - std::allocator_traits::is_always_equal::value) { - if (this == &other) [[unlikely]] { - return *this; - } + [[nodiscard]] constexpr reverse_iterator + rbegin() noexcept { + return reverse_iterator(end()); + } - clear(); - if constexpr (allocator_traits::propagate_on_container_move_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != other.get_allocator()) { - allocator_traits::deallocate(_allocator, _begin, capacity()); - } - } - _allocator = other.get_allocator(); - } + [[nodiscard]] constexpr const_reverse_iterator + rbegin() const noexcept { + return const_reverse_iterator(end()); + } - if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) { - swap_without_allocator(std::move(other)); - } else { - if (get_allocator() == other.get_allocator()) { - swap_without_allocator(std::move(other)); - } else { - assign(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end())); - other.clear(); - } - } - return *this; + [[nodiscard]] constexpr reverse_iterator + rend() noexcept { + return reverse_iterator(begin()); } - constexpr vector& operator=(std::initializer_list list) { - assign(list.begin(), list.end()); - return *this; + [[nodiscard]] constexpr const_reverse_iterator + rend() const noexcept { + return const_reverse_iterator(begin()); } - // assign - constexpr void assign(size_type count, const T& value) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error); - if (count > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_fill_n(new_begin, count, value); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _capacity = _begin + count; - } else if (size() >= count) { - std::fill_n(_begin, count, value); - std::destroy(_begin + count, _end); - } else { - std::fill_n(_begin, size(), value); - std::uninitialized_fill_n(_begin + size(), count - size(), value); - } - _end = _begin + count; + [[nodiscard]] constexpr const_iterator + cbegin() const noexcept { + return begin(); } - template - constexpr void assign(InputIterator first, InputIterator last) { - const size_type count = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error); - if (count > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_copy(first, last, new_begin); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _capacity = _begin + count; - } else if (size() >= count) { - std::copy(first, last, _begin); - std::destroy(_begin + count, _end); - } else { - std::copy(first, first + size(), _begin); - std::uninitialized_copy(first + size(), last, _begin + size()); - } - _end = _begin + count; + [[nodiscard]] constexpr const_iterator + cend() const noexcept { + return end(); } - constexpr void assign(std::initializer_list list) { - assign(list.begin(), list.end()); + [[nodiscard]] constexpr const_reverse_iterator + crbegin() const noexcept { + return rbegin(); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr void assign_range(Range&& range) { - assign(std::ranges::begin(range), std::ranges::end(range)); + [[nodiscard]] constexpr const_reverse_iterator + crend() const noexcept { + return rend(); } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - // get_allocator - constexpr allocator_type get_allocator() const { - return _allocator; + // + // [vector.capacity], capacity + // + [[nodiscard]] constexpr size_type size() const noexcept { + return static_cast(this->_end - this->_begin); } - // element access - constexpr reference at(size_type position) { - PLUGIFY_ASSERT(position < size(), "plg::vector::at(): input index is out of bounds", std::out_of_range); - return *(_begin + position); + [[nodiscard]] constexpr size_type + capacity() const noexcept { + return static_cast(this->_cap - this->_begin); } - constexpr const_reference at(size_type position) const { - PLUGIFY_ASSERT(position < size(), "plg::vector::at(): input index is out of bounds", std::out_of_range); - return *(_begin + position); + [[nodiscard]] constexpr bool + empty() const noexcept { + return this->_begin == this->_end; } - constexpr reference operator[](size_type position) noexcept { - return *(_begin + position); + [[nodiscard]] constexpr size_type + max_size() const noexcept { + return std::min( + alloc_traits::max_size(this->_alloc), + std::numeric_limits::max() + ); } - constexpr const_reference operator[](size_type position) const noexcept { - return *(_begin + position); + constexpr void reserve(size_type n); + constexpr void shrink_to_fit() noexcept; + + // + // element access + // + [[nodiscard]] constexpr reference + operator[](size_type n) noexcept { + PLUGIFY_ASSERT(n < size(), "vector[] index out of bounds"); + return this->_begin[n]; } - constexpr reference front() { - PLUGIFY_ASSERT(!empty(), "plg::vector::front(): vector is empty", std::length_error); - return *_begin; + [[nodiscard]] constexpr const_reference + operator[](size_type n) const noexcept { + PLUGIFY_ASSERT(n < size(), "vector[] index out of bounds"); + return this->_begin[n]; } - constexpr const_reference front() const { - PLUGIFY_ASSERT(!empty(), "plg::vector::front(): vector is empty", std::length_error); - return *_begin; + [[nodiscard]] constexpr reference at(size_type n) { + if (n >= size()) { + this->throw_out_of_range(); + } + return this->_begin[n]; } - constexpr reference back() { - PLUGIFY_ASSERT(!empty(), "plg::vector::back(): vector is empty", std::length_error); - return *(_end - 1); + [[nodiscard]] constexpr const_reference + at(size_type n) const { + if (n >= size()) { + this->throw_out_of_range(); + } + return this->_begin[n]; } - constexpr const_reference back() const { - PLUGIFY_ASSERT(!empty(), "plg::vector::back(): vector is empty", std::length_error); - return *(_end - 1); + [[nodiscard]] constexpr reference front() noexcept { + PLUGIFY_ASSERT(!empty(), "front() called on an empty vector"); + return *this->_begin; } - constexpr T* data() noexcept { - return _begin; + [[nodiscard]] constexpr const_reference + front() const noexcept { + PLUGIFY_ASSERT(!empty(), "front() called on an empty vector"); + return *this->_begin; } - constexpr const T* data() const noexcept { - return _begin; + [[nodiscard]] constexpr reference back() noexcept { + PLUGIFY_ASSERT(!empty(), "back() called on an empty vector"); + return *(this->_end - 1); } - // iterators - constexpr iterator begin() noexcept { - return iterator(_begin); + [[nodiscard]] constexpr const_reference + back() const noexcept { + PLUGIFY_ASSERT(!empty(), "back() called on an empty vector"); + return *(this->_end - 1); } - constexpr const_iterator begin() const noexcept { - return const_iterator(_begin); + // + // [vector.data], data access + // + [[nodiscard]] constexpr value_type* + data() noexcept { + return std::to_address(this->_begin); } - constexpr const_iterator cbegin() const noexcept { - return const_iterator(_begin); + [[nodiscard]] constexpr const value_type* + data() const noexcept { + return std::to_address(this->_begin); } - constexpr iterator end() noexcept { - return iterator(_end); + // + // [vector.modifiers], modifiers + // + constexpr void push_back(const_reference x) { + emplace_back(x); } - constexpr const_iterator end() const noexcept { - return const_iterator(_end); + constexpr void push_back(value_type&& x) { + emplace_back(std::move(x)); } - constexpr const_iterator cend() const noexcept { - return const_iterator(_end); + template + constexpr + reference + emplace_back(Args&&... args); + + template + constexpr void + emplace_back_assume_capacity(Args&&... args) { + PLUGIFY_ASSERT( + size() < capacity(), + "We assume that we have enough space to insert an element at the end of the vector" + ); + ConstructTransaction tx(*this, 1); + alloc_traits::construct(this->_alloc, std::to_address(tx.pos_), std::forward(args)...); + ++tx.pos_; } - constexpr reverse_iterator rbegin() noexcept { - return reverse_iterator(_end); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr void append_range(Range&& range) { + insert_range(end(), std::forward(range)); + } +#endif + + constexpr void pop_back() { + PLUGIFY_ASSERT(!empty(), "vector::pop_back called on an empty vector"); + this->destruct_at_end(this->_end - 1); } - constexpr const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(_end); + constexpr iterator + insert(const_iterator position, const_reference x); + + constexpr iterator + insert(const_iterator position, value_type&& x); + template + constexpr iterator + emplace(const_iterator position, Args&&... args); + + constexpr iterator + insert(const_iterator position, size_type n, const_reference x); + + template + constexpr iterator + insert(const_iterator position, InputIterator first, InputIterator last) { + return insert_with_sentinel(position, first, last); } - constexpr const_reverse_iterator crbegin() const noexcept { - return const_reverse_iterator(_end); + template + constexpr iterator + insert(const_iterator position, ForwardIterator first, ForwardIterator last) { + return insert_with_size(position, first, last, std::distance(first, last)); } - constexpr reverse_iterator rend() noexcept { - return reverse_iterator(_begin); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr iterator + insert_range(const_iterator position, Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + return insert_with_size(position, std::ranges::begin(range), std::ranges::end(range), n); + + } else { + return insert_with_sentinel(position, std::ranges::begin(range), std::ranges::end(range)); + } } +#endif - constexpr const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(_begin); + constexpr iterator + insert(const_iterator position, std::initializer_list il) { + return insert(position, il.begin(), il.end()); } - constexpr const_reverse_iterator crend() const noexcept { - return const_reverse_iterator(_begin); + constexpr iterator erase(const_iterator position); + constexpr iterator + erase(const_iterator first, const_iterator last); + + constexpr void clear() noexcept { + size_type old_size = size(); + base_destruct_at_end(this->_begin); + annotate_shrink(old_size); } - // capacity - constexpr bool empty() const { - return (_begin == _end); + constexpr void resize(size_type sz); + constexpr void + resize(size_type sz, const_reference x); + + constexpr void swap(vector&) noexcept; + + constexpr bool invariants() const; + + private: + pointer _begin = nullptr; + pointer _end = nullptr; + pointer _cap = nullptr; + PLUGIFY_NO_UNIQUE_ADDRESS + allocator_type _alloc; + + // Allocate space for n objects + // throws length_error if n > max_size() + // throws (probably bad_alloc) if memory run out + // Precondition: _begin == _end == _cap == nullptr + // Precondition: n > 0 + // Postcondition: capacity() >= n + // Postcondition: size() == 0 + constexpr void vallocate(size_type n) { + if (n > max_size()) { + this->throw_length_error(); + } + auto allocation = allocate_at_least(this->_alloc, n); + _begin = allocation.ptr; + _end = allocation.ptr; + _cap = _begin + allocation.count; + annotate_new(0); + } + + constexpr void vdeallocate() noexcept; + constexpr size_type recommend(size_type new_size) const; + constexpr void construct_at_end(size_type n); + constexpr void + construct_at_end(size_type n, const_reference x); + + template + constexpr void + init_with_size(InputIterator first, Sentinel last, size_type n) { + auto guard = make_exception_guard(destroy_vector(*this)); + + if (n > 0) { + vallocate(n); + construct_at_end(std::move(first), std::move(last), n); + } + + guard.complete(); } - constexpr size_type size() const noexcept { - return static_cast(_end - _begin); + template + constexpr void + init_with_sentinel(InputIterator first, Sentinel last) { + auto guard = make_exception_guard(destroy_vector(*this)); + + for (; first != last; ++first) { + emplace_back(*first); + } + + guard.complete(); } - constexpr size_type max_size() const noexcept { - return allocator_traits::max_size(_allocator); + template + constexpr void + assign_with_sentinel(Iterator first, Sentinel last); + + // The `Iterator` in `*_with_size` functions can be input-only only if called from + // `*_range` (since C++23). Otherwise, `Iterator` is a forward iterator. + + template + constexpr void + assign_with_size(Iterator first, Sentinel last, difference_type n); + + template + requires (!std::same_as())&&, value_type&&>) + constexpr void + insert_assign_n_unchecked(Iterator first, difference_type n, pointer position) { + for (pointer end_position = position + n; position != end_position; + ++position, (void) ++first) { + detail::temp_value tmp(this->_alloc, *first); + *position = std::move(tmp.get()); + } } - constexpr void reserve(size_type new_capacity) { - PLUGIFY_ASSERT(new_capacity <= max_size(), "plg::vector::reserve(): allocated memory size would exceed max_size()", std::length_error); - if (new_capacity > capacity()) { - reallocate(new_capacity); + template + requires (std::same_as())&&, value_type&&>) + constexpr void + insert_assign_n_unchecked(Iterator first, difference_type n, pointer position) { +#if PLUGIFY_HAS_CXX23 + if constexpr (!std::forward_iterator) { + // Handles input-only sized ranges for insert_range + std::ranges::copy_n(std::move(first), n, position); + } else +#endif + { + std::copy_n(first, n, position); } } - constexpr size_type capacity() const noexcept { - return static_cast(_capacity - _begin); + template + constexpr iterator + insert_with_sentinel(const_iterator position, InputIterator first, Sentinel last); + + template + constexpr iterator + insert_with_size(const_iterator position, Iterator first, Sentinel last, difference_type n); + + template + constexpr void + construct_at_end(InputIterator first, Sentinel last, size_type n); + + constexpr void append(size_type n); + constexpr void + append(size_type n, const_reference x); + + constexpr iterator make_iter(pointer p) noexcept { + return iterator(p); } - constexpr void shrink_to_fit() { - reallocate(size()); + constexpr const_iterator make_iter(const_pointer p) const noexcept { + return const_iterator(p); } - // modifiers - constexpr void clear() noexcept { - std::destroy(_begin, _end); - _end = _begin; - } - - constexpr iterator insert(const_iterator position, const T& value) { - return emplace(position, value); - } - - constexpr iterator insert(const_iterator position, T&& value) { - return emplace(position, std::move(value)); - } - - constexpr iterator insert(const_iterator position, size_type count, const T& value) { - const size_type sz = size(); - const size_type new_size = sz + count; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::insert(): pos out of range", std::out_of_range); - if (count != 0) { - if (new_size > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, new_size); - pointer const old_position = _begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - pointer const new_position = new_begin + position_distance; - std::uninitialized_fill_n(new_position, count, value); - std::uninitialized_move(old_position, _end, new_position + count); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _end; - } else { - pointer const pointer_position = _begin + position_distance; - std::uninitialized_fill_n(_end, count, value); - _end += count; - std::rotate(pointer_position, _end - count, _end); - } - } - return begin() + position_distance; + constexpr void + swap_out_circular_buffer(split_buffer& v); + constexpr pointer + swap_out_circular_buffer(split_buffer& v, pointer p); + constexpr void + move_range(pointer from_s, pointer from_e, pointer to); + constexpr void + move_assign(vector& c, std::true_type) noexcept(std::is_nothrow_move_assignable::value); + constexpr void + move_assign(vector& c, std::false_type) noexcept(alloc_traits::is_always_equal::value); + + constexpr void + destruct_at_end(pointer new_last) noexcept { + size_type old_size = size(); + base_destruct_at_end(new_last); + annotate_shrink(old_size); } - template - constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last) { - const size_type sz = size(); - const size_type count = static_cast(std::distance(first, last)); - const size_type new_size = sz + count; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::insert(): pos out of range", std::out_of_range); - if (count != 0) { - if (new_size > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, new_size); - pointer const old_position = _begin + position_distance; - pointer const new_position = new_begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - std::uninitialized_copy(first, last, new_position); - std::uninitialized_move(old_position, _end, new_position + count); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _end; - } else { - pointer const pointer_position = _begin + position_distance; - std::uninitialized_copy(first, last, _end); - _end += count; - std::rotate(pointer_position, _end - count, _end); - } - } - return begin() + position_distance; + template + constexpr inline pointer + emplace_back_slow_path(Args&&... args); + + // The following functions are no-ops outside of AddressSanitizer mode. + // We call annotations for every allocator, unless explicitly disabled. + // + // To disable annotations for a particular allocator, change value of + // asan_annotate_container_with_allocator to false. + // For more details, see the "Using libc++" documentation page or + // the documentation for sanitizer_annotate_contiguous_container. + + constexpr void + annotate_contiguous_container( + [[maybe_unused]] const void* old_mid, + [[maybe_unused]] const void* new_mid + ) const { + plg::annotate_contiguous_container(data(), data() + capacity(), old_mid, new_mid); } - constexpr iterator insert(const_iterator position, std::initializer_list list) { - return insert(position, list.begin(), list.end()); + constexpr void + annotate_new(size_type current_size) const noexcept { + annotate_contiguous_container(data() + capacity(), data() + current_size); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr iterator insert_range(const_iterator pos, Range&& range) { - return insert(pos - begin(), std::ranges::begin(range), std::ranges::end(range)); + constexpr void annotate_delete() const noexcept { + annotate_contiguous_container(data() + size(), data() + capacity()); } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - template - iterator emplace(const_iterator position, Args&&... args) { - const size_type sz = size(); - const size_type new_size = sz + 1; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::emplace(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::emplace(): pos out of range", std::out_of_range); - if (position == cend()) { - emplace_back(std::forward(args)...); - } else { - if (is_full()) { - const size_type new_capacity = calculate_new_capacity(); - pointer const new_begin = allocator_traits::allocate(_allocator, new_capacity); - pointer const old_position = _begin + position_distance; - pointer const new_position = new_begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - std::construct_at(new_position, std::forward(args)...); - std::uninitialized_move(old_position, _end, new_position + 1); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _begin + new_capacity; - } else { - pointer const pointer_position = _begin + position_distance; - std::construct_at(_end, std::forward(args)...); - ++_end; - std::rotate(pointer_position, _end - 1, _end); - } - } - return begin() + position_distance; + constexpr void + annotate_increase(size_type n) const noexcept { + annotate_contiguous_container(data() + size(), data() + size() + n); } - constexpr iterator erase(const_iterator position) { - iterator nonconst_position = const_iterator_cast(position); - if (nonconst_position + 1 != end()) { - std::rotate(nonconst_position, nonconst_position + 1, end()); + constexpr void + annotate_shrink(size_type old_size) const noexcept { + annotate_contiguous_container(data() + old_size, data() + size()); + } + + struct ConstructTransaction { + constexpr + explicit ConstructTransaction(vector& v, size_type n) + : v_(v) + , pos_(v._end) + , new_end_(v._end + n) { + v.annotate_increase(n); } - --_end; - std::destroy_at(_end); - return nonconst_position; - } - - constexpr iterator erase(const_iterator first, const_iterator last) { - PLUGIFY_ASSERT(first <= last, "plg::vector::erase(): called with invalid range", std::out_of_range); - iterator nonconst_first = const_iterator_cast(first); - iterator nonconst_last = const_iterator_cast(last); - if (nonconst_first != nonconst_last) { - if (nonconst_last != end()) { - std::rotate(nonconst_first, nonconst_last, end()); + + constexpr ~ConstructTransaction() { + v_._end = pos_; + if (pos_ != new_end_) { + v_.annotate_shrink(new_end_ - v_._begin); } - _end = nonconst_first.base() + static_cast(end() - nonconst_last); - std::destroy(_end, _end + static_cast(std::distance(first, last))); } - return nonconst_first; - } - constexpr void push_back(const T& value) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, value); - }); - ++_end; + vector& v_; + pointer pos_; + const const_pointer new_end_; + + ConstructTransaction(const ConstructTransaction&) = delete; + ConstructTransaction& operator=(const ConstructTransaction&) = delete; + }; + + constexpr void + base_destruct_at_end(pointer new_last) noexcept { + pointer soon_to_be_end = this->_end; + while (new_last != soon_to_be_end) { + alloc_traits::destroy(this->_alloc, std::to_address(--soon_to_be_end)); + } + this->_end = new_last; } - constexpr void push_back(T&& value) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, std::move(value)); - }); - ++_end; + constexpr void copy_assign_alloc(const vector& c) { + copy_assign_alloc( + c, + std::integral_constant() + ); } - template - constexpr reference emplace_back(Args&&... args) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::emplace_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, std::forward(args)...); - }); - ++_end; - return back(); + constexpr void + move_assign_alloc(vector& c) noexcept( + !alloc_traits::propagate_on_container_move_assignment::value + || std::is_nothrow_move_assignable::value + ) { + move_assign_alloc( + c, + std::integral_constant() + ); } - constexpr void pop_back() { - PLUGIFY_ASSERT(!empty(), "plg::vector::pop_back(): vector is empty", std::length_error); - --_end; - std::destroy_at(_end); + [[noreturn]] static void throw_length_error() { + PLUGIFY_THROW("allocated memory size would exceed max_size()", std::length_error); } - constexpr void resize(size_type count) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error); - resize_to(count, detail::initialized_value_tag{}); + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); } - constexpr void resize(size_type count, const T& value) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error); - resize_to(count, value); + constexpr void + copy_assign_alloc(const vector& c, std::true_type) { + if (this->_alloc != c._alloc) { + clear(); + annotate_delete(); + alloc_traits::deallocate(this->_alloc, this->_begin, capacity()); + this->_begin = this->_end = this->_cap = nullptr; + } + this->_alloc = c._alloc; } - constexpr vector& operator+=(const T& value) { - push_back(value); - return *this; + constexpr void + copy_assign_alloc(const vector&, std::false_type) { } - constexpr vector& operator+=(T&& value) { - push_back(std::move(value)); - return *this; + constexpr void + move_assign_alloc(vector& c, std::true_type) noexcept( + std::is_nothrow_move_assignable_v + ) { + this->_alloc = std::move(c._alloc); } - constexpr vector& operator+=(const vector& other) { - insert(end(), other.begin(), other.end()); - return *this; + constexpr void + move_assign_alloc(vector&, std::false_type) noexcept { } - constexpr vector& operator+=(vector&& other) { - if (this == &other) [[unlikely]] { - return *this; + template + requires(std::is_pointer_v) + static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(Ptr p) noexcept { + if (!std::is_constant_evaluated()) { + return static_cast(std::assume_aligned(p)); } - - insert(end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end())); - return *this; + return p; } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr void append_range(Range&& range) { - return insert(end(), std::ranges::begin(range), std::ranges::end(range)); + template + requires(!std::is_pointer_v) + static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(Ptr p) noexcept { + return p; } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - constexpr void swap(vector& other) noexcept(std::allocator_traits::propagate_on_container_swap::value || std::allocator_traits::is_always_equal::value) { - using std::swap; - if constexpr (allocator_traits::propagate_on_container_swap::value) { - swap(_allocator, other._allocator); - } - swap(_begin, other._begin); - swap(_end, other._end); - swap(_capacity, other._capacity); + constexpr void + swap_layouts(split_buffer& sb) { + auto vector_begin = _begin; + auto vector_sentinel = _end; + auto vector_cap = _cap; + + auto sb_begin = sb.begin(); + auto sb_sentinel = sb.raw_sentinel(); + auto sb_cap = sb.raw_capacity(); + + // TODO: replace with set_valid_range and set_capacity when vector supports it. + _begin = sb_begin; + _end = sb_sentinel; + _cap = sb_cap; + + sb.set_valid_range(vector_begin, vector_sentinel); + sb.set_capacity(vector_cap); } + }; + + template < + std::input_iterator InputIterator, + is_allocator Alloc> + vector(InputIterator, InputIterator, Alloc = Alloc()) + -> vector, Alloc>; + +#if PLUGIFY_HAS_CXX23 + template < + std::ranges::input_range Range, + is_allocator Alloc> + vector(std::from_range_t, Range&&, Alloc = Alloc()) + -> vector, Alloc>; +#endif + + // swap_out_circular_buffer relocates the objects in [_begin, _end) into the front of v and + // swaps the buffers of *this and v. It is assumed that v provides space for exactly (_end - + // _begin) objects in the front. This function has a strong exception guarantee. + template + constexpr void + vector::swap_out_circular_buffer(split_buffer& v) { + annotate_delete(); + auto new_begin = v.begin() - size(); + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(_begin), + std::to_address(_end), + std::to_address(new_begin) + ); + v.set_valid_range(new_begin, v.end()); + _end = _begin; // All the objects have been destroyed by relocating them. + + swap_layouts(v); + v.set_data(v.begin()); + annotate_new(size()); + } - constexpr operator std::span() noexcept { - return std::span(data(), size()); + // swap_out_circular_buffer relocates the objects in [_begin, p) into the front of v, the + // objects in [p, _end) into the back of v and swaps the buffers of *this and v. It is assumed + // that v provides space for exactly (p - _begin) objects in the front and space for at least + // (_end - p) objects in the back. This function has a strong exception guarantee if _begin == p + // || _end == p. + template + constexpr typename vector::pointer + vector::swap_out_circular_buffer( + split_buffer& v, + pointer p + ) { + annotate_delete(); + pointer ret = v.begin(); + + // Relocate [p, _end) first to avoid having a hole in [_begin, _end) + // in case something in [_begin, p) throws. + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(p), + std::to_address(_end), + std::to_address(v.end()) + ); + auto relocated_so_far = _end - p; + v.set_sentinel(v.end() + relocated_so_far); + _end = p; // The objects in [p, _end) have been destroyed by relocating them. + auto new_begin = v.begin() - (p - _begin); + + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(_begin), + std::to_address(p), + std::to_address(new_begin) + ); + v.set_valid_range(new_begin, v.end()); + _end = _begin; // All the objects have been destroyed by relocating them. + swap_layouts(v); + v.set_data(v.begin()); + annotate_new(size()); + return ret; + } + + template + constexpr void vector::vdeallocate() noexcept { + if (this->_begin != nullptr) { + clear(); + annotate_delete(); + alloc_traits::deallocate(this->_alloc, this->_begin, capacity()); + this->_begin = this->_end = this->_cap = nullptr; } + } - constexpr operator std::span() const noexcept { - return std::span(data(), size()); + // Precondition: new_size > capacity() + template + constexpr inline + typename vector::size_type + vector::recommend(size_type new_size) const { + const size_type ms = max_size(); + if (new_size > ms) { + this->throw_length_error(); + } + const size_type cap = capacity(); + if (cap >= ms / 2) { + return ms; } + return std::max(2 * cap, new_size); + } - constexpr std::span span() const noexcept { - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == size() + n + template + constexpr void vector::construct_at_end(size_type n) { + ConstructTransaction tx(*this, n); + const_pointer new_end = tx.new_end_; + for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos)); } + } - constexpr std::span span() noexcept { - return std::span(data(), size()); + // Copy constructs n objects starting at _end from x + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == old size() + n + // Postcondition: [i] == x for all i in [size() - n, n) + template + constexpr inline void + vector::construct_at_end(size_type n, const_reference x) { + ConstructTransaction tx(*this, n); + const_pointer new_end = tx.new_end_; + for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos), x); } + } + + template + template + constexpr void + vector::construct_at_end(InputIterator first, Sentinel last, size_type n) { + ConstructTransaction tx(*this, n); + tx.pos_ = uninitialized_allocator_copy( + this->_alloc, + std::move(first), + std::move(last), + tx.pos_ + ); + } - template - constexpr std::span span_size() { - PLUGIFY_ASSERT(size() == Size, "plg::vector::span_size(): const_span_size argument does not match size of vector", std::length_error); - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Postcondition: size() == size() + n + // Exception safety: strong. + template + constexpr void vector::append(size_type n) { + if (static_cast(this->_cap - this->_end) >= n) { + this->construct_at_end(n); + } else { + split_buffer v(recommend(size() + n), size(), this->_alloc); + v.construct_at_end(n); + swap_out_circular_buffer(v); } + } - template - constexpr std::span const_span_size() const { - PLUGIFY_ASSERT(size() == Size, "plg::vector::const_span_size(): const_span_size argument does not match size of vector", std::length_error); - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Postcondition: size() == size() + n + // Exception safety: strong. + template + constexpr void + vector::append(size_type n, const_reference x) { + if (static_cast(this->_cap - this->_end) >= n) { + this->construct_at_end(n, x); + } else { + split_buffer v(recommend(size() + n), size(), this->_alloc); + v.construct_at_end(n, x); + swap_out_circular_buffer(v); } + } + + template + constexpr inline + vector::vector(vector&& x) noexcept + : _alloc(std::move(x._alloc)) { + this->_begin = x._begin; + this->_end = x._end; + this->_cap = x._cap; + x._begin = x._end = x._cap = nullptr; + } - constexpr std::span byte_span() const noexcept { - return std::as_bytes(span()); + template + constexpr inline + vector::vector(vector&& x, const std::type_identity_t& a) + : _alloc(a) { + if (a == x._alloc) { + this->_begin = x._begin; + this->_end = x._end; + this->_cap = x._cap; + x._begin = x._end = x._cap = nullptr; + } else { + using Ip = std::move_iterator; + init_with_size(Ip(x.begin()), Ip(x.end()), x.size()); } + } - constexpr std::span byte_span() noexcept { - return std::as_writable_bytes(span()); + template + constexpr void + vector::move_assign(vector& c, std::false_type) noexcept( + alloc_traits::is_always_equal::value + ) { + if (this->_alloc != c._alloc) { + using Ip = std::move_iterator; + assign(Ip(c.begin()), Ip(c.end())); + } else { + move_assign(c, std::true_type()); } + } - constexpr bool contains(const T& elem) const { - return std::find(begin(), end(), elem) != end(); + template + constexpr void + vector::move_assign(vector& c, std::true_type) noexcept( + std::is_nothrow_move_assignable::value + ) { + vdeallocate(); + move_assign_alloc(c); // this can throw + this->_begin = c._begin; + this->_end = c._end; + this->_cap = c._cap; + c._begin = c._end = c._cap = nullptr; + } + + template + constexpr inline vector& + vector::operator=(const vector& x) { + if (this != std::addressof(x)) { + copy_assign_alloc(x); + assign(x._begin, x._end); } + return *this; + } - template - constexpr bool contains_if(F predicate) { - return std::find_if(begin(), end(), predicate) != end(); + template + template + constexpr void + vector::assign_with_sentinel(Iterator first, Sentinel last) { + pointer cur = _begin; + for (; first != last && cur != _end; ++first, (void) ++cur) { + *cur = *first; + } + if (cur != _end) { + destruct_at_end(cur); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } } + } - constexpr auto find(const T& value) const { - return std::find(begin(), end(), value); + template + template + constexpr void + vector::assign_with_size(Iterator first, Sentinel last, difference_type n) { + size_type new_size = static_cast(n); + if (new_size <= capacity()) { + if (new_size > size()) { +#if PLUGIFY_HAS_CXX23 + auto mid = std::ranges::copy_n(std::move(first), size(), this->_begin).in; + construct_at_end(std::move(mid), std::move(last), new_size - size()); +#else + Iterator mid = std::next(first, size()); + std::copy(first, mid, this->_begin); + construct_at_end(mid, last, new_size - size()); +#endif + } else { + pointer m = std::copy(std::move(first), last, this->_begin); + this->destruct_at_end(m); + } + } else { + vdeallocate(); + vallocate(recommend(new_size)); + construct_at_end(std::move(first), std::move(last), new_size); } + } - constexpr auto find(const T& value) { - return std::find(begin(), end(), value); + template + constexpr void + vector::assign(size_type n, const_reference u) { + if (n <= capacity()) { + size_type s = size(); + std::fill_n(this->_begin, std::min(n, s), u); + if (n > s) { + construct_at_end(n - s, u); + } else { + this->destruct_at_end(this->_begin + n); + } + } else { + vdeallocate(); + vallocate(recommend(static_cast(n))); + construct_at_end(n, u); } + } - template - constexpr auto find_if(F predicate) const { - return std::find_if(begin(), end(), predicate); + template + constexpr void vector::reserve(size_type n) { + if (n > capacity()) { + if (n > max_size()) { + this->throw_length_error(); + } + split_buffer v(n, size(), this->_alloc); + swap_out_circular_buffer(v); } + } - template - constexpr auto find_if(F predicate) { - return std::find_if(begin(), end(), predicate); + template + constexpr void vector::shrink_to_fit() noexcept { + if (capacity() > size()) { +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + split_buffer v(size(), size(), this->_alloc); + // The Standard mandates shrink_to_fit() does not increase the capacity. + // With equal capacity keep the existing buffer. This avoids extra work + // due to swapping the elements. + if (v.capacity() < capacity()) { + swap_out_circular_buffer(v); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + } +#endif // PLUGIFY_HAS_EXCEPTIONS } + } + + template + template + constexpr typename vector::pointer + vector::emplace_back_slow_path(Args&&... args) { + split_buffer v(recommend(size() + 1), size(), this->_alloc); + // v.emplace_back(std::forward(args)...); + pointer end = v.end(); + alloc_traits::construct(this->_alloc, std::to_address(end), std::forward(args)...); + v.set_sentinel(++end); + swap_out_circular_buffer(v); + return this->_end; + } - constexpr std::optional find_index(const T& value) { - const auto iter = std::find(begin(), end(), value); - if (iter == end()) { - return {}; + // This makes the compiler inline `else()` if `cond` is known to be false. Currently LLVM + // doesn't do that without the `builtin_constant_p`, since it considers `else` unlikely even + // through it's known to be run. See https://llvm.org/PR154292 + template + constexpr void + if_likely_else(bool cond, If _if, Else _else) { + if (__builtin_constant_p(cond)) { + if (cond) { + _if(); + } else { + _else(); + } + } else { + if (cond) [[likely]] { + _if(); } else { - return iter - begin(); + _else(); } } + } - constexpr std::optional find_index(const T& value) const { - const auto iter = std::find(begin(), end(), value); - if (iter == end()) { - return {}; - } else { - return iter - begin(); + template + template + constexpr inline + typename vector::reference + vector::emplace_back(Args&&... args) { + pointer end = this->_end; + if_likely_else( + end < this->_cap, + [&] { + emplace_back_assume_capacity(std::forward(args)...); + ++end; + }, + [&] { end = emplace_back_slow_path(std::forward(args)...); } + ); + + this->_end = end; + return *(end - 1); + } + + template + constexpr inline + typename vector::iterator + vector::erase(const_iterator position) { + PLUGIFY_ASSERT( + position != end(), + "vector::erase(iterator) called with a non-dereferenceable iterator" + ); + difference_type ps = position - cbegin(); + pointer p = this->_begin + ps; + this->destruct_at_end(std::move(p + 1, this->_end, p)); + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::erase(const_iterator first, const_iterator last) { + PLUGIFY_ASSERT( + first <= last, + "vector::erase(first, last) called with invalid range" + ); + pointer p = this->_begin + (first - begin()); + if (first != last) { + this->destruct_at_end(std::move(p + (last - first), this->_end, p)); + } + return make_iter(p); + } + + template + constexpr void + vector::move_range(pointer from_s, pointer from_e, pointer to) { + pointer old_last = this->_end; + difference_type n = old_last - to; + { + pointer i = from_s + n; + ConstructTransaction tx(*this, from_e - i); + for (pointer pos = tx.pos_; i < from_e; ++i, (void) ++pos, tx.pos_ = pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos), std::move(*i)); } } + std::move_backward(from_s, from_s + n, old_last); + } - template - constexpr std::optional find_index_if(F predicate) { - const auto iter = std::find_if(begin(), end(), predicate); - if (iter == end()) { - return {}; + template + constexpr typename vector::iterator + vector::insert(const_iterator position, const_reference x) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(x); } else { - return iter - begin(); + move_range(p, this->_end, p + 1); + const_pointer xr = std::pointer_traits::pointer_to(x); + if (is_pointer_in_range( + std::to_address(p), + std::to_address(_end), + std::addressof(x) + )) { + ++xr; + } + *p = *xr; + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(x); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::insert(const_iterator position, value_type&& x) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(std::move(x)); + } else { + move_range(p, this->_end, p + 1); + *p = std::move(x); + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(std::move(x)); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + template + constexpr typename vector::iterator + vector::emplace(const_iterator position, Args&&... args) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(std::forward(args)...); + } else { + detail::temp_value tmp(this->_alloc, std::forward(args)...); + move_range(p, this->_end, p + 1); + *p = std::move(tmp.get()); + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(std::forward(args)...); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::insert(const_iterator position, size_type n, const_reference x) { + pointer p = this->_begin + (position - begin()); + if (n > 0) { + if (n <= static_cast(this->_cap - this->_end)) { + size_type old_n = n; + pointer old_last = this->_end; + if (n > static_cast(this->_end - p)) { + size_type cx = n - (this->_end - p); + construct_at_end(cx, x); + n -= cx; + } + if (n > 0) { + move_range(p, old_last, p + old_n); + const_pointer xr = std::pointer_traits::pointer_to(x); + if (is_pointer_in_range( + std::to_address(p), + std::to_address(_end), + std::addressof(x) + )) { + xr += old_n; + } + std::fill_n(p, n, *xr); + } + } else { + split_buffer v( + recommend(size() + n), + p - this->_begin, + this->_alloc + ); + v.construct_at_end(n, x); + p = swap_out_circular_buffer(v, p); } } + return make_iter(p); + } + + template + template + constexpr typename vector::iterator + vector::insert_with_sentinel( + const_iterator position, + InputIterator first, + Sentinel last + ) { + difference_type off = position - begin(); + pointer p = this->_begin + off; + pointer old_last = this->_end; + for (; this->_end != this->_cap && first != last; ++first) { + emplace_back_assume_capacity(*first); + } + + if (first == last) { + (void) std::rotate(p, old_last, this->_end); + } else { + split_buffer v(_alloc); + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(_alloc, old_last, this->_end) + ); + v.construct_at_end_with_sentinel(std::move(first), std::move(last)); + split_buffer merged( + recommend(size() + v.size()), + off, + _alloc + ); // has `off` positions available at the front + uninitialized_allocator_relocate( + _alloc, + std::to_address(old_last), + std::to_address(this->_end), + std::to_address(merged.end()) + ); + guard.complete(); // Release the guard once objects in [old_last_, _end) have been + // successfully relocated. + merged.set_sentinel(merged.end() + (this->_end - old_last)); + this->_end = old_last; + uninitialized_allocator_relocate( + _alloc, + std::to_address(v.begin()), + std::to_address(v.end()), + std::to_address(merged.end()) + ); + merged.set_sentinel(merged.size() + v.size()); + v.set_sentinel(v.begin()); + p = swap_out_circular_buffer(merged, p); + } + return make_iter(p); + } - template - constexpr std::optional find_index_if(F predicate) const { - const auto iter = std::find_if(begin(), end(), predicate); - if (iter == end()) { - return {}; + template + template + constexpr typename vector::iterator + vector::insert_with_size( + const_iterator position, + Iterator first, + Sentinel last, + difference_type n + ) { + pointer p = this->_begin + (position - begin()); + if (n > 0) { + if (n <= this->_cap - this->_end) { + pointer old_last = this->_end; + difference_type dx = this->_end - p; + if (n > dx) { +#if PLUGIFY_HAS_CXX23 + if constexpr (!std::forward_iterator) { + construct_at_end(std::move(first), std::move(last), n); + std::rotate(p, old_last, this->_end); + } else +#endif + { + Iterator m = std::next(first, dx); + construct_at_end(m, last, n - dx); + if (dx > 0) { + move_range(p, old_last, p + n); + insert_assign_n_unchecked(first, dx, p); + } + } + } else { + move_range(p, old_last, p + n); + insert_assign_n_unchecked(std::move(first), n, p); + } } else { - return iter - begin(); + split_buffer v( + recommend(size() + n), + p - this->_begin, + this->_alloc + ); + v.construct_at_end_with_size(std::move(first), n); + p = swap_out_circular_buffer(v, p); } } - }; + return make_iter(p); + } + + template + constexpr void vector::resize(size_type sz) { + size_type cs = size(); + if (cs < sz) { + this->append(sz - cs); + } else if (cs > sz) { + this->destruct_at_end(this->_begin + sz); + } + } + + template + constexpr void + vector::resize(size_type sz, const_reference x) { + size_type cs = size(); + if (cs < sz) { + this->append(sz - cs, x); + } else if (cs > sz) { + this->destruct_at_end(this->_begin + sz); + } + } + + template + constexpr void vector::swap(vector& x) + noexcept + { + PLUGIFY_ASSERT( + alloc_traits::propagate_on_container_swap::value || this->_alloc == x._alloc, + "vector::swap: Either propagate_on_container_swap must be true" + " or the allocators must compare equal" + ); + std::swap(this->_begin, x._begin); + std::swap(this->_end, x._end); + std::swap(this->_cap, x._cap); + swap_allocator(this->_alloc, x._alloc); + } + + template + constexpr bool vector::invariants() const { + if (this->_begin == nullptr) { + if (this->_end != nullptr || this->_cap != nullptr) { + return false; + } + } else { + if (this->_begin > this->_end) { + return false; + } + if (this->_begin == this->_cap) { + return false; + } + if (this->_end > this->_cap) { + return false; + } + } + return true; + } // comparisons template @@ -1046,7 +1552,7 @@ namespace plg { } template - constexpr typename vector::size_type erase(vector& c, const U& value) { + constexpr vector::size_type erase(vector& c, const U& value) { auto it = std::remove(c.begin(), c.end(), value); auto r = std::distance(it, c.end()); c.erase(it, c.end()); @@ -1054,20 +1560,15 @@ namespace plg { } template - constexpr typename vector::size_type erase_if(vector& c, Pred pred) { + constexpr vector::size_type erase_if(vector& c, Pred pred) { auto it = std::remove_if(c.begin(), c.end(), pred); auto r = std::distance(it, c.end()); c.erase(it, c.end()); return r; } - // deduction guides - template::value_type>> - vector(InputIterator, InputIterator, Allocator = Allocator()) -> vector::value_type, Allocator>; - namespace pmr { template using vector = ::plg::vector>; } // namespace pmr - } // namespace plg diff --git a/test/cross_call_worker/external/plugify/include/plg/version.hpp b/test/cross_call_worker/external/plugify/include/plg/version.hpp index 6089f12..b8e8c00 100644 --- a/test/cross_call_worker/external/plugify/include/plg/version.hpp +++ b/test/cross_call_worker/external/plugify/include/plg/version.hpp @@ -13,15 +13,15 @@ #include #endif -#ifndef PLUGIFY_VECTOR_NO_STD_FORMAT -#include "plg/format.hpp" -#endif - +#include "plg/config.hpp" #include "plg/hash.hpp" -#include "plg/macro.hpp" #include "plg/string.hpp" #include "plg/vector.hpp" +#ifndef PLUGIFY_VECTOR_NO_STD_FORMAT +#include "plg/format.hpp" +#endif + // from https://github.com/Neargye/semver namespace plg { namespace detail { @@ -70,7 +70,7 @@ namespace plg { class version_parser; class prerelease_comparator; - } + } // namespace detail template class version { @@ -78,6 +78,11 @@ namespace plg { friend class detail::prerelease_comparator; public: + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value && + is_trivially_relocatable::value, version, void>; + constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase constexpr version(const version&) = default; constexpr version(version&&) = default; @@ -86,38 +91,38 @@ namespace plg { constexpr version& operator=(const version&) = default; constexpr version& operator=(version&&) = default; - constexpr I1 major() const noexcept { return major_; } - constexpr I2 minor() const noexcept { return minor_; } - constexpr I3 patch() const noexcept { return patch_; } + constexpr I1 major() const noexcept { return _major; } + constexpr I2 minor() const noexcept { return _minor; } + constexpr I3 patch() const noexcept { return _patch; } - constexpr const string& prerelease_tag() const { return prerelease_tag_; } - constexpr const string& build_metadata() const { return build_metadata_; } + constexpr const string& prerelease_tag() const { return _prerelease_tag; } + constexpr const string& build_metadata() const { return _build_metadata; } constexpr string to_string() const; private: - I1 major_ = 0; - I2 minor_ = 1; - I3 patch_ = 0; - string prerelease_tag_; - string build_metadata_; + I1 _major = 0; + I2 _minor = 1; + I3 _patch = 0; + string _prerelease_tag; + string _build_metadata; - vector prerelease_identifiers; + vector _prerelease_identifiers; constexpr std::size_t length() const noexcept { - return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 - + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) - + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); + return detail::length(_major) + detail::length(_minor) + detail::length(_patch) + 2 + + (_prerelease_tag.empty() ? 0 : _prerelease_tag.length() + 1) + + (_build_metadata.empty() ? 0 : _build_metadata.length() + 1); } constexpr void clear() noexcept { - major_ = 0; - minor_ = 1; - patch_ = 0; + _major = 0; + _minor = 1; + _patch = 0; - prerelease_tag_.clear(); - prerelease_identifiers.clear(); - build_metadata_.clear(); + _prerelease_tag.clear(); + _prerelease_identifiers.clear(); + _build_metadata.clear(); } }; @@ -126,24 +131,24 @@ namespace plg { string result; detail::resize_uninitialized{}.resize(result, length()); - auto it = result.end(); - if (!build_metadata_.empty()) { - it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); + auto* it = result.end(); + if (!_build_metadata.empty()) { + it = std::copy_backward(_build_metadata.begin(), _build_metadata.end(), it); *(--it) = '+'; } - if (!prerelease_tag_.empty()) { - it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); + if (!_prerelease_tag.empty()) { + it = std::copy_backward(_prerelease_tag.begin(), _prerelease_tag.end(), it); *(--it) = '-'; } - it = detail::to_chars(it, patch_); + it = detail::to_chars(it, _patch); *(--it) = '.'; - it = detail::to_chars(it, minor_); + it = detail::to_chars(it, _minor); *(--it) = '.'; - it = detail::to_chars(it, major_); + it = detail::to_chars(it, _major); return result; } @@ -160,7 +165,7 @@ namespace plg { [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } }; #endif - + enum class version_compare_option : std::uint8_t { exclude_prerelease, include_prerelease @@ -192,25 +197,22 @@ namespace plg { } template - constexpr bool cmp_less(T t, U u) noexcept - { + constexpr bool cmp_less(T t, U u) noexcept { if constexpr (std::is_signed_v == std::is_signed_v) - return t < u; - else if constexpr (std::is_signed_v) - return t < 0 || std::make_unsigned_t(t) < u; - else - return u >= 0 && t < std::make_unsigned_t(u); -} + return t < u; + else if constexpr (std::is_signed_v) + return t < 0 || std::make_unsigned_t(t) < u; + else + return u >= 0 && t < std::make_unsigned_t(u); + } template - constexpr bool cmp_less_equal(T t, U u) noexcept - { + constexpr bool cmp_less_equal(T t, U u) noexcept { return !cmp_less(u, t); } template - constexpr bool cmp_greater_equal(T t, U u) noexcept - { + constexpr bool cmp_greater_equal(T t, U u) noexcept { return !cmp_less(t, u); } @@ -220,28 +222,7 @@ namespace plg { } constexpr int compare(std::string_view lhs, std::string_view rhs) { -#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) - // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html - // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html - constexpr bool workaround = true; -#else - constexpr bool workaround = false; -#endif - - if constexpr (workaround) { - const auto size = std::min(lhs.size(), rhs.size()); - for (std::size_t i = 0; i < size; ++i) { - if (lhs[i] < rhs[i]) { - return -1; - } else if (lhs[i] > rhs[i]) { - return 1; - } - } - - return static_cast(lhs.size() - rhs.size()); - } else { - return lhs.compare(rhs); - } + return lhs.compare(rhs); } constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { @@ -292,28 +273,28 @@ namespace plg { class token_stream { public: constexpr token_stream() = default; - constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} + constexpr explicit token_stream(vector tokens) noexcept : _tokens(std::move(tokens)) {} constexpr void push(const token& token) noexcept { - tokens_.push_back(token); + _tokens.push_back(token); } constexpr token advance() noexcept { - const token token = get(current_); - ++current_; + const token token = get(_current); + ++_current; return token; } constexpr token peek(std::size_t k = 0) const noexcept { - return get(current_ + k); + return get(_current + k); } constexpr token previous() const noexcept { - return get(current_ - 1); + return get(_current - 1); } - constexpr bool advanceIfMatch(token& token, token_type type) noexcept { - if (get(current_).type != type) { + constexpr bool advance_if_match(token& token, token_type type) noexcept { + if (get(_current).type != type) { return false; } @@ -321,9 +302,9 @@ namespace plg { return true; } - constexpr bool advanceIfMatch(token_type type) noexcept { + constexpr bool advance_if_match(token_type type) noexcept { token token; - return advanceIfMatch(token, type); + return advance_if_match(token, type); } constexpr bool consume(token_type type) noexcept { @@ -335,20 +316,20 @@ namespace plg { } private: - std::size_t current_ = 0; - vector tokens_; + std::size_t _current = 0; + vector _tokens; constexpr token get(std::size_t i) const noexcept { - return tokens_[i]; + return _tokens[i]; } }; class lexer { public: - explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} + explicit constexpr lexer(std::string_view text) noexcept : _text{text}, _current_pos{0} {} constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { - from_chars_result result{ text_.data(), std::errc{} }; + from_chars_result result{ _text.data(), std::errc{} }; while (!is_eol()) { result = scan_token(token_stream); @@ -357,14 +338,14 @@ namespace plg { } } - token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); + token_stream.push({ token_type::eol, {}, _text.data() + _text.size() }); return result; } private: - std::string_view text_; - std::size_t current_pos_; + std::string_view _text; + std::size_t _current_pos; constexpr from_chars_result scan_token(token_stream& stream) noexcept { const char c = advance(); @@ -383,16 +364,16 @@ namespace plg { add_token(stream, token_type::plus); break; case '|': - if (advanceIfMatch('|')) { + if (advance_if_match('|')) { add_token(stream, token_type::logical_or); break; } return failure(get_prev_symbol()); case '<': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); + add_token(stream, token_type::range_operator, advance_if_match('=') ? range_operator::less_or_equal : range_operator::less); break; case '>': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); + add_token(stream, token_type::range_operator, advance_if_match('=') ? range_operator::greater_or_equal : range_operator::greater); break; case '=': add_token(stream, token_type::range_operator, range_operator::equal); @@ -417,51 +398,51 @@ namespace plg { stream.push({ type, value, lexeme}); } - constexpr char advance() noexcept { - char c = text_[current_pos_]; - current_pos_ += 1; + constexpr char advance() noexcept { + char c = _text[_current_pos]; + _current_pos += 1; return c; } - constexpr bool advanceIfMatch(char c) noexcept { + constexpr bool advance_if_match(char c) noexcept { if (is_eol()) { return false; } - if (text_[current_pos_] != c) { + if (_text[_current_pos] != c) { return false; } - current_pos_ += 1; + _current_pos += 1; return true; } constexpr const char* get_prev_symbol() const noexcept { - return text_.data() + current_pos_ - 1; + return _text.data() + _current_pos - 1; } - constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } + constexpr bool is_eol() const noexcept { return _current_pos >= _text.size(); } }; class prerelease_comparator { public: template [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { - if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { - return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); + if (lhs._prerelease_identifiers.empty() != rhs._prerelease_identifiers.empty()) { + return static_cast(rhs._prerelease_identifiers.size()) - static_cast(lhs._prerelease_identifiers.size()); } - const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); + const std::size_t count = std::min(lhs._prerelease_identifiers.size(), rhs._prerelease_identifiers.size()); for (std::size_t i = 0; i < count; ++i) { - const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); + const int compare_result = compare_identifier(lhs._prerelease_identifiers[i], rhs._prerelease_identifiers[i]); if (compare_result != 0) { return compare_result; } } - return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); + return static_cast(lhs._prerelease_identifiers.size()) - static_cast(rhs._prerelease_identifiers.size()); } private: @@ -478,45 +459,45 @@ namespace plg { class version_parser { public: - constexpr explicit version_parser(token_stream& stream) : stream_{stream} { + constexpr explicit version_parser(token_stream& stream) : _stream{stream} { } template constexpr from_chars_result parse(version& out) noexcept { out.clear(); - from_chars_result result = parse_number(out.major_); + from_chars_result result = parse_number(out._major); if (!result) { return result; } - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); + if (!_stream.consume(token_type::dot)) { + return failure(_stream.previous().lexeme); } - result = parse_number(out.minor_); + result = parse_number(out._minor); if (!result) { return result; } - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); + if (!_stream.consume(token_type::dot)) { + return failure(_stream.previous().lexeme); } - result = parse_number(out.patch_); + result = parse_number(out._patch); if (!result) { return result; } - if (stream_.advanceIfMatch(token_type::hyphen)) { - result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); + if (_stream.advance_if_match(token_type::hyphen)) { + result = parse_prerelease_tag(out._prerelease_tag, out._prerelease_identifiers); if (!result) { return result; } } - if (stream_.advanceIfMatch(token_type::plus)) { - result = parse_build_metadata(out.build_metadata_); + if (_stream.advance_if_match(token_type::plus)) { + result = parse_build_metadata(out._build_metadata); if (!result) { return result; } @@ -527,11 +508,11 @@ namespace plg { private: - token_stream& stream_; + token_stream& _stream; template constexpr from_chars_result parse_number(Int& out) { - token token = stream_.advance(); + token token = _stream.advance(); if (!is_digit(token)) { return failure(token.lexeme); @@ -542,16 +523,16 @@ namespace plg { if (first_digit == 0) { out = static_cast(result); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } - while (stream_.advanceIfMatch(token, token_type::digit)) { + while (_stream.advance_if_match(token, token_type::digit)) { result = result * 10 + std::get(token.value); } if (detail::number_in_range(result)) { out = static_cast(result); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } return failure(token.lexeme, std::errc::result_out_of_range); @@ -573,10 +554,10 @@ namespace plg { result.append(identifier); out_identifiers.push_back(make_prerelease_identifier(identifier)); - } while (stream_.advanceIfMatch(token_type::dot)); + } while (_stream.advance_if_match(token_type::dot)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr from_chars_result parse_build_metadata(string& out) { @@ -593,15 +574,15 @@ namespace plg { } result.append(identifier); - } while (stream_.advanceIfMatch(token_type::dot)); + } while (_stream.advance_if_match(token_type::dot)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr from_chars_result parse_prerelease_identifier(string& out) { string result; - token token = stream_.advance(); + token token = _stream.advance(); do { switch (token.type) { @@ -615,7 +596,7 @@ namespace plg { { const auto digit = std::get(token.value); - // numerical prerelease identifier doesn't allow leading zero + // numerical prerelease identifier doesn't allow leading zero // 1.2.3-1.alpha is valid, // 1.2.3-01b is valid as well, but // 1.2.3-01.alpha is not valid @@ -632,10 +613,10 @@ namespace plg { default: return failure(token.lexeme); } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + } while (_stream.advance_if_match(token, token_type::hyphen) || _stream.advance_if_match(token, token_type::letter) || _stream.advance_if_match(token, token_type::digit)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { @@ -651,7 +632,7 @@ namespace plg { constexpr from_chars_result parse_build_identifier(string& out) { string result; - token token = stream_.advance(); + token token = _stream.advance(); do { switch (token.type) { @@ -670,10 +651,10 @@ namespace plg { default: return failure(token.lexeme); } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + } while (_stream.advance_if_match(token, token_type::hyphen) || _stream.advance_if_match(token, token_type::letter) || _stream.advance_if_match(token, token_type::digit)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr bool is_leading_zero(int digit) noexcept { @@ -686,7 +667,7 @@ namespace plg { int digits = 0; while (true) { - const token token = stream_.peek(k); + const token token = _stream.peek(k); if (!is_alphanumeric(token)) { break; @@ -766,7 +747,7 @@ namespace plg { return success(token_stream.previous().lexeme); } - } // namespace semver::detail + } // namespace detail template [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { @@ -798,17 +779,15 @@ namespace plg { return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; } -#if __cpp_impl_three_way_comparison >= 201907L template [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); if (compare == 0) - return std::strong_ordering::equal; - if (compare > 0) - return std::strong_ordering::greater; - return std::strong_ordering::less; + return std::strong_ordering::equal; + if (compare > 0) + return std::strong_ordering::greater; + return std::strong_ordering::less; } -#endif template constexpr from_chars_result parse(std::string_view str, version& output) { @@ -824,44 +803,44 @@ namespace plg { template class range_comparator { public: - constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} + constexpr range_comparator(const version& v, range_operator op) noexcept : _v(v), _op(op) {} constexpr bool contains(const version& other) const noexcept { - switch (op_) { + switch (_op) { case range_operator::less: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) < 0; case range_operator::less_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) <= 0; case range_operator::greater: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) > 0; case range_operator::greater_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) >= 0; case range_operator::equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) == 0; } return false; } - constexpr const version& get_version() const noexcept { return v_; } + constexpr const version& get_version() const noexcept { return _v; } - constexpr range_operator get_operator() const noexcept { return op_; } + constexpr range_operator get_operator() const noexcept { return _op; } constexpr string to_string() const { string result; - switch (op_) { + switch (_op) { case range_operator::less: result += "<"; break; case range_operator::less_or_equal: result += "<="; break; case range_operator::greater: result += ">"; break; case range_operator::greater_or_equal: result += ">="; break; case range_operator::equal: result += "="; break; } - result += v_.to_string(); + result += _v.to_string(); return result; } private: - version v_; - range_operator op_; + version _v; + range_operator _op; }; class range_parser; @@ -878,40 +857,40 @@ namespace plg { } } - return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + return std::all_of(_ranges_comparators.begin(), _ranges_comparators.end(), [&](const auto& ranges_comparator) { return ranges_comparator.contains(v); }); } constexpr auto begin() const noexcept { - return ranges_comparators_.begin(); + return _ranges_comparators.begin(); } constexpr auto end() const noexcept { - return ranges_comparators_.end(); + return _ranges_comparators.end(); } constexpr std::size_t size() const noexcept { - return ranges_comparators_.size(); + return _ranges_comparators.size(); } constexpr bool empty() const noexcept { - return ranges_comparators_.empty(); + return _ranges_comparators.empty(); } constexpr string to_string() const { - return join(ranges_comparators_, " "); + return join(_ranges_comparators, " "); } private: - vector> ranges_comparators_; + vector> _ranges_comparators; constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { if (v.prerelease_tag().empty()) { return true; } - return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + return std::any_of(_ranges_comparators.begin(), _ranges_comparators.end(), [&](const auto& ranges_comparator) { const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; return has_prerelease && equal_without_prerelease; @@ -926,39 +905,39 @@ namespace plg { friend class detail::range_parser; constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { - return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { + return std::any_of(_ranges.begin(), _ranges.end(), [&](const auto& range) { return range.contains(v, option); }); } constexpr auto begin() const noexcept { - return ranges_.begin(); + return _ranges.begin(); } constexpr auto end() const noexcept { - return ranges_.end(); + return _ranges.end(); } constexpr std::size_t size() const noexcept { - return ranges_.size(); + return _ranges.size(); } constexpr bool empty() const noexcept { - return ranges_.empty(); + return _ranges.empty(); } constexpr string to_string() const { - return join(ranges_, " "); + return join(_ranges, " "); } private: - vector> ranges_; + vector> _ranges; }; namespace detail { class range_parser { public: - constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} + constexpr explicit range_parser(token_stream stream) noexcept : _stream(std::move(stream)) {} template constexpr from_chars_result parse(range_set& out) noexcept { @@ -974,59 +953,59 @@ namespace plg { ranges.push_back(range); skip_whitespaces(); - } while (stream_.advanceIfMatch(token_type::logical_or)); + } while (_stream.advance_if_match(token_type::logical_or)); - out.ranges_ = std::move(ranges); + out._ranges = std::move(ranges); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } - + private: - token_stream stream_; + token_stream _stream; template constexpr from_chars_result parse_range(detail::range& out) noexcept { do { skip_whitespaces(); - if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { + if (const auto res = parse_range_comparator(out._ranges_comparators); !res) { return res; } skip_whitespaces(); - } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); - - return success(stream_.peek().lexeme); + } while (_stream.check(token_type::range_operator) || _stream.check(token_type::digit)); + + return success(_stream.peek().lexeme); } template constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { range_operator op = range_operator::equal; token token; - if (stream_.advanceIfMatch(token, token_type::range_operator)) { + if (_stream.advance_if_match(token, token_type::range_operator)) { op = std::get(token.value); } skip_whitespaces(); version ver; - version_parser parser{ stream_ }; + version_parser parser{ _stream }; if (const auto res = parser.parse(ver); !res) { return res; } out.emplace_back(ver, op); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr void skip_whitespaces() noexcept { - while (stream_.advanceIfMatch(token_type::space)) { + while (_stream.advance_if_match(token_type::space)) { ; } } }; - } // namespace semver::detail + } // namespace detail template @@ -1039,7 +1018,7 @@ namespace plg { return detail::range_parser{ std::move(token_stream) }.parse(out); } -} // namespace semver +} // namespace plg #ifndef PLUGIFY_VECTOR_NO_STD_HASH // hash support diff --git a/test/example_plugin/CMakeLists.txt b/test/example_plugin/CMakeLists.txt index f707562..ff1eee7 100644 --- a/test/example_plugin/CMakeLists.txt +++ b/test/example_plugin/CMakeLists.txt @@ -13,6 +13,15 @@ set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug|Devel|MinSizeRel|RelWithDebInfo|Release") + message(STATUS "CMAKE_BUILD_TYPE not set, defaulting to Debug.") + set(CMAKE_BUILD_TYPE Debug) +endif() + +if(UNIX AND NOT APPLE) + set(LINUX TRUE) +endif() + # # Format # @@ -32,9 +41,11 @@ else() target_compile_options(${PROJECT_NAME} PRIVATE -Wextra -Wshadow -Wconversion -Wpedantic -Werror) endif() -if(UNIX AND NOT APPLE) - target_compile_definitions(${PROJECT_NAME} PRIVATE _GLIBCXX_USE_CXX11_ABI=0) +if(LINUX) + target_compile_definitions(${PROJECT_NAME} PRIVATE _GLIBCXX_USE_CXX11_ABI=1) target_link_libraries(${PROJECT_NAME} PRIVATE -static-libstdc++ -static-libgcc) + #target_compile_options(${PROJECT_NAME} PRIVATE $<$: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) + #target_link_libraries(${PROJECT_NAME} PRIVATE $<$: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE diff --git a/test/example_plugin/external/plugify/include/plg/allocator.hpp b/test/example_plugin/external/plugify/include/plg/allocator.hpp index 3c01cd5..3cc57b2 100644 --- a/test/example_plugin/external/plugify/include/plg/allocator.hpp +++ b/test/example_plugin/external/plugify/include/plg/allocator.hpp @@ -1,85 +1,59 @@ #pragma once -#include // for std::size_t, std::ptrdiff_t -#include // for std::malloc, std::free, std::aligned_alloc -#include // for std::is_constant_evaluated -#include // for ::operator new, ::operator delete +#include // for std::size_t, std::ptrdiff_t +#include // for std::malloc, std::free, std::aligned_alloc +#include // for ::operator new, ::operator delete +#include // for std::is_constant_evaluated -#include "plg/macro.hpp" +#include "plg/config.hpp" namespace plg { - // Forward declaration for allocator template class allocator; - // Specialization for `void`, but we no longer need to define `pointer` and `const_pointer` template<> class allocator { public: using value_type = void; - // Rebind struct template struct rebind { using other = allocator; }; }; - // Define the custom allocator inheriting from std::allocator template class allocator { + static_assert(!std::is_const_v, "plg::allocator does not support const types"); + static_assert(!std::is_volatile_v, "plg::allocator does not support volatile types"); public: using value_type = T; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - // Default constructor constexpr allocator() noexcept = default; - // Copy constructor template constexpr allocator(const allocator&) noexcept {} - // Rebind struct template struct rebind { using other = allocator; }; - // Override allocate method to use custom allocation function - constexpr pointer allocate(size_type n, [[maybe_unused]] const_pointer hint = nullptr) { + [[nodiscard]] constexpr T* allocate(size_type n) { static_assert(sizeof(T) != 0, "cannot allocate incomplete types"); static_assert((alignof(T) & (alignof(T) - 1)) == 0, "alignof(T) must be a power of 2"); - if (n > max_size()) [[unlikely]] { - if (n > static_cast(-1) / sizeof(T)) { - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): bad array new length", std::bad_array_new_length); - } - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): too big", std::bad_alloc); + if (n > std::allocator_traits::max_size(*this)) { + throw_bad_array_new_length(); } - pointer ret; size_type size = n * sizeof(T); if (std::is_constant_evaluated()) { - ret = static_cast(::operator new(size)); + return static_cast(::operator new(size)); } else { - if constexpr (alignof(T) > alignof(std::max_align_t)) { - size_type aligned_size = (size + (alignof(T) - 1)) & ~(alignof(T) - 1); - ret = static_cast(aligned_allocate(alignof(T), aligned_size)); - } else { - ret = static_cast(std::malloc(size)); - } - - if (!ret) { - PLUGIFY_ASSERT(false, "plg::allocator::allocate(): bad allocation", std::bad_alloc); - } + return malloc_allocate(size); } - - return ret; } - // Override deallocate method to use custom deallocation function - constexpr void deallocate(pointer p, [[maybe_unused]] size_type n) { + constexpr void deallocate(T* p, [[maybe_unused]] size_type n) { if (std::is_constant_evaluated()) { ::operator delete(p); } else { @@ -88,28 +62,114 @@ namespace plg { } private: - constexpr size_type max_size() noexcept { -#if __PTRDIFF_MAX__ < __SIZE_MAX__ - return static_cast(__PTRDIFF_MAX__) / sizeof(T); -#else - return static_cast(-1) / sizeof(T); -#endif // __PTRDIFF_MAX__ + static T* malloc_allocate(size_type size) { + T* ret; + if constexpr (alignof(T) > alignof(std::max_align_t)) { + size_type aligned_size = (size + (alignof(T) - 1)) & ~(alignof(T) - 1); + ret = static_cast(aligned_allocate(alignof(T), aligned_size)); + } else { + ret = static_cast(std::malloc(size)); + } + if (!ret) { + throw_bad_alloc(); + } + return ret; + } + + [[noreturn]] static void throw_bad_array_new_length() { + PLUGIFY_THROW("bad array new length", std::bad_array_new_length); } - void* aligned_allocate(size_type alignment, size_type size) { -#if _WIN32 + [[noreturn]] static void throw_bad_alloc() { + PLUGIFY_THROW("bad allocation", std::bad_alloc); + } + + static void* aligned_allocate(size_type alignment, size_type size) { +#if PLUGIFY_PLATFORM_WINDOWS return _aligned_malloc(size, alignment); #else return std::aligned_alloc(alignment, size); -#endif // _WIN32 +#endif // PLUGIFY_PLATFORM_WINDOWS } }; - // Comparison operators for compatibility template constexpr bool operator==(const allocator&, const allocator) { return true; } template constexpr bool operator!=(const allocator&, const allocator) { return false; } + template + void swap_allocator(Alloc& a1, Alloc& a2, std::true_type) { + using std::swap; + swap(a1, a2); + } + + template + void swap_allocator(Alloc&, Alloc&, std::false_type) noexcept {} + + template + void swap_allocator(Alloc& a1, Alloc& a2) { + swap_allocator(a1, a2, std::integral_constant::propagate_on_container_swap::value>()); + } + + template + struct allocation_result { + Pointer ptr; + Size count; + }; + + template + [[nodiscard]] allocation_result::pointer> + allocate_at_least(Alloc& alloc, size_t n) { + return { alloc.allocate(n), n }; + } + + template + constexpr bool is_pointer_in_range(const T* begin, const T* end, const U* ptr) { + if (std::is_constant_evaluated()) + return false; + return reinterpret_cast(begin) <= reinterpret_cast(ptr) && + reinterpret_cast(ptr) < reinterpret_cast(end); + } + + template + constexpr bool is_overlapping_range(const T* begin, const T* end, const U* begin2) { + auto size = end - begin; + auto end2 = begin2 + size; + return is_pointer_in_range(begin, end, begin2) || is_pointer_in_range(begin2, end2, begin); + } + + // asan_annotate_container_with_allocator determines whether containers with custom allocators are annotated. This is + // a public customization point to disable annotations if the custom allocator assumes that the memory isn't poisoned. + // See the https://libcxx.llvm.org/UsingLibcxx.html#turning-off-asan-annotation-in-containers for more information. +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + template + struct asan_annotate_container_with_allocator : std::true_type {}; +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + + // Annotate a contiguous range. + // [__first_storage, __last_storage) is the allocated memory region, + // __old_last_contained is the previously last allowed (unpoisoned) element, and + // __new_last_contained is the new last allowed (unpoisoned) element. + template + void annotate_contiguous_container( + [[maybe_unused]] const void* first_storage, + [[maybe_unused]] const void* last_storage, + [[maybe_unused]] const void* old_last_contained, + [[maybe_unused]] const void* new_last_contained + ) { +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + if (!std::is_constant_evaluated() + && asan_annotate_container_with_allocator::value + && first_storage != nullptr) { + __sanitizer_annotate_contiguous_container( + first_storage, + last_storage, + old_last_contained, + new_last_contained + ); + } +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + } } // namespace plg diff --git a/test/example_plugin/external/plugify/include/plg/concepts.hpp b/test/example_plugin/external/plugify/include/plg/concepts.hpp new file mode 100644 index 0000000..398018b --- /dev/null +++ b/test/example_plugin/external/plugify/include/plg/concepts.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include +#include + +#if PLUGIFY_HAS_CXX23 +# include +#endif + +namespace plg { +#if PLUGIFY_HAS_CXX23 + template + concept container_compatible_range = std::ranges::input_range && std::convertible_to, Type>; +#endif + + template + concept is_allocator = + // basic nested types (via allocator_traits) + requires { + typename std::allocator_traits::value_type; + typename std::allocator_traits::pointer; + typename std::allocator_traits::const_pointer; + typename std::allocator_traits::void_pointer; + typename std::allocator_traits::const_void_pointer; + typename std::allocator_traits::size_type; + typename std::allocator_traits::difference_type; + } && + // required expressions / member calls (use allocator_traits helpers where appropriate) + requires( + Alloc& a, + typename std::allocator_traits::size_type n, + typename std::allocator_traits::pointer p, + typename std::allocator_traits::value_type& v, + const typename std::allocator_traits::value_type& cv + ) { + // allocation / deallocation + { a.allocate(n) } -> std::same_as::pointer>; + { a.deallocate(p, n) } -> std::same_as; + + // max_size: prefer allocator_traits::max_size (calls member or fallback) + { std::allocator_traits::max_size(a) } -> std::convertible_to::size_type>; + + // construct / destroy (via allocator_traits helpers; these must be well-formed) + { std::allocator_traits::construct(a, p, cv) } -> std::same_as; + { std::allocator_traits::destroy(a, p) } -> std::same_as; + + // optional helpful factory used by containers when copying them + { std::allocator_traits::select_on_container_copy_construction(a) } -> std::convertible_to; + }; + + template + concept is_char_traits = requires { + // Required type definitions + typename Traits::char_type; + typename Traits::int_type; + typename Traits::off_type; + typename Traits::pos_type; + typename Traits::state_type; + } && requires( + typename Traits::char_type c1, + typename Traits::char_type c2, + typename Traits::char_type& cr, + const typename Traits::char_type& ccr, + typename Traits::char_type* p, + const typename Traits::char_type* cp, + typename Traits::int_type i1, + typename Traits::int_type i2, + std::size_t n + ) { + // Character operations + { Traits::assign(cr, ccr) } -> std::same_as; + { Traits::eq(ccr, ccr) } -> std::convertible_to; + { Traits::lt(ccr, ccr) } -> std::convertible_to; + + // String operations + { Traits::compare(cp, cp, n) } -> std::convertible_to; + { Traits::length(cp) } -> std::convertible_to; + { Traits::find(cp, n, ccr) } -> std::convertible_to; + + // Memory operations + { Traits::move(p, cp, n) } -> std::same_as; + { Traits::copy(p, cp, n) } -> std::same_as; + { Traits::assign(p, n, c1) } -> std::same_as; + + // int_type operations + { Traits::not_eof(i1) } -> std::same_as; + { Traits::to_char_type(i1) } -> std::same_as; + { Traits::to_int_type(c1) } -> std::same_as; + { Traits::eq_int_type(i1, i2) } -> std::convertible_to; + { Traits::eof() } -> std::same_as; + }; + + // A type is trivially relocatable if a move construct + destroy of the original object is equivalent to + // `memcpy(dst, src, sizeof(T))`. + // + // Note that we don't use the __cpp_lib_trivially_relocatable Clang builtin right now because it does not + // implement the semantics of any current or future trivial relocation proposal and it can lead to + // incorrect optimizations on some platforms (Windows) and supported compilers (AppleClang). +#if __has_builtin(__cpp_lib_trivially_relocatable) + template + struct is_trivially_relocatable : std::integral_constant {}; +#else + template + struct is_trivially_relocatable : std::is_trivially_copyable {}; +#endif + + template requires(std::is_same_v) + struct is_trivially_relocatable : std::true_type {}; +} diff --git a/test/cross_call_master/external/plugify/include/plg/macro.hpp b/test/example_plugin/external/plugify/include/plg/config.hpp similarity index 75% rename from test/cross_call_master/external/plugify/include/plg/macro.hpp rename to test/example_plugin/external/plugify/include/plg/config.hpp index a072fec..05db47f 100644 --- a/test/cross_call_master/external/plugify/include/plg/macro.hpp +++ b/test/example_plugin/external/plugify/include/plg/config.hpp @@ -16,57 +16,47 @@ # define __has_builtin(x) 0 #endif -#include - -#define PLUGIFY_HAS_EXCEPTIONS (__cpp_exceptions || __EXCEPTIONS || _HAS_EXCEPTIONS) - -#ifndef PLUGIFY_EXCEPTIONS -# if PLUGIFY_HAS_EXCEPTIONS -# define PLUGIFY_EXCEPTIONS 1 -# else -# define PLUGIFY_EXCEPTIONS 0 -# endif -#endif - -#if PLUGIFY_EXCEPTIONS && (!PLUGIFY_HAS_EXCEPTIONS || !__has_include()) -# undef PLUGIFY_EXCEPTIONS -# define PLUGIFY_EXCEPTIONS 0 -#endif - -#ifndef PLUGIFY_FALLBACK_ASSERT -# define PLUGIFY_FALLBACK_ASSERT 1 +#ifndef __builtin_constant_p +# define __builtin_constant_p(x) std::is_constant_evaluated() #endif -#if PLUGIFY_FALLBACK_ASSERT && !__has_include() -# undef PLUGIFY_FALLBACK_ASSERT -# define PLUGIFY_FALLBACK_ASSERT 0 +#if __has_include() +# include #endif -#ifndef PLUGIFY_FALLBACK_ABORT -# define PLUGIFY_FALLBACK_ABORT 1 -#endif - -#if PLUGIFY_FALLBACK_ABORT && !__has_include() -# undef PLUGIFY_FALLBACK_ABORT -# define PLUGIFY_FALLBACK_ABORT 0 -#endif - -#ifndef PLUGIFY_FALLBACK_ABORT_FUNCTION -# define PLUGIFY_FALLBACK_ABORT_FUNCTION [] (auto) { } +#if __has_include() +# include +# define PLUGIFY_ASSERT(cond, mesg) assert((cond) && (mesg)) #endif -#if PLUGIFY_EXCEPTIONS +#define PLUGIFY_HAS_EXCEPTIONS __cpp_exceptions || _CPPUNWIND || __EXCEPTIONS +#if PLUGIFY_HAS_EXCEPTIONS # include # include -# define PLUGIFY_ASSERT(x, str, e) do { if (!(x)) [[unlikely]] plugify_throw(str); } while (0) -#elif PLUGIFY_FALLBACK_ASSERT -# include -# define PLUGIFY_ASSERT(x, str, ...) assert((x) && (str)) -#elif PLUGIFY_FALLBACK_ABORT +namespace plg { + template + [[noreturn]] constexpr void throw_exception(const char* msg, Args...args) { + if constexpr (std::is_constructible_v) { + throw E(msg); + } else { + throw E(std::forward(args)...); + } + } +} // namespace plg +# define PLUGIFY_THROW(str, exp, ...) ::plg::throw_exception(str, ##__VA_ARGS__); +#else # include -# define PLUGIFY_ASSERT(x, ...) do { if (!(x)) [[unlikely]] { std::abort(); } } while (0) +# include +# define PLUGIFY_THROW(str, ...) \ + std::fputs(str "\n", stderr); \ + std::abort(); +#endif + +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define PLUGIFY_INSTRUMENTED_WITH_ASAN 1 +# include #else -# define PLUGIFY_ASSERT(x, str, ...) do { if (!(x)) [[unlikely]] { PLUGIFY_FALLBACK_ABORT_FUNCTION (str); { while (true) { [] { } (); } } } } while (0) +# define PLUGIFY_INSTRUMENTED_WITH_ASAN 0 #endif # define PLUGIFY_COMPILER_MAKE_VERSION2(version, sp) ((version) * 100 + (sp)) @@ -258,12 +248,24 @@ #elif PLUGIFY_COMPILER_MSVC # pragma warning(error: 4714) # define PLUGIFY_FORCE_INLINE [[msvc::forceinline]] -# define PLUGIFY_NOINLINE __declspec(noinline) +# define PLUGIFY_NOINLINE [[msvc::noinline]] #else # define PLUGIFY_FORCE_INLINE inline # define PLUGIFY_NOINLINE #endif +#if __has_feature(nullability) +# define PLUGIFY_NO_NULL _Nonnull +#else +# define PLUGIFY_NO_NULL +#endif + +#if __has_cpp_attribute(__no_sanitize__) +# define PLUGIFY_NO_CFI __attribute__((__no_sanitize__("cfi"))) +#else +# define PLUGIFY_NO_CFI +#endif + #if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG # define PLUGIFY_RESTRICT __restrict__ #elif PLUGIFY_COMPILER_MSVC @@ -272,13 +274,68 @@ # define PLUGIFY_RESTRICT #endif -#if PLUGIFY_EXCEPTIONS -template -[[noreturn]] PLUGIFY_FORCE_INLINE constexpr void plugify_throw(const char* msg) { - if constexpr (std::is_constructible_v) { - throw E(msg); - } else { - throw E(); - } -} -#endif \ No newline at end of file +#ifndef PLUGIFY_PLATFORM_WINDOWS +# if defined(_WIN32) || defined(_WIN64) +# define PLUGIFY_PLATFORM_WINDOWS 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_APPLE +# if defined(__APPLE__) && defined(__MACH__) +# define PLUGIFY_PLATFORM_APPLE 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_LINUX +# if defined(__linux__) +# define PLUGIFY_PLATFORM_LINUX 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_ANDROID +# if defined(__ANDROID__) +# define PLUGIFY_PLATFORM_ANDROID 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_ORBIS +# if defined(__ORBIS__) +# define PLUGIFY_PLATFORM_ORBIS 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_PROSPERO +# if defined(__PROSPERO__) +# define PLUGIFY_PLATFORM_PROSPERO 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_SWITCH +# if defined(__NX__) +# define PLUGIFY_PLATFORM_SWITCH 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_BSD +# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +# define PLUGIFY_PLATFORM_BSD 1 +# endif +#endif + +#ifndef PLUGIFY_PLATFORM_UNIX +# if defined(__unix__) || defined(__unix) || defined(unix) || defined(__APPLE__) +# define PLUGIFY_PLATFORM_UNIX 1 +# endif +#endif + +#if !defined(PLUGIFY_PLATFORM_WINDOWS) && \ + !defined(PLUGIFY_PLATFORM_APPLE) && \ + !defined(PLUGIFY_PLATFORM_LINUX) && \ + !defined(PLUGIFY_PLATFORM_ANDROID) && \ + !defined(PLUGIFY_PLATFORM_ORBIS) && \ + !defined(PLUGIFY_PLATFORM_PROSPERO)&& \ + !defined(PLUGIFY_PLATFORM_SWITCH) && \ + !defined(PLUGIFY_PLATFORM_BSD) && \ + !defined(PLUGIFY_PLATFORM_UNIX) +# error "Unsupported platform! Please extend macro.hpp" +#endif diff --git a/test/example_plugin/external/plugify/include/plg/debugging.hpp b/test/example_plugin/external/plugify/include/plg/debugging.hpp index b52ec8c..0326fe7 100644 --- a/test/example_plugin/external/plugify/include/plg/debugging.hpp +++ b/test/example_plugin/external/plugify/include/plg/debugging.hpp @@ -1,13 +1,19 @@ #pragma once -#include "plg/macro.hpp" - -#ifdef __cpp_lib_debugging +#include "plg/config.hpp" +#if __has_include() #include +#if defined(__cpp_lib_debugging) && __cpp_lib_debugging >= 202403L +#define PLUGIFY_HAS_STD_DEBUGGING 1 +#else +#define PLUGIFY_HAS_STD_DEBUGGING 0 +#endif +#else +#define PLUGIFY_HAS_STD_DEBUGGING 0 +#endif -#else //def __cpp_lib_debugging - +#if !PLUGIFY_HAS_STD_DEBUGGING #if PLUGIFY_PLATFORM_WINDOWS #include #include @@ -25,16 +31,7 @@ #include #endif -#endif //def __cpp_lib_debugging - namespace plg { -#ifdef __cpp_lib_debugging - - using std::breakpoint; - using std::breakpoint_if_debugging; - using std::is_debugger_present; - -#else //def __cpp_lib_debugging #if PLUGIFY_PLATFORM_WINDOWS @@ -178,7 +175,7 @@ namespace plg { } // namespace debugging } // namespace detail - PLUGIFY_NOINLINE inline bool is_debugger_present() noexcept { + inline bool is_debugger_present() noexcept { return plg::detail::debugging::parse_proc_status(); } @@ -190,7 +187,7 @@ namespace plg { #endif - PLUGIFY_FORCE_INLINE void breakpoint() noexcept { + inline void breakpoint() noexcept { #if PLUGIFY_COMPILER_MSVC __debugbreak(); #elif PLUGIFY_COMPILER_CLANG @@ -202,11 +199,17 @@ namespace plg { #endif } - PLUGIFY_FORCE_INLINE void breakpoint_if_debugging() noexcept { + inline void breakpoint_if_debugging() noexcept { if (plg::is_debugger_present()) { plg::breakpoint(); } } - -#endif //def __cpp_lib_debugging } // namespace plg + +namespace std { + using plg::breakpoint; + using plg::breakpoint_if_debugging; + using plg::is_debugger_present; +} // namespace std + +#endif // !PLUGIFY_HAS_STD_DEBUGGING diff --git a/test/example_plugin/external/plugify/include/plg/enum.hpp b/test/example_plugin/external/plugify/include/plg/enum.hpp index f8780e1..802b7c1 100644 --- a/test/example_plugin/external/plugify/include/plg/enum.hpp +++ b/test/example_plugin/external/plugify/include/plg/enum.hpp @@ -6,7 +6,7 @@ #include #include -#include "plg/macro.hpp" +#include "plg/config.hpp" // from // https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/ @@ -17,15 +17,15 @@ namespace plg { template struct static_string { constexpr static_string(std::string_view sv) noexcept { - std::copy(sv.begin(), sv.end(), content.begin()); + std::copy(sv.begin(), sv.end(), _content.begin()); } constexpr operator std::string_view() const noexcept { - return { content.data(), N }; + return { _content.data(), N }; } private: - std::array content{}; + std::array _content{}; }; constexpr auto is_pretty(char ch) noexcept { diff --git a/test/example_plugin/external/plugify/include/plg/expected.hpp b/test/example_plugin/external/plugify/include/plg/expected.hpp index d6bc137..f35fea5 100644 --- a/test/example_plugin/external/plugify/include/plg/expected.hpp +++ b/test/example_plugin/external/plugify/include/plg/expected.hpp @@ -1,14 +1,19 @@ #pragma once -#include "plg/macro.hpp" +#include "plg/config.hpp" -#ifdef __cpp_lib_expected +#if __has_include() #include -namespace plg { - using std::expected; - using std::unexpected; -} +#if defined(__cpp_lib_expected) && __cpp_lib_expected >= 202202L +#define PLUGIFY_HAS_STD_EXPECTED 1 +#else +#define PLUGIFY_HAS_STD_EXPECTED 0 +#endif #else +#define PLUGIFY_HAS_STD_EXPECTED 0 +#endif + +#if !PLUGIFY_HAS_STD_EXPECTED #include #include #include @@ -524,27 +529,39 @@ namespace plg { // precondition: has_value() = true constexpr auto operator->() const noexcept -> T const* { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::addressof(this->val); } // precondition: has_value() = true constexpr auto operator->() noexcept -> T* { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::addressof(this->val); } // precondition: has_value() = true - constexpr auto operator*() const& noexcept -> T const& { return this->val; } + constexpr auto operator*() const& noexcept -> T const& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return this->val; + } // precondition: has_value() = true - constexpr auto operator*() & noexcept -> T& { return this->val; } + constexpr auto operator*() & noexcept -> T& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return this->val; + } // precondition: has_value() = true constexpr auto operator*() const&& noexcept -> T const&& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); return std::move(this->val); } // precondition: has_value() = true - constexpr auto operator*() && noexcept -> T&& { return std::move(this->val); } + constexpr auto operator*() && noexcept -> T&& { + PLUGIFY_ASSERT(this->has_val, "requires the expected to contain a value"); + return std::move(this->val); + } constexpr explicit operator bool() const noexcept { return has_val; } @@ -553,44 +570,56 @@ namespace plg { } constexpr auto value() const& -> T const& { - if (has_value()) { - return this->val; + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } - throw bad_expected_access(error()); + return this->val; } constexpr auto value() & -> T& { - if (has_value()) { - return this->val; + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } - throw bad_expected_access(error()); + return this->val; } constexpr auto value() const&& -> T const&& { - if (has_value()) { - return std::move(this->val); + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } - throw bad_expected_access(std::move(error())); + return std::move(this->val); } constexpr auto value() && -> T&& { - if (has_value()) { - return std::move(this->val); + if (!has_value()) { + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } - throw bad_expected_access(std::move(error())); + return std::move(this->val); } // precondition: has_value() = false - constexpr auto error() const& -> E const& { return this->unex; } + constexpr auto error() const& -> E const& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() & -> E& { return this->unex; } + constexpr auto error() & -> E& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() const&& -> E const&& { return std::move(this->unex); } + constexpr auto error() const&& -> E const&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // precondition: has_value() = false - constexpr auto error() && -> E&& { return std::move(this->unex); } + constexpr auto error() && -> E&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } template requires std::is_copy_constructible_v && std::is_convertible_v @@ -1126,27 +1155,39 @@ namespace plg { constexpr void value() const& { if (!has_value()) { - throw bad_expected_access(error()); + PLUGIFY_THROW("bad expected access", bad_expected_access, std::as_const(error())); } } constexpr void value() && { if (!has_value()) { - throw bad_expected_access(std::move(error())); + PLUGIFY_THROW("bad expected access", bad_expected_access, std::move(error())); } } // precondition: has_value() = false - constexpr auto error() const& -> E const& { return this->unex; } + constexpr auto error() const& -> E const& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() & -> E& { return this->unex; } + constexpr auto error() & -> E& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return this->unex; + } // precondition: has_value() = false - constexpr auto error() const&& -> E const&& { return std::move(this->unex); } + constexpr auto error() const&& -> E const&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // precondition: has_value() = false - constexpr auto error() && -> E&& { return std::move(this->unex); } + constexpr auto error() && -> E&& { + PLUGIFY_ASSERT(!this->has_val, "requires the expected to contain an error"); + return std::move(this->unex); + } // monadic template>> @@ -1426,5 +1467,27 @@ namespace plg { }; }; -}// namespace plg -#endif \ No newline at end of file +} // namespace plg + +namespace std { + template + using expected = plg::expected; + + template + concept is_expected = std::same_as, expected >; + +#if PLUGIFY_COMPILER_CLANG + template + struct unexpected : public plg::unexpected { + using plg::unexpected::unexpected; + }; + template + unexpected(U) -> unexpected; +#else + template + using unexpected = plg::unexpected; +#endif + +} // namespace std + +#endif // !PLUGIFY_HAS_STD_EXPECTED \ No newline at end of file diff --git a/test/example_plugin/external/plugify/include/plg/flat_map.hpp b/test/example_plugin/external/plugify/include/plg/flat_map.hpp deleted file mode 100644 index 7b5f7b7..0000000 --- a/test/example_plugin/external/plugify/include/plg/flat_map.hpp +++ /dev/null @@ -1,780 +0,0 @@ -#pragma once - -#include "plg/macro.hpp" - -#ifdef __cpp_lib_flat_map -#include -namespace plg { - template> - using flat_map = std::flat_map; -} -#else -#include "plg/vector.hpp" - -namespace plg { - namespace detail { - template < typename T, typename U, typename = void > - struct is_transparent - : std::false_type {}; - - template < typename T, typename U > - struct is_transparent> - : std::true_type {}; - - template < typename T, typename U > - inline constexpr bool is_transparent_v = is_transparent::value; - - template - constexpr bool is_sorted(Iter first, Iter last, Compare comp) { - if (first != last) { - Iter next = first; - while (++next != last) { - if (comp(*next, *first)) { - return false; - } - ++first; - } - } - return true; - } - - template - constexpr bool is_sorted_unique(Iter first, Iter last, Compare comp) { - if (first != last) { - Iter next = first; - while (++next != last) { - if (!comp(*first, *next)) { - return false; - } - ++first; - } - } - return true; - } - - template - struct pair_compare : public Compare { - pair_compare() = default; - - explicit pair_compare(const Compare& compare) - : Compare(compare) {} - - bool operator()( - const typename Pair::first_type& l, - const typename Pair::first_type& r) const { - return Compare::operator()(l, r); - } - - bool operator()(const Pair& l, const Pair& r) const { - return Compare::operator()(l.first, r.first); - } - - bool operator()( - const typename Pair::first_type& l, - const Pair& r) const { - return Compare::operator()(l, r.first); - } - - bool operator()( - const Pair& l, - const typename Pair::first_type& r) const { - return Compare::operator()(l.first, r); - } - - template - requires (is_transparent_v) - bool operator()(const K& l, const Pair& r) const { - return Compare::operator()(l, r.first); - } - - template - requires (is_transparent_v) - bool operator()(const Pair& l, const K& r) const { - return Compare::operator()(l.first, r); - } - }; - - template - struct eq_compare : public Compare { - eq_compare() = default; - - explicit eq_compare(const Compare& compare) - : Compare(compare) {} - - template - bool operator()(const L& l, const R& r) const { - return !Compare::operator()(l, r) && !Compare::operator()(r, l); - } - }; - } // namespace detail - - struct sorted_range_t {}; - inline constexpr sorted_range_t sorted_range = sorted_range_t(); - - struct sorted_unique_range_t : public sorted_range_t {}; - inline constexpr sorted_unique_range_t sorted_unique_range = sorted_unique_range_t(); - - template, typename Container = std::vector>> - class flat_map { - public: - using key_type = Key; - using mapped_type = Value; - using value_type = typename Container::value_type; - - using size_type = typename Container::size_type; - using difference_type = typename Container::difference_type; - - using key_compare = Compare; - using container_type = Container; - - using reference = typename Container::reference; - using const_reference = typename Container::const_reference; - using pointer = typename Container::pointer; - using const_pointer = typename Container::const_pointer; - - using iterator = typename Container::iterator; - using const_iterator = typename Container::const_iterator; - using reverse_iterator = typename Container::reverse_iterator; - using const_reverse_iterator = typename Container::const_reverse_iterator; - - struct value_compare : private key_compare { - value_compare() = default; - - explicit value_compare(key_compare compare) - : key_compare(std::move(compare)) {} - - bool operator()(const value_type& l, const value_type& r) const { - return key_compare::operator()(l.first, r.first); - } - }; - - public: - flat_map() = default; - ~flat_map() = default; - - explicit flat_map(const Compare& c) - : _compare(c) {} - - template - explicit flat_map(const Allocator& a) - : _data(a) {} - - template - flat_map(const Compare& c, const Allocator& a) - : _compare(c), _data(a) {} - - template - flat_map(Iterator first, Iterator last) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Compare& c) - : _compare(c) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Allocator& a) - : _data(a) { - from_range(sorted_unique_range, first, last); - } - - template - flat_map(Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(first, last); - } - - template - flat_map(sorted_range_t, Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_range, first, last); - } - - template - flat_map(sorted_unique_range_t, Iterator first, Iterator last, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_unique_range, first, last); - } - - flat_map(std::initializer_list list) { - from_range(list.begin(), list.end()); - } - - flat_map(sorted_range_t, std::initializer_list list) { - from_range(sorted_range, list.begin(), list.end()); - } - - flat_map(sorted_unique_range_t, std::initializer_list list) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - flat_map(std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(list.begin(), list.end()); - } - - flat_map(sorted_range_t, std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(sorted_range, list.begin(), list.end()); - } - - flat_map(sorted_unique_range_t, std::initializer_list list, const Compare& c) - : _compare(c) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(list.begin(), list.end()); - } - - template - flat_map(sorted_range_t, std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(sorted_range, list.begin(), list.end()); - } - - template - flat_map(sorted_unique_range_t, std::initializer_list list, const Allocator& a) - : _data(a) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(list.begin(), list.end()); - } - - template - flat_map(sorted_range_t, std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_range, list.begin(), list.end()); - } - - template - flat_map(sorted_unique_range_t, std::initializer_list list, const Compare& c, const Allocator& a) - : _compare(c), _data(a) { - from_range(sorted_unique_range, list.begin(), list.end()); - } - - template - flat_map(flat_map&& other, const Allocator& a) - : _compare(std::move(other._compare)), _data(std::move(other._data), a) {} - - template - flat_map(const flat_map& other, const Allocator& a) - : _compare(other._compare), _data(other._data, a) {} - - flat_map(flat_map&& other) noexcept = default; - flat_map(const flat_map& other) = default; - - flat_map& operator=(flat_map&& other) noexcept = default; - flat_map& operator=(const flat_map& other) = default; - - flat_map& operator=(std::initializer_list list) { - flat_map(list).swap(*this); - return *this; - } - - iterator begin() noexcept(noexcept(std::declval().begin())) { - return _data.begin(); - } - - const_iterator begin() const - noexcept(noexcept(std::declval().begin())) { - return _data.begin(); - } - - const_iterator cbegin() const - noexcept(noexcept(std::declval().cbegin())) { - return _data.cbegin(); - } - - iterator end() noexcept(noexcept(std::declval().end())) { - return _data.end(); - } - - const_iterator end() const - noexcept(noexcept(std::declval().end())) { - return _data.end(); - } - - const_iterator cend() const - noexcept(noexcept(std::declval().cend())) { - return _data.cend(); - } - - reverse_iterator rbegin() noexcept(noexcept(std::declval().rbegin())) { - return _data.rbegin(); - } - - const_reverse_iterator rbegin() const - noexcept(noexcept(std::declval().rbegin())) { - return _data.rbegin(); - } - - const_reverse_iterator crbegin() const - noexcept(noexcept(std::declval().crbegin())) { - return _data.crbegin(); - } - - reverse_iterator rend() noexcept(noexcept(std::declval().rend())) { - return _data.rend(); - } - - const_reverse_iterator rend() const - noexcept(noexcept(std::declval().rend())) { - return _data.rend(); - } - - const_reverse_iterator crend() const - noexcept(noexcept(std::declval().crend())) { - return _data.crend(); - } - - bool empty() const - noexcept(noexcept(std::declval().empty())) { - return _data.empty(); - } - - size_type size() const - noexcept(noexcept(std::declval().size())) { - return _data.size(); - } - - size_type max_size() const - noexcept(noexcept(std::declval().max_size())) { - return _data.max_size(); - } - - size_type capacity() const - noexcept(noexcept(std::declval().capacity())) { - return _data.capacity(); - } - - void reserve(size_type capacity) { - _data.reserve(capacity); - } - - void shrink_to_fit() { - _data.shrink_to_fit(); - } - - mapped_type& operator[](key_type&& key) { - const iterator iter = find(key); - return iter != end() - ? iter->second - : emplace(std::move(key), mapped_type()).first->second; - } - - mapped_type& operator[](const key_type& key) { - const iterator iter = find(key); - return iter != end() - ? iter->second - : emplace(key, mapped_type()).first->second; - } - - mapped_type& at(const key_type& key) { - const iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - const mapped_type& at(const key_type& key) const { - const const_iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - template - requires (detail::is_transparent_v) - mapped_type& at(const K& key) { - const iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - template - requires (detail::is_transparent_v) - const mapped_type& at(const K& key) const { - const const_iterator iter = find(key); - PLUGIFY_ASSERT(iter != end(), "plg::flat_map::at(): key not found", std::out_of_range); - return iter->second; - } - - std::pair insert(value_type&& value) { - const iterator iter = lower_bound(value.first); - return iter == end() || _compare(value, *iter) - ? std::make_pair(_data.insert(iter, std::move(value)), true) - : std::make_pair(iter, false); - } - - std::pair insert(const value_type& value) { - const iterator iter = lower_bound(value.first); - return iter == end() || _compare(value, *iter) - ? std::make_pair(_data.insert(iter, value), true) - : std::make_pair(iter, false); - } - - iterator insert(const_iterator hint, value_type&& value) { - return (hint == begin() || _compare(*(hint - 1), value)) && (hint == end() || _compare(value, *hint)) - ? _data.insert(hint, std::move(value)) - : insert(std::move(value)).first; - } - - iterator insert(const_iterator hint, const value_type& value) { - return (hint == begin() || _compare(*(hint - 1), value)) && (hint == end() || _compare(value, *hint)) - ? _data.insert(hint, value) - : insert(value).first; - } - - template - std::pair insert_or_assign(key_type&& key, V&& value) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, std::move(key), std::forward(value)); - return {iter, true}; - } - (*iter).second = std::forward(value); - return {iter, false}; - } - - template - std::pair insert_or_assign(const key_type& key, V&& value) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, key, std::forward(value)); - return {iter, true}; - } - (*iter).second = std::forward(value); - return {iter, false}; - } - - template - void insert(Iterator first, Iterator last) { - insert_range(first, last); - } - - template - void insert(sorted_range_t, Iterator first, Iterator last) { - insert_range(sorted_range, first, last); - } - - void insert(std::initializer_list list) { - insert_range(list.begin(), list.end()); - } - - void insert(sorted_range_t, std::initializer_list list) { - insert_range(sorted_range, list.begin(), list.end()); - } - - template - std::pair emplace(Args&&... args) { - return insert(value_type(std::forward(args)...)); - } - - template - iterator emplace_hint(const_iterator hint, Args&&... args) { - return insert(hint, value_type(std::forward(args)...)); - } - - template - std::pair try_emplace(key_type&& key, Args&&... args) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, std::move(key), std::forward(args)...); - return {iter, true}; - } - return {iter, false}; - } - - template - std::pair try_emplace(const key_type& key, Args&&... args) { - iterator iter = lower_bound(key); - if (iter == end() || _compare(key, *iter)) { - iter = emplace_hint(iter, key, std::forward(args)...); - return {iter, true}; - } - return {iter, false}; - } - - void clear() noexcept(noexcept(std::declval().clear())) { - _data.clear(); - } - - iterator erase(const_iterator iter) { - return _data.erase(iter); - } - - iterator erase(const_iterator first, const_iterator last) { - return _data.erase(first, last); - } - - size_type erase(const key_type& key) { - const const_iterator iter = find(key); - return iter != end() - ? (erase(iter), 1) - : 0; - } - - void swap(flat_map& other) noexcept(std::is_nothrow_swappable_v && std::is_nothrow_swappable_v) { - using std::swap; - swap(_compare, other._compare); - swap(_data, other._data); - } - - size_type count(const key_type& key) const { - const const_iterator iter = find(key); - return iter != end() ? 1 : 0; - } - - template - requires (detail::is_transparent_v) - size_type count(const K& key) const { - const const_iterator iter = find(key); - return iter != end() ? 1 : 0; - } - - iterator find(const key_type& key) { - const iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - const_iterator find(const key_type& key) const { - const const_iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - template - requires (detail::is_transparent_v) - iterator find(const K& key) { - const iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - template - requires (detail::is_transparent_v) - const_iterator find(const K& key) const { - const const_iterator iter = lower_bound(key); - return iter != end() && !_compare(key, *iter) - ? iter - : end(); - } - - bool contains(const key_type& key) const { - return find(key) != end(); - } - - template - requires (detail::is_transparent_v) - bool contains(const K& key) const { - return find(key) != end(); - } - - std::pair equal_range(const key_type& key) { - return std::equal_range(begin(), end(), key, _compare); - } - - std::pair equal_range(const key_type& key) const { - return std::equal_range(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - std::pair equal_range(const K& key) { - return std::equal_range(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - std::pair equal_range(const K& key) const { - return std::equal_range(begin(), end(), key, _compare); - } - - iterator lower_bound(const key_type& key) { - return std::lower_bound(begin(), end(), key, _compare); - } - - const_iterator lower_bound(const key_type& key) const { - return std::lower_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - iterator lower_bound(const K& key) { - return std::lower_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - const_iterator lower_bound(const K& key) const { - return std::lower_bound(begin(), end(), key, _compare); - } - - iterator upper_bound(const key_type& key) { - return std::upper_bound(begin(), end(), key, _compare); - } - - const_iterator upper_bound(const key_type& key) const { - return std::upper_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - iterator upper_bound(const K& key) { - return std::upper_bound(begin(), end(), key, _compare); - } - - template - requires (detail::is_transparent_v) - const_iterator upper_bound(const K& key) const { - return std::upper_bound(begin(), end(), key, _compare); - } - - key_compare key_comp() const { - return _compare; - } - - value_compare value_comp() const { - return value_compare(key_comp()); - } - - private: - template - void from_range(Iter first, Iter last) { - assert(_data.empty()); - _data.insert(_data.end(), first, last); - std::sort(_data.begin(), _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void from_range(sorted_range_t, Iter first, Iter last) { - assert(_data.empty()); - assert(detail::is_sorted(first, last, value_comp())); - _data.insert(_data.end(), first, last); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void from_range(sorted_unique_range_t, Iter first, Iter last) { - assert(_data.empty()); - assert(detail::is_sorted_unique(first, last, value_comp())); - _data.insert(_data.end(), first, last); - } - - private: - template - void insert_range(Iter first, Iter last) { - const auto mid_iter = _data.insert(_data.end(), first, last); - std::sort(mid_iter, _data.end(), value_comp()); - std::inplace_merge(_data.begin(), mid_iter, _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - template - void insert_range(sorted_range_t, Iter first, Iter last) { - assert(detail::is_sorted(first, last, value_comp())); - const auto mid_iter = _data.insert(_data.end(), first, last); - std::inplace_merge(_data.begin(), mid_iter, _data.end(), value_comp()); - _data.erase( - std::unique(_data.begin(), _data.end(), - detail::eq_compare(value_comp())), - _data.end()); - } - - private: - PLUGIFY_NO_UNIQUE_ADDRESS - detail::pair_compare _compare; - container_type _data; - }; - - template - void swap( - flat_map& l, - flat_map& r) noexcept(noexcept(l.swap(r))) { - l.swap(r); - } - - template - bool operator==( - const flat_map& l, - const flat_map& r) { - return l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin()); - } - - template - auto operator<=>( - const flat_map& l, - const flat_map& r) { - if (l.size() < r.size()) { - return std::partial_ordering::less; - } else if (l.size() > r.size()) { - return std::partial_ordering::greater; - } else { - if (std::lexicographical_compare(l.cbegin(), l.cend(), r.cbegin(), r.cend())) { - return std::partial_ordering::less; - } else { - return std::partial_ordering::greater; - } - } - } - - template, typename Container = plg::vector>> - using map = flat_map; - -}// namespace plg -#endif \ No newline at end of file diff --git a/test/example_plugin/external/plugify/include/plg/format.hpp b/test/example_plugin/external/plugify/include/plg/format.hpp index 94e5bdb..9abb9fe 100644 --- a/test/example_plugin/external/plugify/include/plg/format.hpp +++ b/test/example_plugin/external/plugify/include/plg/format.hpp @@ -1,12 +1,19 @@ #pragma once -#include "plg/macro.hpp" - -#ifdef __cpp_lib_format +#include "plg/config.hpp" +#if __has_include() #include +#if defined(__cpp_lib_format) && __cpp_lib_format >= 201907L +#define PLUGIFY_HAS_STD_FORMAT 1 +#else +#define PLUGIFY_HAS_STD_FORMAT 0 +#endif +#else +#define PLUGIFY_HAS_STD_FORMAT 0 +#endif -#else // __cpp_lib_format +#if !PLUGIFY_HAS_STD_FORMAT // Define FMT_FORMAT_H externally to force a difference location for {fmt} #ifndef FMT_FORMAT_H @@ -21,6 +28,6 @@ namespace std { using namespace fmt; using namespace fmt::detail; -} +} // namespace std -#endif // __cpp_lib_format +#endif // !PLUGIFY_HAS_STD_FORMAT diff --git a/test/example_plugin/external/plugify/include/plg/guards.hpp b/test/example_plugin/external/plugify/include/plg/guards.hpp new file mode 100644 index 0000000..4691341 --- /dev/null +++ b/test/example_plugin/external/plugify/include/plg/guards.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include "plg/config.hpp" + +namespace plg { +#if PLUGIFY_HAS_EXCEPTIONS + template + struct exception_guard_exceptions { + exception_guard_exceptions() = delete; + + constexpr explicit exception_guard_exceptions(Rollback rollback) + : _rollback(std::move(rollback)) + , _completed(false) { + } + + constexpr exception_guard_exceptions( + exception_guard_exceptions&& other + ) noexcept(std::is_nothrow_move_constructible_v) + : _rollback(std::move(other._rollback)) + , _completed(other._completed) { + other._completed = true; + } + + exception_guard_exceptions(const exception_guard_exceptions&) = delete; + exception_guard_exceptions& operator=(const exception_guard_exceptions&) = delete; + exception_guard_exceptions& operator=(exception_guard_exceptions&&) = delete; + + constexpr void complete() noexcept { + _completed = true; + } + + constexpr ~exception_guard_exceptions() { + if (!_completed) { + _rollback(); + } + } + + private: + PLUGIFY_NO_UNIQUE_ADDRESS Rollback _rollback; + bool _completed; + }; + + template + using exception_guard = exception_guard_exceptions; +#else + template + struct exception_guard_noexceptions { + exception_guard_noexceptions() = delete; + + constexpr explicit exception_guard_noexceptions(Rollback) { + } + + constexpr exception_guard_noexceptions( + exception_guard_noexceptions&& other + ) noexcept(std::is_nothrow_move_constructible_v) + : _completed(other._completed) { + other._completed = true; + } + + exception_guard_noexceptions(const exception_guard_noexceptions&) = delete; + exception_guard_noexceptions& operator=(const exception_guard_noexceptions&) = delete; + exception_guard_noexceptions& operator=(exception_guard_noexceptions&&) = delete; + + constexpr void complete() noexcept { + _completed = true; + } + + constexpr ~exception_guard_noexceptions() { + PLUGIFY_ASSERT(_completed, "exception_guard not completed with exceptions disabled"); + } + + private: + bool _completed = false; + }; + + template + using exception_guard = exception_guard_noexceptions; +#endif + + template + constexpr exception_guard make_exception_guard(Rollback rollback) { + return exception_guard(std::move(rollback)); + } + + template + class scope_guard { + PLUGIFY_NO_UNIQUE_ADDRESS Func _func; + + public: + constexpr explicit scope_guard(Func func) + : _func(std::move(func)) { + } + + constexpr ~scope_guard() { + _func(); + } + + scope_guard(const scope_guard&) = delete; + scope_guard& operator=(const scope_guard&) = delete; + scope_guard& operator=(scope_guard&&) = delete; + scope_guard(scope_guard&&) = delete; + }; + + template + constexpr scope_guard make_scope_guard(Func func) { + return scope_guard(std::move(func)); + } +} diff --git a/test/example_plugin/external/plugify/include/plg/hash.hpp b/test/example_plugin/external/plugify/include/plg/hash.hpp index 296436a..4028e57 100644 --- a/test/example_plugin/external/plugify/include/plg/hash.hpp +++ b/test/example_plugin/external/plugify/include/plg/hash.hpp @@ -34,16 +34,36 @@ namespace plg { } }; + // --- Hash traits depending on pointer size --- + template + struct hash_traits; + + template <> + struct hash_traits<4> { // 32-bit + static constexpr std::size_t fnv_basis = 0x811C9DC5u; + static constexpr std::size_t fnv_prime = 0x01000193u; + static constexpr std::size_t golden_ratio = 0x9e3779b9u; + }; + + template <> + struct hash_traits<8> { // 64-bit + static constexpr std::size_t fnv_basis = 0xcbf29ce484222325ULL; + static constexpr std::size_t fnv_prime = 0x100000001b3ULL; + static constexpr std::size_t golden_ratio = 0x9e3779b97f4a7c15ULL; + }; + + using active_hash_traits = hash_traits; + struct case_insensitive_hash { using is_transparent = void; // Enables heterogeneous lookup template auto operator()(const T& str_like) const noexcept { std::string_view str = str_like; - std::size_t hash = 0xcbf29ce484222325; // FNV-1a 64-bit basis - for (char c : str) { + std::size_t hash = active_hash_traits::fnv_basis; // FNV-1a + for (const char& c : str) { hash ^= static_cast(std::tolower(static_cast(c))); - hash *= 0x100000001b3; + hash *= active_hash_traits::fnv_prime; } return hash; } @@ -77,8 +97,7 @@ namespace plg { template inline void hash_combine(std::size_t& seed, const T& v) { std::hash hasher; - // 0x9e3779b97f4a7c15 is 64-bit golden ratio constant - seed ^= hasher(v) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2); + seed ^= hasher(v) + active_hash_traits::golden_ratio + (seed << 6) + (seed >> 2); } template @@ -94,5 +113,4 @@ namespace plg { return hash_combine_all(p.first, p.second); } }; - } diff --git a/test/example_plugin/external/plugify/include/plg/inplace_vector.hpp b/test/example_plugin/external/plugify/include/plg/inplace_vector.hpp new file mode 100644 index 0000000..71292c8 --- /dev/null +++ b/test/example_plugin/external/plugify/include/plg/inplace_vector.hpp @@ -0,0 +1,772 @@ +#pragma once + +#include "plg/config.hpp" + +#if __has_include() +#include +#if defined(__cpp_lib_inplace_vector) && __cpp_lib_inplace_vector >= 202406L +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 1 +#else +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 0 +#endif +#else +#define PLUGIFY_HAS_STD_INPLACE_VECTOR 0 +#endif + +#if !PLUGIFY_HAS_STD_INPLACE_VECTOR +#include +#include +#include +#include +#include +#include + +#if PLUGIFY_CPP_VERSION >= 202002L +#include +#include +#endif + +#ifndef PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF +#if defined(__cpp_impl_trivially_relocatable) && defined(__cpp_lib_trivially_relocatable) +#define PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(x) [[trivially_relocatable(x)]] +#else +#define PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(x) +#endif // __cpp_impl_trivially_relocatable +#endif // PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF + +// from https://github.com/Quuxplusone/SG14 +namespace plg { + namespace detail { + + template && std::is_copy_assignable_v), + bool = (std::is_move_constructible_v && std::is_move_assignable_v)> + struct ipvbase_assignable { + // Base for copyable types + }; + + template + struct ipvbase_assignable { + // Base for immobile types like std::mutex + explicit ipvbase_assignable() = default; + ipvbase_assignable(ipvbase_assignable&&) = delete; + ipvbase_assignable(const ipvbase_assignable&) = delete; + void operator=(ipvbase_assignable&&) = delete; + void operator=(const ipvbase_assignable&) = delete; + ~ipvbase_assignable() = default; + }; + + template + struct ipvbase_assignable { + explicit ipvbase_assignable() = default; + ipvbase_assignable(const ipvbase_assignable&) = delete; + ipvbase_assignable(ipvbase_assignable&&) = default; + void operator=(const ipvbase_assignable&) = delete; + ipvbase_assignable& operator=(ipvbase_assignable&&) = default; + ~ipvbase_assignable() = default; + }; + + template + struct PLUGIFY_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF(std::is_trivially_relocatable_v) ipvbase + { + size_t _size = 0; + union { + [[maybe_unused]] char _dummy; + T _data[N]; + }; + + constexpr T *base_data() { return _data; } + constexpr const T *base_data() const { return _data; } + constexpr void set_size(size_t n) { _size = n; } + + constexpr explicit ipvbase() noexcept {} + ipvbase(const ipvbase& rhs) + noexcept(std::is_nothrow_copy_constructible_v) + { + if constexpr (std::is_trivially_copy_constructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else { + std::uninitialized_copy_n(rhs._data, rhs._size, _data); + _size = rhs._size; + } + } + ipvbase(ipvbase&& rhs) + noexcept(std::is_nothrow_move_constructible_v +#if defined(__cpp_lib_trivially_relocatable) + || std::is_trivially_relocatable_v +#endif // __cpp_lib_trivially_relocatable + ) + { + if constexpr (std::is_trivially_move_constructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); +#if defined(__cpp_lib_trivially_relocatable) + } else if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_n(rhs._data, rhs._size, _data); + _size = rhs._size; + rhs._size = 0; +#endif // __cpp_lib_trivially_relocatable + } else { + std::uninitialized_move_n(rhs._data, rhs._size, _data); + _size = rhs._size; + } + } + void operator=(const ipvbase& rhs) + noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_copy_assignable_v) + { + if constexpr (std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v && std::is_trivially_destructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else if (this == std::addressof(rhs)) { + // do nothing + } else if (rhs._size <= _size) { + std::copy(rhs._data, rhs._data + rhs._size, _data); + std::destroy(_data + rhs._size, _data + _size); + _size = rhs._size; + } else { + std::copy(rhs._data, rhs._data + _size, _data); + std::uninitialized_copy(rhs._data + _size, rhs._data + rhs._size, _data + _size); + _size = rhs._size; + } + } + void operator=(ipvbase&& rhs) + noexcept(std::is_nothrow_move_constructible_v && std::is_nothrow_move_assignable_v) + { + if constexpr (std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v && std::is_trivially_destructible_v) { + std::memmove((void*)this, (const void*)std::addressof(rhs), sizeof(ipvbase)); + } else if (this == std::addressof(rhs)) { + // do nothing + } else if (rhs._size <= _size) { + std::move(rhs._data, rhs._data + rhs._size, _data); + std::destroy(_data + rhs._size, _data + _size); + _size = rhs._size; + } else { + std::move(rhs._data, rhs._data + _size, _data); +#if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate(rhs._data + _size, rhs._data + rhs._size, _data + _size); + std::swap(rhs._size, _size); + return; + } +#endif // __cpp_lib_trivially_relocatable + std::uninitialized_move(rhs._data + _size, rhs._data + rhs._size, _data + _size); + _size = rhs._size; + } + } + +#if __cpp_concepts >= 202002L + ipvbase(const ipvbase&) requires std::is_trivially_copy_constructible_v = default; + ipvbase(ipvbase&&) requires std::is_trivially_move_constructible_v = default; + ipvbase& operator=(const ipvbase&) requires std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v && std::is_trivially_destructible_v = default; + ipvbase& operator=(ipvbase&&) requires std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v && std::is_trivially_destructible_v = default; + ~ipvbase() requires std::is_trivially_destructible_v = default; +#endif // __cpp_concepts >= 202002L + +#if PLUGIFY_CPP_VERSION >= 202002L + constexpr +#endif // PLUGIFY_CPP_VERSION >= 202002L + ~ipvbase() { + std::destroy(_data, _data + _size); + } + }; + + template + struct ipvbase_zero { + static constexpr size_t _size = 0; + constexpr T *base_data() { return nullptr; } + constexpr const T *base_data() const { return nullptr; } + constexpr void set_size(size_t) { } + }; + + template + struct ipvbase_trivial { + size_t _size = 0; + union { + [[maybe_unused]] char _dummy; + T _data[N]; + }; + constexpr explicit ipvbase_trivial() {} + constexpr T *base_data() { return _data; } + constexpr const T *base_data() const { return _data; } + constexpr void set_size(size_t n) { _size = n; } + }; + + template + using ipvbase_t = std::conditional_t< + N == 0, + ipvbase_zero, + std::conditional_t< + std::is_trivially_copyable_v, + ipvbase_trivial, + ipvbase + > + >; + } // namespace detail + + template + class inplace_vector : detail::ipvbase_assignable, detail::ipvbase_t { + using detail::ipvbase_t::_size; + using detail::ipvbase_t::set_size; + public: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = T*; + using const_iterator = const T*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // [inplace.vector.cons] + + inplace_vector() = default; + inplace_vector(inplace_vector&&) = default; + inplace_vector(const inplace_vector&) = default; + inplace_vector& operator=(inplace_vector&&) = default; + inplace_vector& operator=(const inplace_vector&) = default; + inplace_vector& operator=(std::initializer_list il) + requires std::is_copy_constructible_v + { + assign(il.begin(), il.end()); + return *this; + } + + constexpr inplace_vector(std::initializer_list il) + requires std::copy_constructible : inplace_vector(il.begin(), il.end()) { } + constexpr explicit inplace_vector(size_t n) + requires std::default_initializable + { + if (n > N) { + throw_bad_alloc(); + } + std::uninitialized_value_construct_n(data(), n); + set_size(n); + } + constexpr explicit inplace_vector(size_t n, const value_type& value) + requires std::copy_constructible + { + assign(n, value); + } + + template + requires std::constructible_from::value_type> + constexpr explicit inplace_vector(InputIterator first, InputIterator last) + { + if constexpr (std::random_access_iterator) { + size_t n = static_cast(std::distance(first, last)); + if (n > N) { + throw_bad_alloc(); + } + std::uninitialized_copy_n(first, n, data()); + set_size(n); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } + } + } + + constexpr void assign(std::initializer_list il) + requires std::is_copy_constructible_v + { + assign(il.begin(), il.end()); + } + + constexpr void assign(size_t n, const value_type& value) + requires std::is_copy_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::fill_n(data(), n, value); + std::destroy(data() + n, data() + _size); + } else { + std::fill_n(data(), _size, value); + std::uninitialized_fill_n(data() + _size, n - _size, value); + } + set_size(n); + } + + template + requires std::is_constructible_v::value_type> + constexpr void assign(InputIterator first, InputIterator last) { + const size_type n = static_cast(std::distance(first, last)); + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::copy(first, last, data()); + std::destroy(data() + n, data() + _size); + } else { + std::copy(first, first + _size, data()); + std::uninitialized_copy(first + _size, last, data() + _size); + } + set_size(n); + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + constexpr explicit inplace_vector(std::from_range_t, R&& rg) { + if constexpr (std::ranges::sized_range) { + size_t n = std::ranges::size(rg); + if (n > N) { + throw_bad_alloc(); + } + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, data(), std::unreachable_sentinel); + set_size(n); + } else { + for (auto&& e : rg) { + emplace_back(decltype(e)(e)); + } + } + } + + template + requires std::convertible_to, value_type> + constexpr void assign_range(R&& rg) { + auto first = std::ranges::begin(rg); + auto last = std::ranges::end(rg); + size_t n = std::ranges::size(rg); + if (n > N) { + throw_bad_alloc(); + } else if (_size >= n) { + std::ranges::copy(first, last, data()); + std::destroy(data() + n, data() + _size); + } else { + auto mid = std::ranges::next(first, _size, last); + std::ranges::copy(first, mid, data()); + std::ranges::uninitialized_copy(mid, last, data() + _size); + } + set_size(n); + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + // iterators + + constexpr iterator begin() noexcept { return data(); } + constexpr iterator end() noexcept { return data() + _size; } + constexpr const_iterator begin() const noexcept { return data(); } + constexpr const_iterator end() const noexcept { return data() + _size; } + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + constexpr const_iterator cbegin() const noexcept { return data(); } + constexpr const_iterator cend() const noexcept { return data() + _size; } + constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + constexpr void resize(size_type n) + requires std::is_default_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (n < _size) { + std::destroy(data() + n, data() + _size); + set_size(n); + } else { + std::uninitialized_value_construct(data() + _size, data() + n); + set_size(_size + n); + } + } + + constexpr void resize(size_type n, const value_type& value) + requires std::is_copy_constructible_v + { + if (n > N) { + throw_bad_alloc(); + } else if (n < _size) { + std::destroy(data() + n, data() + _size); + set_size(n); + } else { + std::uninitialized_fill(data() + _size, data() + n, value); + set_size(_size + n); + } + } + + static constexpr void reserve(size_type n) { + if (n > N) { + throw_bad_alloc(); + } + } + static constexpr void shrink_to_fit() noexcept {} + + // element access + + constexpr reference operator[](size_type pos) { + PLUGIFY_ASSERT(pos < size(), "index out of bounds"); + return data()[pos]; + } + constexpr reference front() { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[0]; + } + constexpr reference back() { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[_size - 1]; + } + + constexpr const_reference operator[](size_type pos) const { + PLUGIFY_ASSERT(pos < size(), "index out of bounds"); + return data()[pos]; + } + constexpr const_reference front() const { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[0]; + } + constexpr const_reference back() const { + PLUGIFY_ASSERT(!empty(), "called on an empty vector"); + return data()[_size - 1]; + } + + constexpr reference at(size_type i) { + if (i >= _size) { + throw_out_of_range(); + } + return data()[i]; + } + constexpr const_reference at(size_type i) const { + if (i >= _size) { + throw_out_of_range(); + } + return data()[i]; + } + + // [inplace.vector.data] + + constexpr T* data() noexcept { return this->base_data(); } + constexpr const T* data() const noexcept { return this->base_data(); } + constexpr size_type size() const noexcept { return _size; } + static constexpr size_type max_size() noexcept { return N; } + static constexpr size_type capacity() noexcept { return N; } + [[nodiscard]] constexpr bool empty() const noexcept { return _size == 0; }; + + // [inplace.vector.modifiers] + + template + requires std::is_constructible_v + value_type& unchecked_emplace_back(Args&&... args) { + // Precondition: (_size < N) + value_type* p = data() + _size; + p = std::construct_at(p, std::forward(args)...); + set_size(_size + 1); + return *p; + } + value_type& unchecked_push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return unchecked_emplace_back(value); + } + value_type& unchecked_push_back(value_type&& value) + requires std::is_move_constructible_v + { + return unchecked_emplace_back(static_cast(value)); + } + + template + requires std::is_constructible_v + constexpr value_type* try_emplace_back(Args&&... args) { + if (_size == N) { + return nullptr; + } + return std::addressof(unchecked_emplace_back(static_cast(args)...)); + } + constexpr value_type* try_push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return try_emplace_back(value); + } + constexpr value_type* try_push_back(value_type&& value) + requires std::is_move_constructible_v + { + return try_emplace_back(static_cast(value)); + } + + template + requires std::is_constructible_v + value_type& emplace_back(Args&&... args) { + if (_size == N) { + throw_bad_alloc(); + } + return unchecked_emplace_back(static_cast(args)...); + } + value_type& push_back(const value_type& value) + requires std::is_copy_constructible_v + { + return emplace_back(value); + } + value_type& push_back(value_type&& value) + requires std::is_move_constructible_v + { + return emplace_back(static_cast(value)); + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + constexpr void append_range(R&& rg) { + for (auto&& e : rg) { + emplace_back(static_cast(e)); + } + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + void pop_back() { + std::destroy_at(data() + _size - 1); + set_size(_size - 1); + } + + template + requires std::is_constructible_v + iterator emplace(const_iterator pos, Args&&... args) { + auto it = iterator(pos); + emplace_back(static_cast(args)...); + std::rotate(it, end() - 1, end()); + return it; + } + iterator insert(const_iterator pos, const value_type& value) + requires std::is_copy_constructible_v + { + return emplace(pos, value); + } + iterator insert(const_iterator pos, value_type&& value) + requires std::is_move_constructible_v + { + return emplace(pos, static_cast(value)); + } + + iterator insert(const_iterator pos, size_type n, const value_type& value) + requires std::is_copy_constructible_v + { + if (N - _size < n) { + throw_bad_alloc(); + } + auto it = iterator(pos); + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::uninitialized_fill_n(it, n, value); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::uninitialized_fill_n(oldend, n, value); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + return it; + } + + template + requires (std::is_constructible_v::value_type> && !std::is_const_v) + iterator insert(const_iterator pos, InputIterator first, InputIterator last) { + auto it = iterator(pos); + auto oldend = end(); + if constexpr (std::random_access_iterator) { + size_type n = static_cast(std::distance(first, last)); + if (N - _size < n) { + throw_bad_alloc(); + } + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::uninitialized_copy_n(first, n, it); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::uninitialized_copy_n(first, n, oldend); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } + std::rotate(it, oldend, end()); + } + return it; + } + + #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + template + requires std::convertible_to, value_type> + iterator insert_range(const_iterator pos, R&& rg) { + auto it = iterator(pos); + auto oldend = end(); + if constexpr (std::ranges::sized_range) { + size_type n = std::ranges::size(rg); + if (N - _size < n) { + throw_bad_alloc(); + } + #if defined(__cpp_lib_trivially_relocatable) + // Open a window and fill in-place; if filling fails, close the window again. + if constexpr (std::is_trivially_relocatable_v) { + std::uninitialized_relocate_backward(it, oldend, oldend + n); + try { + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, it, std::unreachable_sentinel); + set_size(_size + n); + } catch (...) { + std::uninitialized_relocate(it + n, oldend + n, it); + throw; + } + return it; + } + #endif + // Fill at the end of the vector, then rotate into place. + std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, oldend, std::unreachable_sentinel); + set_size(_size + n); + std::rotate(it, oldend, oldend + n); + } else { + auto [rgend, newend] = std::ranges::uninitialized_copy(rg, std::ranges::subrange(oldend, data() + N)); + if (rgend != std::ranges::end(rg)) { + std::destroy(oldend, newend); + throw_bad_alloc(); + } else { + set_size(newend - data()); + std::rotate(it, oldend, newend); + } + } + return it; + } + #endif // __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L + + iterator insert(const_iterator pos, std::initializer_list il) + requires (std::is_copy_constructible_v && !std::is_const_v) + { + return insert(pos, il.begin(), il.end()); + } + + iterator erase(const_iterator pos) + requires (!std::is_const_v) + { + auto it = iterator(pos); + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::destroy_at(it); + std::uninitialized_relocate(it + 1, oldend, it); + set_size(_size - 1); + return it; + } + #endif + std::move(it + 1, oldend, it); + std::destroy_at(oldend - 1); + set_size(_size - 1); + return it; + } + + iterator erase(const_iterator first, const_iterator last) + requires (!std::is_const_v) + { + auto ifirst = iterator(first); + auto ilast = iterator(last); + auto n = static_cast(std::distance(ifirst, ilast)); + if (n != 0) { + auto oldend = end(); + #if defined(__cpp_lib_trivially_relocatable) + if constexpr (std::is_trivially_relocatable_v) { + std::destroy(ifirst, ilast); + std::uninitialized_relocate(ilast, oldend, ifirst); + set_size(_size - n); + return ifirst; + } + #endif // __cpp_lib_trivially_relocatable + std::destroy(std::move(ilast, oldend, ifirst), oldend); + set_size(_size - n); + } + return ifirst; + } + + constexpr void clear() noexcept { + std::destroy(data(), data() + _size); + set_size(0); + } + + constexpr void swap(inplace_vector& b) + noexcept(N == 0 || (std::is_nothrow_swappable_v && std::is_nothrow_move_constructible_v)) + requires (!std::is_const_v) + { + auto& a = *this; + if (a._size < b._size) { + b.swap(a); + } else { + std::swap_ranges(a.data(), a.data() + b._size, b.data()); + #if defined(__cpp_lib_trivially_relocatable) + size_t n = a._size; + a.set_size(b._size); + std::uninitialized_relocate(a.data() + b._size, a.data() + n, b.data() + b._size); + b.set_size(n); + #else + std::uninitialized_move(a.data() + b._size, a.data() + a._size, b.data() + b._size); + std::destroy(a.data() + b._size, a.data() + a._size); + if constexpr (N != 0) { + std::swap(a._size, b._size); + } + #endif + } + } + + friend constexpr void swap(inplace_vector& a, inplace_vector& b) noexcept(noexcept(a.swap(b))) { + a.swap(b); + } + + constexpr friend bool operator==(const inplace_vector& lhs, const inplace_vector& rhs) { + if (lhs.size() != rhs.size()) return false; + return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + } + + #if __cpp_impl_three_way_comparison >= 201907L + constexpr friend auto operator<=>(const inplace_vector& lhs, const inplace_vector& rhs) { + return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + #else + constexpr friend bool operator<(const inplace_vector& a, const inplace_vector& b) { + const T* adata = a.data(); + const T* bdata = b.data(); + size_t n = (a._size < b._size) ? a._size : b._size; + for (size_t i = 0; i < n; ++i) { + if (adata[i] < bdata[i]) { + return true; + } else if (bdata[i] < adata[i]) { + return false; + } + } + return (a._size < b._size); + } + constexpr friend bool operator>(const inplace_vector& a, const inplace_vector& b) { return (b < a); } + constexpr friend bool operator<=(const inplace_vector& a, const inplace_vector& b) { return !(b < a); } + constexpr friend bool operator>=(const inplace_vector& a, const inplace_vector& b) { return !(a < b); } + constexpr friend bool operator!=(const inplace_vector& a, const inplace_vector& b) { return !(a == b); } + #endif + + private: + [[noreturn]] static void throw_bad_alloc() { + PLUGIFY_THROW("memory size would exceed capacity()", std::bad_alloc); + } + + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); + } + }; +} // namespace plg + +namespace std { + template + using inplace_vector = plg::inplace_vector; +} // namespace std + +#endif \ No newline at end of file diff --git a/test/example_plugin/external/plugify/include/plg/numerics.hpp b/test/example_plugin/external/plugify/include/plg/numerics.hpp index 9dd82f3..f975f3d 100644 --- a/test/example_plugin/external/plugify/include/plg/numerics.hpp +++ b/test/example_plugin/external/plugify/include/plg/numerics.hpp @@ -1,7 +1,6 @@ #pragma once -#include "plg/string.hpp" -#include "plg/vector.hpp" +#include "plg/config.hpp" namespace plg { PLUGIFY_WARN_PUSH() diff --git a/test/example_plugin/external/plugify/include/plg/path.hpp b/test/example_plugin/external/plugify/include/plg/path.hpp index afc3d6e..7c44925 100644 --- a/test/example_plugin/external/plugify/include/plg/path.hpp +++ b/test/example_plugin/external/plugify/include/plg/path.hpp @@ -4,13 +4,15 @@ #include #include +#include "plg/config.hpp" + namespace plg { using path_view = std::basic_string_view; using path_string = std::filesystem::path::string_type; using path_char = path_string::value_type; using path_diff_t = path_string::difference_type; -#if _WIN32 +#if PLUGIFY_PLATFORM_WINDOWS #define PLUGIFY_PATH_LITERAL(x) L##x #else #define PLUGIFY_PATH_LITERAL(x) x @@ -19,15 +21,14 @@ namespace plg { template bool insensitive_equals(const path_char lhs, const path_char rhs) { if constexpr (std::is_same_v) { - return std::towlower(lhs) == rhs; // NOLINT + return std::towlower(static_cast(lhs)) == std::towlower(static_cast(rhs)); } else { - return std::tolower(lhs) == rhs; + return std::tolower(static_cast(lhs)) == std::tolower(static_cast(rhs)); } } inline bool insensitive_equals(const path_view lhs, const path_view rhs) { - return lhs.size() == rhs.size() - && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); + return lhs.size() == rhs.size() && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), insensitive_equals); } inline path_view extension_view(const std::filesystem::path& path, size_t extension_size) { @@ -47,7 +48,7 @@ namespace plg { } inline auto as_string(const std::filesystem::path& p) { -#if _WIN32 +#if PLUGIFY_PLATFORM_WINDOWS return p.string(); // returns std::string by value #else return p.native(); // returns const std::string& diff --git a/test/example_plugin/external/plugify/include/plg/plugin.hpp b/test/example_plugin/external/plugify/include/plg/plugin.hpp index 76f2286..550b623 100644 --- a/test/example_plugin/external/plugify/include/plg/plugin.hpp +++ b/test/example_plugin/external/plugify/include/plg/plugin.hpp @@ -181,15 +181,15 @@ namespace plg { namespace plg { namespace raw { struct vector { - [[maybe_unused]] uint8_t padding[sizeof(plg::vector)]{}; + uint8_t pad[sizeof(plg::vector)]{}; }; struct string { - [[maybe_unused]] uint8_t padding[sizeof(plg::string)]{}; + uint8_t pad[sizeof(plg::string)]{}; }; struct variant { - [[maybe_unused]] uint8_t padding[sizeof(plg::any)]{}; + uint8_t pad[sizeof(plg::any)]{}; }; } // namespace raw diff --git a/test/example_plugin/external/plugify/include/plg/split_buffer.hpp b/test/example_plugin/external/plugify/include/plg/split_buffer.hpp new file mode 100644 index 0000000..0568d15 --- /dev/null +++ b/test/example_plugin/external/plugify/include/plg/split_buffer.hpp @@ -0,0 +1,907 @@ +#pragma once + +#include "plg/config.hpp" +#include "plg/concepts.hpp" + +namespace plg { + template class Layout> + class split_buffer; + + template + class split_buffer_pointer_layout { + protected: + using value_type = T; + using allocator_type = Allocator; + using alloc_rr = std::remove_reference_t; + using alloc_traits = std::allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using constIterator = const_pointer; + using sentinel_type = pointer; + + public: + constexpr split_buffer_pointer_layout() + : _back_cap(nullptr) { + } + + constexpr explicit split_buffer_pointer_layout(const allocator_type& alloc) + : _back_cap(nullptr) + , _alloc(alloc) { + } + + constexpr pointer front_cap() noexcept { + return _front_cap; + } + + constexpr const_pointer front_cap() const noexcept { + return _front_cap; + } + + constexpr pointer begin() noexcept { + return _begin; + } + + constexpr const_pointer begin() const noexcept { + return _begin; + } + + constexpr pointer end() noexcept { + return _end; + } + + constexpr pointer end() const noexcept { + return _end; + } + + constexpr size_type size() const noexcept { + return static_cast(_end - _begin); + } + + constexpr bool empty() const noexcept { + return _begin == _end; + } + + constexpr size_type capacity() const noexcept { + return static_cast(_back_cap - _front_cap); + } + + constexpr allocator_type& get_allocator() noexcept { + return _alloc; + } + + constexpr const allocator_type& get_allocator() const noexcept { + return _alloc; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type + // deduction, not explicit types. + constexpr sentinel_type raw_sentinel() const noexcept { + return _end; + } + + constexpr sentinel_type raw_capacity() const noexcept { + return _back_cap; + } + + constexpr void set_data(pointer new_first) noexcept { + _front_cap = new_first; + } + + constexpr void + set_valid_range(pointer new_begin, pointer new_end) noexcept { + _begin = new_begin; + _end = new_end; + } + + constexpr void + set_valid_range(pointer new_begin, size_type new_size) noexcept { + _begin = new_begin; + _end = _begin + new_size; + } + + constexpr void set_sentinel(pointer new_end) noexcept { + PLUGIFY_ASSERT(_front_cap <= new_end, "new_end cannot precede _front_cap"); + _end = new_end; + } + + constexpr void set_sentinel(size_type new_size) noexcept { + _end = _begin + new_size; + } + + constexpr void set_capacity(size_type new_capacity) noexcept { + _back_cap = _front_cap + new_capacity; + } + + constexpr void set_capacity(pointer new_capacity) noexcept { + _back_cap = new_capacity; + } + + constexpr size_type front_spare() const noexcept { + return static_cast(_begin - _front_cap); + } + + constexpr size_type back_spare() const noexcept { + return static_cast(_back_cap - _end); + } + + constexpr reference back() noexcept { + return *(_end - 1); + } + + constexpr const_reference back() const noexcept { + return *(_end - 1); + } + + constexpr void swap_without_allocator( + split_buffer_pointer_layout< + split_buffer, + value_type, + alloc_rr&>& other + ) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_back_cap, other._back_cap); + std::swap(_end, other._end); + } + + constexpr void swap(split_buffer_pointer_layout& other) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_back_cap, other._back_cap); + std::swap(_end, other._end); + swap_allocator(_alloc, other._alloc); + } + + constexpr void reset() noexcept { + _front_cap = nullptr; + _begin = nullptr; + _end = nullptr; + _back_cap = nullptr; + } + + constexpr void copy_without_alloc( + const split_buffer_pointer_layout& other + ) noexcept(std::is_nothrow_copy_assignable::value) { + _front_cap = other._front_cap; + _begin = other._begin; + _end = other._end; + _back_cap = other._back_cap; + } + + private: + pointer _front_cap = nullptr; + pointer _begin = nullptr; + pointer _end = nullptr; + pointer _back_cap = nullptr; + PLUGIFY_NO_UNIQUE_ADDRESS allocator_type _alloc; + + template + friend class split_buffer_pointer_layout; + }; + + template + class split_buffer_size_layout { + protected: + using value_type = T; + using allocator_type = Allocator; + using alloc_rr = std::remove_reference_t; + using alloc_traits = std::allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using constIterator = const_pointer; + using sentinel_type = size_type; + + public: + constexpr split_buffer_size_layout() = default; + + constexpr explicit split_buffer_size_layout(const allocator_type& alloc) + : _alloc(alloc) { + } + + constexpr pointer front_cap() noexcept { + return _front_cap; + } + + constexpr const_pointer front_cap() const noexcept { + return _front_cap; + } + + constexpr pointer begin() noexcept { + return _begin; + } + + constexpr const_pointer begin() const noexcept { + return _begin; + } + + constexpr pointer end() noexcept { + return _begin + _size; + } + + constexpr pointer end() const noexcept { + return _begin + _size; + } + + constexpr size_type size() const noexcept { + return _size; + } + + constexpr bool empty() const noexcept { + return _size == 0; + } + + constexpr size_type capacity() const noexcept { + return _cap; + } + + constexpr allocator_type& get_allocator() noexcept { + return _alloc; + } + + constexpr const allocator_type& get_allocator() const noexcept { + return _alloc; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type + // deduction, not explicit types. + constexpr sentinel_type raw_sentinel() const noexcept { + return _size; + } + + constexpr sentinel_type raw_capacity() const noexcept { + return _cap; + } + + constexpr void set_data(pointer new_first) noexcept { + _front_cap = new_first; + } + + constexpr void + set_valid_range(pointer new_begin, pointer new_end) noexcept { + // Size-based split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + _size -= new_begin - _begin; + _begin = new_begin; + set_sentinel(new_end); + } + + constexpr void + set_valid_range(pointer new_begin, size_type new_size) noexcept { + // Size-based split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + _size -= new_begin - _begin; + _begin = new_begin; + set_sentinel(new_size); + } + + constexpr void set_sentinel(pointer new_end) noexcept { + _LIBCPP_ASSERT_INTERNAL(_front_cap <= new_end, "new_end cannot precede _front_cap"); + _size += new_end - end(); + } + + constexpr void set_sentinel(size_type new_size) noexcept { + _size = new_size; + } + + constexpr void set_capacity(size_type new_capacity) noexcept { + _cap = new_capacity; + } + + constexpr void set_capacity(pointer new_capacity) noexcept { + _cap = new_capacity - _begin; + } + + constexpr size_type front_spare() const noexcept { + return static_cast(_begin - _front_cap); + } + + constexpr size_type back_spare() const noexcept { + // `_cap - _end` tells us the total number of spares when in size-mode. We need to remove + // the front_spare from the count. + return _cap - _size - front_spare(); + } + + constexpr reference back() noexcept { + return _begin[_size - 1]; + } + + constexpr const_reference back() const noexcept { + return _begin[_size - 1]; + } + + constexpr void swap_without_allocator( + split_buffer_pointer_layout< + split_buffer, + value_type, + alloc_rr&>& other + ) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_cap, other._cap); + std::swap(_size, other._size); + } + + constexpr void swap(split_buffer_size_layout& other) noexcept { + std::swap(_front_cap, other._front_cap); + std::swap(_begin, other._begin); + std::swap(_cap, other._cap); + std::swap(_size, other._size); + swap_allocator(_alloc, other._alloc); + } + + constexpr void reset() noexcept { + _front_cap = nullptr; + _begin = nullptr; + _size = 0; + _cap = 0; + } + + constexpr void copy_without_alloc( + const split_buffer_size_layout& other + ) noexcept(std::is_nothrow_copy_assignable::value) { + _front_cap = other._front_cap; + _begin = other._begin; + _cap = other._cap; + _size = other._size; + } + + private: + pointer _front_cap = nullptr; + pointer _begin = nullptr; + size_type _size = 0; + size_type _cap = 0; + PLUGIFY_NO_UNIQUE_ADDRESS allocator_type _alloc; + + template + friend class split_buffer_size_layout; + }; + + // `split_buffer` is a contiguous array data structure. It may hold spare capacity at both ends of + // the sequence. This allows for a `split_buffer` to grow from both the front and the back without + // relocating its contents until it runs out of room. This characteristic sets it apart from + // `std::vector`, which only holds spare capacity at its end. As such, `split_buffer` is useful + // for implementing both `std::vector` and `std::deque`. + // + // The sequence is stored as a contiguous chunk of memory delimited by the following "pointers" (`o` + // denotes uninitialized memory and `x` denotes a valid object): + // + // |oooooooooooooooooooxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxoooooooooooooooooooooooo| + // ^ ^ ^ ^ + // _front_cap _begin _end _back_cap + // + // The range [_front_cap, _begin) contains uninitialized memory. It is referred to as the "front + // spare capacity". The range [_begin, _end) contains valid objects. It is referred to as the "valid + // range". The range [_end, _back_cap) contains uninitialized memory. It is referred to as the "back + // spare capacity". + // + // The layout of `split_buffer` is determined by the `Layout` template template parameter. This + // `Layout` allows the above pointers to be stored as different representations, such as integer + // offsets. A layout class template must provide the following interface: + // + // template + // class layout { + // protected: + // using value_type = T; + // using allocator_type = Allocator; + // using alloc_rr = std::remove_reference_t; + // using alloc_traits = allocator_traits; + // using reference = value_type&; + // using const_reference = const value_type&; + // using size_type = typename alloc_traits::size_type; + // using difference_type = typename alloc_traits::difference_type; + // using pointer = typename alloc_traits::pointer; + // using const_pointer = typename alloc_traits::const_pointer; + // using iterator = pointer; + // using constIterator = const_pointer; + // using sentinel_type = /* type that represents the layout's sentinel */; + // + // public: + // layout() = default; + // explicit layout(const allocator_type&); + // + // pointer front_cap(); + // const_pointer front_cap() const; + // + // pointer begin(); + // const_pointer begin() const; + // + // pointer end(); + // pointer end() const; + // + // size_type size() const; + // bool empty() const; + // size_type capacity() const; + // + // allocator_type& get_allocator(); + // allocator_type const& get_allocator() const; + // + // sentinel_type raw_sentinel() const; + // sentinel_type raw_capacity() const; + // + // void set_data(pointer); + // void set_valid_range(pointer begin, pointer end); + // void set_valid_range(pointer begin, size_type size); + // void set_sentinel(pointer end); + // void set_sentinel(size_type size); + // + // void set_capacity(size_type capacity); + // void set_capacity(pointer capacity); + // + // size_type front_spare() const; + // size_type back_spare() const; + // + // reference back(); + // const_reference back() const; + // + // template + // void swap_without_allocator(_OtherLayout&); + // void swap(layout&); + // + // void reset(); + // void copy_without_alloc(layout const&); + // }; + // + template class Layout> + class split_buffer : Layout, T, Allocator> { + using base_type = Layout, T, Allocator>; + + public: + using base_type::back_spare; + using base_type::copy_without_alloc; + using base_type::front_cap; + using base_type::front_spare; + using base_type::get_allocator; + using base_type::raw_capacity; + using base_type::raw_sentinel; + using base_type::reset; + using base_type::set_capacity; + using base_type::set_data; + using base_type::set_sentinel; + using base_type::set_valid_range; + + using typename base_type::alloc_rr; + using typename base_type::alloc_traits; + using typename base_type::allocator_type; + using typename base_type::constIterator; + using typename base_type::const_pointer; + using typename base_type::const_reference; + using typename base_type::difference_type; + using typename base_type::iterator; + using typename base_type::pointer; + using typename base_type::reference; + using typename base_type::size_type; + using typename base_type::value_type; + + // A split_buffer contains the following members which may be trivially relocatable: + // - pointer: may be trivially relocatable, so it's checked + // - allocator_type: may be trivially relocatable, so it's checked + // split_buffer doesn't have any self-references, so it's trivially relocatable if its members + // are. + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value, + split_buffer, + void>; + + split_buffer(const split_buffer&) = delete; + split_buffer& operator=(const split_buffer&) = delete; + + split_buffer() = default; + + constexpr explicit split_buffer(alloc_rr& a) + : base_type(a) { + } + + constexpr explicit split_buffer(const alloc_rr& a) + : base_type(a) { + } + + constexpr split_buffer(size_type cap, size_type start, alloc_rr& a); + + constexpr + split_buffer(split_buffer&& c) noexcept(std::is_nothrow_move_constructible_v); + + constexpr split_buffer(split_buffer&& c, const alloc_rr& a); + + + constexpr split_buffer& operator=(split_buffer&& c) noexcept( + (alloc_traits::propagate_on_container_move_assignment::value + && std::is_nothrow_move_assignable_v) + || !alloc_traits::propagate_on_container_move_assignment::value + ); + + constexpr ~split_buffer(); + + using base_type::back; + using base_type::begin; + using base_type::capacity; + using base_type::empty; + using base_type::end; + using base_type::size; + + constexpr void clear() noexcept { + destruct_at_end(begin()); + } + + constexpr reference front() { + return *begin(); + } + + constexpr const_reference front() const { + return *begin(); + } + + constexpr void shrink_to_fit() noexcept; + + template + constexpr void emplace_front(Args&&... args); + template + constexpr void emplace_back(Args&&... args); + + constexpr void pop_front() { + destruct_at_begin(begin() + 1); + } + + constexpr void pop_back() { + destruct_at_end(end() - 1); + } + + constexpr void construct_at_end(size_type n); + constexpr void construct_at_end(size_type n, const_reference x); + + template + constexpr void + construct_at_end(ForwardIterator first, ForwardIterator last); + + template + constexpr void + construct_at_end_with_sentinel(Iterator first, Sentinel last); + + template + constexpr void construct_at_end_with_size(Iterator first, size_type n); + + constexpr void destruct_at_begin(pointer new_begin) { + destruct_at_begin(new_begin, std::is_trivially_destructible()); + } + + constexpr void destruct_at_begin(pointer new_begin, std::false_type); + constexpr void destruct_at_begin(pointer new_begin, std::true_type); + + constexpr void destruct_at_end(pointer new_last) noexcept { + destruct_at_end(new_last, std::false_type()); + } + + constexpr void destruct_at_end(pointer new_last, std::false_type) noexcept; + constexpr void destruct_at_end(pointer new_last, std::true_type) noexcept; + + constexpr void swap( + split_buffer& x + ) noexcept(!alloc_traits::propagate_on_container_swap::value || std::is_nothrow_swappable_v); + + constexpr bool invariants() const { + if (front_cap() == nullptr) { + if (begin() != nullptr) { + return false; + } + + if (!empty()) { + return false; + } + + if (capacity() != 0) { + return false; + } + + return true; + } else { + if (begin() < front_cap()) { + return false; + } + + if (capacity() < size()) { + return false; + } + + if (end() < begin()) { + return false; + } + + return true; + } + } + + constexpr void + swap_without_allocator(split_buffer& other) noexcept { + base_type::swap_without_allocator(other); + } + + private: + constexpr void move_assign_alloc(split_buffer& c, std::true_type) noexcept( + std::is_nothrow_move_assignable_v + ) { + get_allocator() = std::move(c.get_allocator()); + } + + constexpr void move_assign_alloc(split_buffer&, std::false_type) noexcept { + } + + struct ConstructTransaction { + constexpr explicit ConstructTransaction( + split_buffer* parent, + pointer p, + size_type n + ) noexcept + : _pos(p) + , _end(p + n) + , _parent(parent) { + } + + constexpr ~ConstructTransaction() { + _parent->set_sentinel(_pos); + } + + pointer _pos; + const pointer _end; + + private: + split_buffer* _parent; + }; + + template class L2> + friend class split_buffer; + }; + + // Default constructs n objects starting at `end()` + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == size() + n + template class Layout> + constexpr void split_buffer::construct_at_end(size_type n) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos)); + } + } + + // Copy constructs n objects starting at `end()` from x + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == old size() + n + // Postcondition: [i] == x for all i in [size() - n, n) + template class Layout> + constexpr void + split_buffer::construct_at_end(size_type n, const_reference x) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos), x); + } + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end_with_sentinel(Iterator first, Sentinel last) { + alloc_rr& a = get_allocator(); + for (; first != last; ++first) { + if (back_spare() == 0) { + size_type old_cap = capacity(); + size_type new_cap = std::max(2 * old_cap, 8); + split_buffer buf(new_cap, 0, a); + pointer buf_end = buf.end(); + pointer cur_end = end(); + for (pointer p = begin(); p != cur_end; ++p) { + alloc_traits::construct(buf.get_allocator(), std::to_address(buf_end), std::move(*p)); + buf.set_sentinel(++buf_end); + } + swap(buf); + } + + alloc_traits::construct(a, std::to_address(end()), *first); + set_sentinel(size() + 1); + } + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end(ForwardIterator first, ForwardIterator last) { + construct_at_end_with_size(first, std::distance(first, last)); + } + + template class Layout> + template + constexpr void + split_buffer::construct_at_end_with_size(ForwardIterator first, size_type n) { + ConstructTransaction tx(this, end(), n); + for (; tx._pos != tx._end; ++tx._pos, (void) ++first) { + alloc_traits::construct(get_allocator(), std::to_address(tx._pos), *first); + } + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_begin(pointer new_begin, std::false_type) { + pointer pos = begin(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (pos != new_begin) { + alloc_traits::destroy(get_allocator(), std::to_address(pos++)); + } + set_valid_range(pos, end()); + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_begin(pointer new_begin, std::true_type) { + set_valid_range(new_begin, end()); + } + + template class Layout> + inline constexpr void + split_buffer::destruct_at_end(pointer new_last, std::false_type) noexcept { + pointer cur_end = end(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (new_last != cur_end) { + alloc_traits::destroy(get_allocator(), std::to_address(--cur_end)); + } + set_sentinel(cur_end); + } + + template class Layout> + constexpr split_buffer::split_buffer(size_type cap, size_type start, alloc_rr& a) + : base_type(a) { + PLUGIFY_ASSERT(cap >= start, "can't have a start point outside the capacity"); + if (cap > 0) { + auto allocation = allocate_at_least(get_allocator(), cap); + set_data(allocation.ptr); + cap = allocation.count; + } + + pointer pos = front_cap() + start; + set_valid_range(pos, pos); + set_capacity(cap); + } + + template class Layout> + constexpr split_buffer::~split_buffer() { + clear(); + if (front_cap()) { + alloc_traits::deallocate(get_allocator(), front_cap(), capacity()); + } + } + + template class Layout> + constexpr split_buffer::split_buffer(split_buffer&& c) noexcept( + std::is_nothrow_move_constructible_v + ) + : base_type(std::move(c)) { + c.reset(); + } + + template class Layout> + constexpr split_buffer::split_buffer(split_buffer&& c, const alloc_rr& a) + : base_type(a) { + if (a == c.get_allocator()) { + set_data(c.front_cap()); + set_valid_range(c.begin(), c.end()); + set_capacity(c.capacity()); + c.reset(); + } else { + auto allocation = allocate_at_least(get_allocator(), c.size()); + set_data(allocation.ptr); + set_valid_range(front_cap(), front_cap()); + set_capacity(allocation.count); + using Ip = std::move_iterator; + construct_at_end(Ip(c.begin()), Ip(c.end())); + } + } + + template class Layout> + constexpr split_buffer& + split_buffer::operator=(split_buffer&& c) noexcept( + (alloc_traits::propagate_on_container_move_assignment::value + && std::is_nothrow_move_assignable_v) + || !alloc_traits::propagate_on_container_move_assignment::value + ) { + clear(); + shrink_to_fit(); + copy_without_alloc(c); + move_assign_alloc( + c, + std::integral_constant() + ); + c.reset(); + return *this; + } + + template class Layout> + constexpr void split_buffer::swap( + split_buffer& x + ) noexcept(!alloc_traits::propagate_on_container_swap::value || std::is_nothrow_swappable_v) { + base_type::swap(x); + } + + template class Layout> + constexpr void split_buffer::shrink_to_fit() noexcept { + if (capacity() > size()) { +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + split_buffer t(size(), 0, get_allocator()); + if (t.capacity() < capacity()) { + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(end())); + t.set_sentinel(size()); + swap_without_allocator(t); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } + } + + template class Layout> + template + constexpr void split_buffer::emplace_front(Args&&... args) { + if (front_spare() == 0) { + pointer cur_end = end(); + if (back_spare() > 0) { + // The elements are pressed up against the front of the buffer: we need to move them + // back a little bit to make `emplace_front` have amortised O(1) complexity. + difference_type d = back_spare(); + d = (d + 1) / 2; + auto new_end = cur_end + d; + set_valid_range(std::move_backward(begin(), cur_end, new_end), new_end); + } else { + size_type c = std::max(2 * capacity(), 1); + split_buffer t(c, (c + 3) / 4, get_allocator()); + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(cur_end)); + base_type::swap_without_allocator(t); + } + } + + alloc_traits::construct(get_allocator(), std::to_address(begin() - 1), std::forward(args)...); + set_valid_range(begin() - 1, size() + 1); + } + + template class Layout> + template + constexpr void split_buffer::emplace_back(Args&&... args) { + pointer cur_end = end(); + if (back_spare() == 0) { + if (front_spare() > 0) { + difference_type d = front_spare(); + d = (d + 1) / 2; + cur_end = std::move(begin(), cur_end, begin() - d); + set_valid_range(begin() - d, cur_end); + } else { + size_type c = std::max(2 * capacity(), 1); + split_buffer t(c, c / 4, get_allocator()); + t.construct_at_end(std::move_iterator(begin()), std::move_iterator(cur_end)); + base_type::swap_without_allocator(t); + } + } + + alloc_traits::construct(get_allocator(), std::to_address(cur_end), std::forward(args)...); + set_sentinel(++cur_end); + } + + template class Layout> + inline constexpr void + swap(split_buffer& x, split_buffer& y) noexcept( + noexcept(x.swap(y)) + ) { + x.swap(y); + } +} // namespace plg diff --git a/test/example_plugin/external/plugify/include/plg/string.hpp b/test/example_plugin/external/plugify/include/plg/string.hpp index 830f168..3613b95 100644 --- a/test/example_plugin/external/plugify/include/plg/string.hpp +++ b/test/example_plugin/external/plugify/include/plg/string.hpp @@ -1,1692 +1,3608 @@ -#pragma once - -// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc -#if PLUGIFY_COMPILER_CLANG -# pragma clang system_header -#elif PLUGIFY_COMPILER_GCC -# pragma GCC system_header -#endif +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// -#include // for std::initializer_list -#include // for std::basic_string_view -#include // for std::is_constant_evaluated, std::declval, std::false_type -#include // for std::min, std::max -#include // for std::unsigned_integral, std::signed_integral -#include // for std::distance, std::next, std::iterator_traits, std::input_iterator -#include // for std::move, std::hash -#include // for std::strong_ordering -#include // for std::allocator, std::swap, std::allocator_traits -#include // for std::numeric_limits -#include // for std::to_chars +#pragma once +// clang-format off + +/* + string synopsis + +#include +#include + +namespace std +{ + +template +class fpos +{ +private: + stateT st; +public: + fpos(streamoff = streamoff()); + + operator streamoff() const; + + stateT state() const; + void state(stateT); + + fpos& operator+=(streamoff); + fpos operator+ (streamoff) const; + fpos& operator-=(streamoff); + fpos operator- (streamoff) const; +}; + +template streamoff operator-(const fpos& x, const fpos& y); + +template bool operator==(const fpos& x, const fpos& y); +template bool operator!=(const fpos& x, const fpos& y); + +template +struct char_traits +{ + using char_type = charT; + using int_type = ...; + using off_type = streamoff; + using pos_type = streampos; + using state_type = mbstate_t; + using comparison_category = strong_ordering; // Since C++20 only for the specializations + // char, wchar_t, char8_t, char16_t, and char32_t. + + static void assign(char_type& c1, const char_type& c2) noexcept; + static constexpr bool eq(char_type c1, char_type c2) noexcept; + static constexpr bool lt(char_type c1, char_type c2) noexcept; + + static int compare(const char_type* s1, const char_type* s2, size_t n); + static size_t length(const char_type* s); + static const char_type* find(const char_type* s, size_t n, const char_type& a); + static char_type* move(char_type* s1, const char_type* s2, size_t n); + static char_type* copy(char_type* s1, const char_type* s2, size_t n); + static char_type* assign(char_type* s, size_t n, char_type a); + + static constexpr int_type not_eof(int_type c) noexcept; + static constexpr char_type to_char_type(int_type c) noexcept; + static constexpr int_type to_int_type(char_type c) noexcept; + static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept; + static constexpr int_type eof() noexcept; +}; + +template <> struct char_traits; +template <> struct char_traits; +template <> struct char_traits; // C++20 +template <> struct char_traits; +template <> struct char_traits; + +template, class Allocator = allocator > +class basic_string +{ +public: +// types: + typedef traits traits_type; + typedef typename traits_type::char_type value_type; + typedef Allocator allocator_type; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef implementation-defined iterator; + typedef implementation-defined const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static const size_type npos = -1; + + basic_string() + noexcept(std::is_nothrow_default_constructible::value); // constexpr since C++20 + explicit basic_string(const allocator_type& a); // constexpr since C++20 + basic_string(const basic_string& str); // constexpr since C++20 + basic_string(basic_string&& str) + noexcept(std::is_nothrow_move_constructible::value); // constexpr since C++20 + basic_string(const basic_string& str, size_type pos, + const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(const basic_string& str, size_type pos, size_type n, + const Allocator& a = Allocator()); // constexpr since C++20 + constexpr basic_string( + basic_string&& str, size_type pos, const Allocator& a = Allocator()); // since C++23 + constexpr basic_string( + basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); // since C++23 + template + basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); // C++17, constexpr since C++20 + template + explicit basic_string(const T& t, const Allocator& a = Allocator()); // C++17, constexpr since C++20 + basic_string(const value_type* s, const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(const value_type* s, size_type n, const allocator_type& a = allocator_type()); // constexpr since C++20 + basic_string(nullptr_t) = delete; // C++23 + basic_string(size_type n, value_type c, const allocator_type& a = allocator_type()); // constexpr since C++20 + template + basic_string(InputIterator begin, InputIterator end, + const allocator_type& a = allocator_type()); // constexpr since C++20 + template R> + constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); // since C++23 + basic_string(std::initializer_list, const Allocator& = Allocator()); // constexpr since C++20 + basic_string(const basic_string&, const Allocator&); // constexpr since C++20 + basic_string(basic_string&&, const Allocator&); // constexpr since C++20 + + ~basic_string(); // constexpr since C++20 + + operator std::basic_string_view() const noexcept; // constexpr since C++20 + + basic_string& operator=(const basic_string& str); // constexpr since C++20 + template + basic_string& operator=(const T& t); // C++17, constexpr since C++20 + basic_string& operator=(basic_string&& str) + noexcept( + allocator_type::propagate_on_container_move_assignment::value || + allocator_type::is_always_equal::value ); // C++17, constexpr since C++20 + basic_string& operator=(const value_type* s); // constexpr since C++20 + basic_string& operator=(nullptr_t) = delete; // C++23 + basic_string& operator=(value_type c); // constexpr since C++20 + basic_string& operator=(std::initializer_list); // constexpr since C++20 + + iterator begin() noexcept; // constexpr since C++20 + const_iterator begin() const noexcept; // constexpr since C++20 + iterator end() noexcept; // constexpr since C++20 + const_iterator end() const noexcept; // constexpr since C++20 + + reverse_iterator rbegin() noexcept; // constexpr since C++20 + const_reverse_iterator rbegin() const noexcept; // constexpr since C++20 + reverse_iterator rend() noexcept; // constexpr since C++20 + const_reverse_iterator rend() const noexcept; // constexpr since C++20 + + const_iterator cbegin() const noexcept; // constexpr since C++20 + const_iterator cend() const noexcept; // constexpr since C++20 + const_reverse_iterator crbegin() const noexcept; // constexpr since C++20 + const_reverse_iterator crend() const noexcept; // constexpr since C++20 + + size_type size() const noexcept; // constexpr since C++20 + size_type length() const noexcept; // constexpr since C++20 + size_type max_size() const noexcept; // constexpr since C++20 + size_type capacity() const noexcept; // constexpr since C++20 + + void resize(size_type n, value_type c); // constexpr since C++20 + void resize(size_type n); // constexpr since C++20 + + template + constexpr void resize_and_overwrite(size_type n, Operation op); // since C++23 + + void reserve(size_type res_arg); // constexpr since C++20 + void reserve(); // deprecated in C++20, removed in C++26 + void shrink_to_fit(); // constexpr since C++20 + void clear() noexcept; // constexpr since C++20 + bool empty() const noexcept; // constexpr since C++20 + + const_reference operator[](size_type pos) const; // constexpr since C++20 + reference operator[](size_type pos); // constexpr since C++20 + + const_reference at(size_type n) const; // constexpr since C++20 + reference at(size_type n); // constexpr since C++20 + + basic_string& operator+=(const basic_string& str); // constexpr since C++20 + template + basic_string& operator+=(const T& t); // C++17, constexpr since C++20 + basic_string& operator+=(const value_type* s); // constexpr since C++20 + basic_string& operator+=(value_type c); // constexpr since C++20 + basic_string& operator+=(std::initializer_list); // constexpr since C++20 + + basic_string& append(const basic_string& str); // constexpr since C++20 + template + basic_string& append(const T& t); // C++17, constexpr since C++20 + basic_string& append(const basic_string& str, size_type pos, size_type n=npos); // C++14, constexpr since C++20 + template + basic_string& append(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 + basic_string& append(const value_type* s, size_type n); // constexpr since C++20 + basic_string& append(const value_type* s); // constexpr since C++20 + basic_string& append(size_type n, value_type c); // constexpr since C++20 + template + basic_string& append(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& append_range(R&& rg); // C++23 + basic_string& append(std::initializer_list); // constexpr since C++20 + + void push_back(value_type c); // constexpr since C++20 + void pop_back(); // constexpr since C++20 + reference front(); // constexpr since C++20 + const_reference front() const; // constexpr since C++20 + reference back(); // constexpr since C++20 + const_reference back() const; // constexpr since C++20 + + basic_string& assign(const basic_string& str); // constexpr since C++20 + template + basic_string& assign(const T& t); // C++17, constexpr since C++20 + basic_string& assign(basic_string&& str); // constexpr since C++20 + basic_string& assign(const basic_string& str, size_type pos, size_type n=npos); // C++14, constexpr since C++20 + template + basic_string& assign(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 + basic_string& assign(const value_type* s, size_type n); // constexpr since C++20 + basic_string& assign(const value_type* s); // constexpr since C++20 + basic_string& assign(size_type n, value_type c); // constexpr since C++20 + template + basic_string& assign(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& assign_range(R&& rg); // C++23 + basic_string& assign(std::initializer_list); // constexpr since C++20 + + basic_string& insert(size_type pos1, const basic_string& str); // constexpr since C++20 + template + basic_string& insert(size_type pos1, const T& t); // constexpr since C++20 + basic_string& insert(size_type pos1, const basic_string& str, + size_type pos2, size_type n2=npos); // constexpr since C++20 + template + basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n=npos); // C++17, constexpr since C++20 + basic_string& insert(size_type pos, const value_type* s, size_type n=npos); // C++14, constexpr since C++20 + basic_string& insert(size_type pos, const value_type* s); // constexpr since C++20 + basic_string& insert(size_type pos, size_type n, value_type c); // constexpr since C++20 + iterator insert(const_iterator p, value_type c); // constexpr since C++20 + iterator insert(const_iterator p, size_type n, value_type c); // constexpr since C++20 + template + iterator insert(const_iterator p, InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr iterator insert_range(const_iterator p, R&& rg); // C++23 + iterator insert(const_iterator p, std::initializer_list); // constexpr since C++20 + + basic_string& erase(size_type pos = 0, size_type n = npos); // constexpr since C++20 + iterator erase(const_iterator position); // constexpr since C++20 + iterator erase(const_iterator first, const_iterator last); // constexpr since C++20 + + basic_string& replace(size_type pos1, size_type n1, const basic_string& str); // constexpr since C++20 + template + basic_string& replace(size_type pos1, size_type n1, const T& t); // C++17, constexpr since C++20 + basic_string& replace(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2=npos); // C++14, constexpr since C++20 + template + basic_string& replace(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2=npos); // C++17, constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, const value_type* s, size_type n2); // constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, const value_type* s); // constexpr since C++20 + basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str); // constexpr since C++20 + template + basic_string& replace(const_iterator i1, const_iterator i2, const T& t); // C++17, constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s); // constexpr since C++20 + basic_string& replace(const_iterator i1, const_iterator i2, size_type n, value_type c); // constexpr since C++20 + template + basic_string& replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2); // constexpr since C++20 + template R> + constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); // C++23 + basic_string& replace(const_iterator i1, const_iterator i2, std::initializer_list); // constexpr since C++20 + + size_type copy(value_type* s, size_type n, size_type pos = 0) const; // constexpr since C++20 + basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr in C++20, removed in C++23 + basic_string substr(size_type pos = 0, size_type n = npos) const&; // since C++23 + constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; // since C++23 + void swap(basic_string& str) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); // C++17, constexpr since C++20 + + const value_type* c_str() const noexcept; // constexpr since C++20 + const value_type* data() const noexcept; // constexpr since C++20 + value_type* data() noexcept; // C++17, constexpr since C++20 + + allocator_type get_allocator() const noexcept; // constexpr since C++20 + + size_type find(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type rfind(const T& t, size_type pos = npos) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type rfind(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type rfind(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type rfind(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find_first_of(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_first_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_first_of(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find_first_of(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type find_last_of(const T& t, size_type pos = npos) const noexcept noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_last_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_last_of(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type find_last_of(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept; // constexpr since C++20 + template + size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_first_not_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_first_not_of(const value_type* s, size_type pos = 0) const noexcept; // constexpr since C++20 + size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept; // constexpr since C++20 + + size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept; // constexpr since C++20 + template + size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + size_type find_last_not_of(const value_type* s, size_type pos, size_type n) const noexcept; // constexpr since C++20 + size_type find_last_not_of(const value_type* s, size_type pos = npos) const noexcept; // constexpr since C++20 + size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept; // constexpr since C++20 + + int compare(const basic_string& str) const noexcept; // constexpr since C++20 + template + int compare(const T& t) const noexcept; // C++17, noexcept as an extension, constexpr since C++20 + int compare(size_type pos1, size_type n1, const basic_string& str) const; // constexpr since C++20 + template + int compare(size_type pos1, size_type n1, const T& t) const; // C++17, constexpr since C++20 + int compare(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2=npos) const; // C++14, constexpr since C++20 + template + int compare(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2=npos) const; // C++17, constexpr since C++20 + int compare(const value_type* s) const noexcept; // constexpr since C++20 + int compare(size_type pos1, size_type n1, const value_type* s) const; // constexpr since C++20 + int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; // constexpr since C++20 + + constexpr bool starts_with(std::basic_string_view sv) const noexcept; // C++20 + constexpr bool starts_with(charT c) const noexcept; // C++20 + constexpr bool starts_with(const charT* s) const; // C++20 + constexpr bool ends_with(std::basic_string_view sv) const noexcept; // C++20 + constexpr bool ends_with(charT c) const noexcept; // C++20 + constexpr bool ends_with(const charT* s) const; // C++20 + + constexpr bool contains(std::basic_string_view sv) const noexcept; // C++23 + constexpr bool contains(charT c) const noexcept; // C++23 + constexpr bool contains(const charT* s) const; // C++23 +}; + +template::value_type>> +basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string::value_type, + char_traits::value_type>, + Allocator>; // C++17 + +template>> + basic_string(from_range_t, R&&, Allocator = Allocator()) + -> basic_string, char_traits>, + Allocator>; // C++23 + +template> + explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) + -> basic_string; // C++17 + +template> + basic_string(std::basic_string_view, + typename see below::size_type, typename see below::size_type, + const Allocator& = Allocator()) + -> basic_string; // C++17 + +template +basic_string +operator+(const basic_string& lhs, + const basic_string& rhs); // constexpr since C++20 + +template +basic_string +operator+(const charT* lhs , const basic_string&rhs); // constexpr since C++20 + +template +basic_string +operator+(charT lhs, const basic_string& rhs); // constexpr since C++20 + +template +basic_string +operator+(const basic_string& lhs, const charT* rhs); // constexpr since C++20 + +template +basic_string +operator+(const basic_string& lhs, charT rhs); // constexpr since C++20 + +template + constexpr basic_string + operator+(const basic_string& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(basic_string&& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + const basic_string& rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + basic_string&& rhs); // Since C++26 + + +template +bool operator==(const basic_string& lhs, + const basic_string& rhs) noexcept; // constexpr since C++20 + +template +bool operator==(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator==(const basic_string& lhs, const charT* rhs) noexcept; // constexpr since C++20 + +template +bool operator!=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator!=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator!=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator< (const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator< (const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator< (const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator> (const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator> (const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator> (const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator<=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator<=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator<=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator>=(const basic_string& lhs, + const basic_string& rhs) noexcept; // removed in C++20 + +template +bool operator>=(const basic_string& lhs, const charT* rhs) noexcept; // removed in C++20 + +template +bool operator>=(const charT* lhs, const basic_string& rhs) noexcept; // removed in C++20 + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const basic_string& rhs) noexcept; + +template // since C++20 +constexpr see below operator<=>(const basic_string& lhs, + const charT* rhs) noexcept; + +template +void swap(basic_string& lhs, + basic_string& rhs) + noexcept(noexcept(lhs.swap(rhs))); // constexpr since C++20 + +template +std::basic_istream& +operator>>(std::basic_istream& is, basic_string& str); + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const basic_string& str); + +template +std::basic_istream& +getline(std::basic_istream& is, basic_string& str, + charT delim); + +template +std::basic_istream& +getline(std::basic_istream& is, basic_string& str); + +template +constexpr typename basic_string::size_type +erase(basic_string& c, const U& value); // C++20 +template +constexpr typename basic_string::size_type +erase_if(basic_string& c, Predicate pred); // C++20 + +typedef basic_string string; +typedef basic_string wstring; +typedef basic_string u8string; // C++20 +typedef basic_string u16string; +typedef basic_string u32string; + +int stoi (const string& str, size_t* idx = nullptr, int base = 10); +long stol (const string& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul (const string& str, size_t* idx = nullptr, int base = 10); +long long stoll (const string& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10); + +float stof (const string& str, size_t* idx = nullptr); +double stod (const string& str, size_t* idx = nullptr); +long double stold(const string& str, size_t* idx = nullptr); + +string to_string(int val); +string to_string(unsigned val); +string to_string(long val); +string to_string(unsigned long val); +string to_string(long long val); +string to_string(unsigned long long val); +string to_string(float val); +string to_string(double val); +string to_string(long double val); + +int stoi (const wstring& str, size_t* idx = nullptr, int base = 10); +long stol (const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul (const wstring& str, size_t* idx = nullptr, int base = 10); +long long stoll (const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10); + +float stof (const wstring& str, size_t* idx = nullptr); +double stod (const wstring& str, size_t* idx = nullptr); +long double stold(const wstring& str, size_t* idx = nullptr); + +wstring to_wstring(int val); +wstring to_wstring(unsigned val); +wstring to_wstring(long val); +wstring to_wstring(unsigned long val); +wstring to_wstring(long long val); +wstring to_wstring(unsigned long long val); +wstring to_wstring(float val); +wstring to_wstring(double val); +wstring to_wstring(long double val); + +template <> struct hash; +template <> struct hash; // C++20 +template <> struct hash; +template <> struct hash; +template <> struct hash; + +basic_string operator""s( const char *str, size_t len ); // C++14, constexpr since C++20 +basic_string operator""s( const wchar_t *str, size_t len ); // C++14, constexpr since C++20 +constexpr basic_string operator""s( const char8_t *str, size_t len ); // C++20 +basic_string operator""s( const char16_t *str, size_t len ); // C++14, constexpr since C++20 +basic_string operator""s( const char32_t *str, size_t len ); // C++14, constexpr since C++20 + +} // std + +*/ + +// clang-format on + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#if PLUGIFY_STRING_CONTAINERS_RANGES && (__cplusplus <= 202002L || !__has_include() || !defined(__cpp_lib_containers_ranges)) -# undef PLUGIFY_STRING_CONTAINERS_RANGES -# define PLUGIFY_STRING_CONTAINERS_RANGES 0 -#endif - -#if PLUGIFY_STRING_CONTAINERS_RANGES -# include -#endif - -#ifndef PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS -# include -#endif +#include "plg/allocator.hpp" +#include "plg/guards.hpp" +#include "plg/concepts.hpp" #ifndef PLUGIFY_STRING_NO_STD_FORMAT #include "plg/format.hpp" #endif -#include "plg/allocator.hpp" +// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc +#if PLUGIFY_COMPILER_CLANG +# pragma clang system_header +#elif PLUGIFY_COMPILER_GCC +# pragma GCC system_header +#endif +// from https://github.com/llvm/llvm-project/blob/main/libcxx/include/string namespace plg { - namespace detail { - template - concept is_allocator = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; + // basic_string + template + class basic_string; - template - concept is_char_traits = requires { - // Required type definitions - typename Traits::char_type; - typename Traits::int_type; - typename Traits::off_type; - typename Traits::pos_type; - typename Traits::state_type; - } && requires( - typename Traits::char_type c1, - typename Traits::char_type c2, - typename Traits::char_type& cr, - const typename Traits::char_type& ccr, - typename Traits::char_type* p, - const typename Traits::char_type* cp, - typename Traits::int_type i1, - typename Traits::int_type i2, - std::size_t n - ) { - // Character operations - { Traits::assign(cr, ccr) } -> std::same_as; - { Traits::eq(ccr, ccr) } -> std::convertible_to; - { Traits::lt(ccr, ccr) } -> std::convertible_to; - - // String operations - { Traits::compare(cp, cp, n) } -> std::convertible_to; - { Traits::length(cp) } -> std::convertible_to; - { Traits::find(cp, n, ccr) } -> std::convertible_to; - - // Memory operations - { Traits::move(p, cp, n) } -> std::same_as; - { Traits::copy(p, cp, n) } -> std::same_as; - { Traits::assign(p, n, c1) } -> std::same_as; - - // int_type operations - { Traits::not_eof(i1) } -> std::same_as; - { Traits::to_char_type(i1) } -> std::same_as; - { Traits::to_int_type(c1) } -> std::same_as; - { Traits::eq_int_type(i1, i2) } -> std::convertible_to; - { Traits::eof() } -> std::same_as; - }; + template + constexpr basic_string concatenate_strings( + const Allocator& alloc, + std::type_identity_t> str1, + std::type_identity_t> str2 + ); - struct uninitialized_size_tag {}; + template + inline const bool string_is_trivial_iterator_v = false; - template - constexpr bool dependent_false = false; + template + concept string_is_trivial_iterator = std::is_arithmetic_v; -#if PLUGIFY_STRING_CONTAINERS_RANGES - template - concept string_compatible_range = std::ranges::input_range && std::convertible_to, Type>; -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + concept string_view_convertible = std::is_convertible_v> && !std::is_convertible_v; - } // namespace detail + // second concept = the above, but exclude std::basic_string itself + template + concept string_view_convertible_with_exceptiom = string_view_convertible && !std::is_same_v, basic_string>; - // basic_string - // based on implementations from libc++, libstdc++ and Microsoft STL - template, detail::is_allocator Allocator = plg::allocator> + template + concept string_like = requires(T v) { + { std::string_view(v) }; + }; + + template + struct padding { + char _pad[N]; + }; + + template <> + struct padding<0> {}; + + struct uninitialized_size_tag {}; + + struct init_with_sentinel_tag {}; + + template , class Allocator = allocator> class basic_string { - private: - using allocator_traits = std::allocator_traits; public: + // using self = std::basic_string; + using self_view = std::basic_string_view; using traits_type = Traits; - using value_type = typename traits_type::char_type; + using value_type = CharT; using allocator_type = Allocator; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; + using alloc_traits = std::allocator_traits; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; using reference = value_type&; using const_reference = const value_type&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + + // A basic_string contains the following members which may be trivially relocatable: + // - pointer: is currently assumed to be trivially relocatable, but is still checked in case + // that changes + // - size_type: is always trivially relocatable, since it has to be an integral type + // - value_type: is always trivially relocatable, since it has to be trivial + // - unsigned char: is a fundamental type, so it's trivially relocatable + // - allocator_type: may or may not be trivially relocatable, so it's checked + // + // This string implementation doesn't contain any references into itself. It only contains a + // bit that says whether it is in small or large string mode, so the entire structure is + // trivially relocatable if its members are. +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + // When compiling with AddressSanitizer (ASan), basic_string cannot be trivially + // relocatable. Because the object's memory might be poisoned when its content + // is kept inside objects memory (short string optimization), instead of in allocated + // external memory. In such cases, the destructor is responsible for unpoisoning + // the memory to avoid triggering false positives. + // Therefore it's crucial to ensure the destructor is called. + // + // However, it is replaceable since implementing move-assignment as a destroy + + // move-construct will maintain the right ASAN state. + using trivially_relocatable = void; +#else + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value, + basic_string, + void>; +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + +#if PLUGIFY_INSTRUMENTED_WITH_ASAN && __has_cpp_attribute(__no_sanitize__) +# define PLUGIFY_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address"))) +// This macro disables AddressSanitizer (ASan) instrumentation for a specific function, +// allowing memory accesses that would normally trigger ASan errors to proceed without crashing. +// This is useful for accessing parts of objects memory, which should not be accessed, +// such as unused bytes in short strings, that should never be accessed +// by other parts of the program. +#else +# define PLUGIFY_INTERNAL_MEMORY_ACCESS +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + +#if PLUGIFY_INSTRUMENTED_WITH_ASAN + constexpr pointer asan_volatile_wrapper(pointer const& ptr) const { + if (std::is_constant_evaluated()) { + return ptr; + } + + volatile pointer copy_ptr = ptr; + + return const_cast(copy_ptr); + } + + constexpr const_pointer asan_volatile_wrapper(const const_pointer& ptr) const { + if (std::is_constant_evaluated()) { + return ptr; + } + + volatile const_pointer copy_ptr = ptr; + + return const_cast(copy_ptr); + } + +# define PLUGIFY_ASAN_VOLATILE_WRAPPER(PTR) asan_volatile_wrapper(PTR) +#else +# define PLUGIFY_ASAN_VOLATILE_WRAPPER(PTR) PTR +#endif // PLUGIFY_INSTRUMENTED_WITH_ASAN + + static_assert(!std::is_array_v, "Character type of basic_string must not be an array"); + static_assert( + std::is_standard_layout_v, + "Character type of basic_string must be standard-layout" + ); + static_assert( + std::is_trivially_default_constructible_v, + "Character type of basic_string must be trivially default constructible" + ); + static_assert( + std::is_trivially_copyable_v, + "Character type of basic_string must be trivially copyable" + ); + static_assert( + std::is_same_v, + "traits_type::char_type must be the same type as CharT" + ); + static_assert( + std::is_same_v, + "Allocator::value_type must be same type as value_type" + ); + // static_assert(std::check_valid_allocator::value, ""); + using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - using sview_type = std::basic_string_view; - constexpr static size_type npos = static_cast(-1); + using alloc_result = allocation_result; private: - constexpr static auto _terminator = value_type(); - - PLUGIFY_NO_UNIQUE_ADDRESS - allocator_type _allocator; + static constexpr int char_bit = std::numeric_limits::digits + std::numeric_limits::is_signed; + static_assert(char_bit == 8, "This implementation assumes that one byte contains 8 bits"); - PLUGIFY_WARN_PUSH() + struct long_ { + constexpr long_() = default; -#if PLUGIFY_COMPILER_CLANG - PLUGIFY_WARN_IGNORE("-Wgnu-anonymous-struct") - PLUGIFY_WARN_IGNORE("-Wzero-length-array") -#elif PLUGIFY_COMPILER_GCC - PLUGIFY_WARN_IGNORE("-Wpedantic") -#elif PLUGIFY_COMPILER_MSVC - PLUGIFY_WARN_IGNORE(4201) - PLUGIFY_WARN_IGNORE(4200) -#endif + constexpr long_(alloc_result alloc, size_type size) + : _data(alloc.ptr) + , _size(size) + , _cap(alloc.count / endian_factor) + , _is_long(true) { + PLUGIFY_ASSERT(!fits_in_sso(alloc.count), "Long capacity should always be larger than the SSO"); + } - template - struct padding { - [[maybe_unused]] uint8_t pad[sizeof(CharT) - 1]; + pointer _data; + size_type _size; + size_type _cap : sizeof(size_type) * char_bit - 1; + size_type _is_long : 1; }; - template - struct padding { - // template specialization to remove the padding structure to avoid warnings on zero length arrays - // also, this allows us to take advantage of the empty-base-class optimization. - }; + static constexpr size_type min_cap = ((sizeof(long_) - 1) / sizeof(value_type) > 2 ? (sizeof(long_) - 1) / sizeof(value_type) : 2) + 1; - // size must correspond to the last byte of long_data.cap, so we don't want the compiler to insert - // padding after size if sizeof(value_type) != 1; Also ensures both layouts are the same size. - struct sso_size : padding { - PLUGIFY_PACK(struct { - uint8_t spare_size : 7; - uint8_t is_long : 1; - }); - }; + struct short_ { + constexpr short_() + : _data{} + , _spare_size(min_cap - 1) + , _is_long(false) { + } - static constexpr int char_bit = std::numeric_limits::digits + std::numeric_limits::is_signed; - static_assert(char_bit == 8, "assumes an 8 bit byte."); - - struct long_data { - pointer data; - size_type size; - PLUGIFY_PACK(struct { - size_type cap : sizeof(size_type) * char_bit - 1; - size_type is_long : 1; - }); + value_type _data[min_cap - 1]; + PLUGIFY_NO_UNIQUE_ADDRESS padding _padding; + uint8_t _spare_size : 7; + uint8_t _is_long : 1; }; - static constexpr size_type min_cap = (sizeof(long_data) - 1) / sizeof(value_type) > 2 ? (sizeof(long_data) - 1) / sizeof(value_type) : 2; + // The endian_factor is required because the field we use to store the size + // has one fewer bit than it would if it were not a bitfield. + // + // If the LSB is used to store the short-flag in the short string representation, + // we have to multiply the size by two when it is stored and divide it by two when + // it is loaded to make sure that we always store an even number. In the long string + // representation, we can ignore this because we can assume that we always allocate + // an even amount of value_types. + // + // If the MSB is used for the short-flag, the max_size() is numeric_limits::max() + // / 2. This does not impact the short string representation, since we never need the MSB + // for representing the size of a short string anyway. + + static constexpr size_type endian_factor = std::endian::native == std::endian::big ? 2 : 1; + + static_assert( + sizeof(short_) == (sizeof(value_type) * min_cap), + "short has an unexpected size." + ); + static_assert( + sizeof(short_) == sizeof(long_), + "short and long layout structures must be the same size" + ); + + union rep { + short_ s{}; + long_ l; + } _rep; + PLUGIFY_NO_UNIQUE_ADDRESS + allocator_type _alloc; + + // annotate the string with its size() at scope exit. The string has to be in a valid state + // at that point. + struct annotate_new_size { + basic_string& _str; - struct short_data { - value_type data[min_cap]; - sso_size size; + constexpr explicit annotate_new_size(basic_string& str) + : _str(str) { + } + + constexpr void operator()() { + _str.annotate_new(_str.size()); + } }; - PLUGIFY_WARN_POP() + // Construct a string with the given allocator and enough storage to hold `size` characters, + // but don't initialize the characters. The contents of the string, including the null + // terminator, must be initialized separately. + constexpr /*explicit*/ basic_string(uninitialized_size_tag, size_type size, const allocator_type& a) + : _alloc(a) { + init_internal_buffer(size); + } - static_assert(sizeof(short_data) == (sizeof(value_type) * (min_cap + 1)), "short has an unexpected size."); - static_assert(sizeof(short_data) == sizeof(long_data), "short and long layout structures must be the same size"); + template + constexpr basic_string(init_with_sentinel_tag, Iter first, Sent last, const allocator_type& a) + : _alloc(a) { + init_with_sentinel(std::move(first), std::move(last)); + } - union { - long_data _long; - short_data _short{}; - } _storage; + constexpr iterator make_iterator(pointer p) { + return iterator(p); + } - constexpr static bool fits_in_sso(size_type size) noexcept { - return size < min_cap; + constexpr const_iterator make_const_iterator(const_pointer p) const { + return const_iterator(p); } - constexpr void long_init() noexcept { - set_long(true); - set_long_data(nullptr); - set_long_size(0); - set_long_cap(0); + public: + static const size_type npos = static_cast(-1); + + constexpr basic_string() noexcept(std::is_nothrow_default_constructible_v) + : _rep(short_()) { + annotate_new(0); } - constexpr void short_init() noexcept { - set_long(false); - set_short_size(0); + constexpr /*explicit*/ basic_string(const allocator_type& a) noexcept + : _rep(short_()) + , _alloc(a) { + annotate_new(0); } - constexpr void default_init(size_type size) noexcept { - if (fits_in_sso(size)) - short_init(); - else - long_init(); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& str) + : _alloc(alloc_traits::select_on_container_copy_construction(str._alloc)) { + if (!str.is_long()) { + _rep = str._rep; + annotate_new(get_short_size()); + } else { + init_copy_ctor_external(std::to_address(str.get_long_pointer()), str.get_long_size()); + } } - constexpr auto& get_long_data() noexcept { - return _storage._long.data; + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS + basic_string(const basic_string& str, const allocator_type& a) + : _alloc(a) { + if (!str.is_long()) { + _rep = str._rep; + annotate_new(get_short_size()); + } else { + init_copy_ctor_external(std::to_address(str.get_long_pointer()), str.get_long_size()); + } } - constexpr const auto& get_long_data() const noexcept { - return _storage._long.data; + constexpr basic_string(basic_string&& str) noexcept + // Turning off ASan instrumentation for variable initialization with + // PLUGIFY_INTERNAL_MEMORY_ACCESS does not work consistently during + // initialization of r_, so we instead unpoison str's memory manually first. str's + // memory needs to be unpoisoned only in the case where it's a short string. + : _rep([](basic_string& s) -> decltype(s._rep)&& { + if (!s.is_long()) { + s.annotate_delete(); + } + return std::move(s._rep); + }(str)) + , _alloc(std::move(str._alloc)) { + str._rep = rep(); + str.annotate_new(0); + if (!is_long()) { + annotate_new(size()); + } } - constexpr auto& get_short_data() noexcept { - return _storage._short.data; + constexpr basic_string(basic_string&& str, const allocator_type& a) + : _alloc(a) { + if (str.is_long() && a != str._alloc) { // copy, not move + init(std::to_address(str.get_long_pointer()), str.get_long_size()); + } else { + if (std::is_constant_evaluated()) { + _rep = rep(); + } + if (!str.is_long()) { + str.annotate_delete(); + } + _rep = str._rep; + str._rep = rep(); + str.annotate_new(0); + if (!is_long() && this != std::addressof(str)) { + annotate_new(size()); + } + } } - constexpr const auto& get_short_data() const noexcept { - return _storage._short.data; + constexpr basic_string(const CharT* PLUGIFY_NO_NULL s) + requires(is_allocator) + { + PLUGIFY_ASSERT(s != nullptr, "basic_string(const char*) detected nullptr"); + init(s, traits_type::length(s)); } - constexpr void set_short_size(size_type size) noexcept { - _storage._short.size.spare_size = min_cap - (size & 0x7F); + constexpr basic_string(const CharT* PLUGIFY_NO_NULL s, const Allocator& a) + requires(is_allocator) + : _alloc(a) { + PLUGIFY_ASSERT(s != nullptr, "basic_string(const char*, allocator) detected nullptr"); + init(s, traits_type::length(s)); } - constexpr size_type get_short_size() const noexcept { - return min_cap - _storage._short.size.spare_size; + basic_string(std::nullptr_t) = delete; + + constexpr basic_string(const CharT* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "basic_string(const char*, n) detected nullptr"); + init(s, n); } - constexpr void set_long_size(size_type size) noexcept { - _storage._long.size = size; + constexpr basic_string(const CharT* s, size_type n, const Allocator& a) + : _alloc(a) { + PLUGIFY_ASSERT( + n == 0 || s != nullptr, + "basic_string(const char*, n, allocator) detected nullptr" + ); + init(s, n); } - constexpr size_type get_long_size() const noexcept { - return _storage._long.size; + constexpr basic_string(size_type n, CharT c) { + init(n, c); } - constexpr void set_long_cap(size_type cap) noexcept { - _storage._long.cap = (cap & 0x7FFFFFFFFFFFFFFF); + constexpr basic_string(basic_string&& str, size_type pos, const Allocator& alloc = Allocator()) + : basic_string(std::move(str), pos, npos, alloc) { } - constexpr size_type get_long_cap() const noexcept { - return _storage._long.cap; + constexpr basic_string( + basic_string&& str, + size_type pos, + size_type n, + const Allocator& alloc = Allocator() + ) + : _alloc(alloc) { + if (pos > str.size()) { + this->throw_out_of_range(); + } + + auto len = std::min(n, str.size() - pos); + if (alloc_traits::is_always_equal::value || alloc == str._alloc) { + move_assign(std::move(str), pos, len); + } else { + // Perform a copy because the allocators are not compatible. + init(str.data() + pos, len); + } } - constexpr void set_long_data(value_type* data) noexcept { - _storage._long.data = data; + constexpr basic_string(size_type n, CharT c, const Allocator& a) + requires(is_allocator) + : _alloc(a) { + init(n, c); } - constexpr bool is_long() const noexcept { - return _storage._long.is_long == true; + constexpr basic_string( + const basic_string& str, + size_type pos, + size_type n, + const Allocator& a = Allocator() + ) + : _alloc(a) { + size_type str_sz = str.size(); + if (pos > str_sz) { + this->throw_out_of_range(); + } + init(str.data() + pos, std::min(n, str_sz - pos)); } - constexpr void set_long(bool is_long) noexcept { - _storage._long.is_long = is_long; + constexpr basic_string(const basic_string& str, size_type pos, const Allocator& a = Allocator()) + : _alloc(a) { + size_type str_sz = str.size(); + if (pos > str_sz) { + this->throw_out_of_range(); + } + init(str.data() + pos, str_sz - pos); } - constexpr void set_size(size_type size) noexcept { - if (is_long()) - set_long_size(size); - else - set_short_size(size); + template T> + constexpr basic_string( + const T& t, + size_type pos, + size_type n, + const allocator_type& a = allocator_type() + ) + : _alloc(a) { + self_view sv0 = t; + self_view sv = sv0.substr(pos, n); + init(sv.data(), sv.size()); } - constexpr sview_type view() const noexcept { - return sview_type(data(), size()); + template T> + constexpr /*explicit*/ basic_string(const T& t) { + self_view sv = t; + init(sv.data(), sv.size()); } - constexpr void reallocate(size_type new_cap, bool copy_old) { - if (new_cap == get_long_cap()) - return; + template T> + constexpr /*explicit*/ basic_string(const T& t, const allocator_type& a) + : _alloc(a) { + self_view sv = t; + init(sv.data(), sv.size()); + } - auto old_len = get_long_size(); - auto old_cap = get_long_cap(); - auto& old_buffer = get_long_data(); + template + constexpr basic_string(InputIterator first, InputIterator last) { + init(first, last); + } - auto new_len = std::min(new_cap, old_len); - auto new_data = allocator_traits::allocate(_allocator, new_cap + 1); + template + constexpr basic_string(InputIterator first, InputIterator last, const allocator_type& a) + : _alloc(a) { + init(first, last); + } - if (old_buffer != nullptr) { - if (old_len != 0 && copy_old) - Traits::copy(new_data, old_buffer, new_len); - allocator_traits::deallocate(_allocator, old_buffer, old_cap + 1); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string(std::from_range_t, Range&& range, const allocator_type& a = allocator_type()) + : _alloc(a) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + init_with_size( + std::ranges::begin(range), + std::ranges::end(range), + std::ranges::distance(range) + ); + } else { + init_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } + } +#endif - set_long_data(new_data); - set_long_size(new_len); - set_long_cap(new_cap); + constexpr basic_string(std::initializer_list il) { + init(il.begin(), il.end()); } - constexpr void deallocate() { - if (is_long()) { - if (auto& buffer = get_long_data(); buffer != nullptr) { - allocator_traits::deallocate(_allocator, buffer, get_long_cap() + 1); - buffer = nullptr; - } - } + constexpr basic_string(std::initializer_list il, const Allocator& a) + : _alloc(a) { + init(il.begin(), il.end()); } - constexpr void grow_to(size_type new_cap) { - if (is_long() == true) { - reallocate(new_cap, true); - return; - } + inline constexpr ~basic_string() { + reset_internal_buffer(); + } - auto buffer = allocator_traits::allocate(_allocator, new_cap + 1); - auto len = get_short_size(); + constexpr operator self_view() const noexcept { + return self_view(begin(), end()); + } - Traits::copy(buffer, get_short_data(), len); - Traits::assign(buffer[len], _terminator); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string& operator=(const basic_string& str); - long_init(); - set_long_data(buffer); - set_long_size(len); - set_long_cap(new_cap); + template T> + constexpr basic_string& operator=(const T& t) { + self_view sv = t; + return assign(sv); } - constexpr void null_terminate() { - auto buffer = data(); - if (buffer == nullptr) [[unlikely]] - return; - Traits::assign(buffer[size()], _terminator); + constexpr basic_string& operator=(basic_string&& str + ) noexcept(alloc_traits::propagate_on_container_move_assignment::value) { + move_assign( + str, + std::integral_constant() + ); + return *this; } - constexpr bool addr_in_range(const_pointer ptr) const noexcept { - if (std::is_constant_evaluated()) - return false; - else - return data() <= ptr && ptr <= data() + size(); + constexpr basic_string& operator=(std::initializer_list il) { + return assign(il.begin(), il.size()); } - template - constexpr void internal_replace_impl(const F& func, size_type pos, size_type oldcount, size_type count) { - auto cap = capacity(); - auto sz = size(); + constexpr basic_string& operator=(const value_type* PLUGIFY_NO_NULL s) { + return assign(s); + } - auto rsz = sz - oldcount + count; + basic_string& operator=(std::nullptr_t) = delete; + constexpr basic_string& operator=(value_type c); - if (cap < rsz) - grow_to(rsz); + constexpr iterator begin() noexcept { + return make_iterator(get_pointer()); + } - if (oldcount != count) - Traits::move(data() + pos + count, data() + pos + oldcount, sz - pos - oldcount); + constexpr const_iterator begin() const noexcept { + return make_const_iterator(get_pointer()); + } - func(); + constexpr iterator end() noexcept { + return make_iterator(get_pointer() + size()); + } - set_size(rsz); - null_terminate(); + constexpr const_iterator end() const noexcept { + return make_const_iterator(get_pointer() + size()); } - constexpr void internal_replace(size_type pos, const_pointer str, size_type oldcount, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_replace_impl([&]() { Traits::copy(data() + pos, rstr.data(), count); }, pos, oldcount, count); - } else - internal_replace_impl([&]() { Traits::copy(data() + pos, str, count); }, pos, oldcount, count); + constexpr reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); } - constexpr void internal_replace(size_type pos, value_type ch, size_type oldcount, size_type count) { - internal_replace_impl([&]() { Traits::assign(data() + pos, count, ch); }, pos, oldcount, count); + constexpr const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); } - template - constexpr void internal_insert_impl(const F& func, size_type pos, size_type count) { - if (count == 0) [[unlikely]] - return; + constexpr reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - auto cap = capacity(); - auto sz = size(); - auto rsz = sz + count; + constexpr const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - if (cap < rsz) - grow_to(rsz); + constexpr const_iterator cbegin() const noexcept { + return begin(); + } - Traits::move(data() + pos + count, data() + pos, sz - pos); - func(); + constexpr const_iterator cend() const noexcept { + return end(); + } - set_size(rsz); - null_terminate(); + constexpr const_reverse_iterator crbegin() const noexcept { + return rbegin(); } - constexpr void internal_insert(size_type pos, const_pointer str, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_insert_impl([&]() { Traits::copy(data() + pos, rstr.data(), count); }, pos, count); - } else - internal_insert_impl([&]() { Traits::copy(data() + pos, str, count); }, pos, count); + constexpr const_reverse_iterator crend() const noexcept { + return rend(); } - constexpr void internal_insert(size_type pos, value_type ch, size_type count) { - internal_insert_impl([&]() { Traits::assign(data() + pos, count, ch); }, pos, count); + constexpr size_type size() const noexcept { + return is_long() ? get_long_size() : get_short_size(); } - template - constexpr void internal_append_impl(const F& func, size_type count) { - if (count == 0) [[unlikely]] - return; + constexpr size_type length() const noexcept { + return size(); + } - auto cap = capacity(); - auto sz = size(); - auto rsz = sz + count; + constexpr size_type max_size() const noexcept { + constexpr bool uses_lsb = endian_factor == 2; - if (cap < rsz) - grow_to(rsz); + if (size_type m = alloc_traits::max_size(_alloc); + m <= std::numeric_limits::max() / 2) { + size_type res = m - alignment; - func(sz); - set_size(rsz); - null_terminate(); - } + // When the endian_factor == 2, our string representation assumes that the capacity + // (including the null terminator) is always even, so we have to make sure the + // lowest bit isn't set when the string grows to max_size() + if constexpr (uses_lsb) { + res &= ~size_type(1); + } - constexpr void internal_append(const_pointer str, size_type count) { - if (addr_in_range(str)) { - basic_string rstr(str, count); - internal_append_impl([&](size_type pos) { Traits::copy(data() + pos, rstr.data(), count); }, count); - } else - internal_append_impl([&](size_type pos) { Traits::copy(data() + pos, str, count); }, count); + // We have to allocate space for the null terminator, but max_size() doesn't include + // it. + return res - 1; + } else { + return uses_lsb ? m - alignment - 1 : (m / 2) - alignment - 1; + } } - constexpr void internal_append(value_type ch, size_type count) { - internal_append_impl([&](size_type pos) { Traits::assign(data() + pos, count, ch); }, count); + constexpr size_type capacity() const noexcept { + return (is_long() ? get_long_cap() : min_cap) - 1; } - template - constexpr void internal_assign_impl(const F& func, size_type size, bool copy_old) { - if (fits_in_sso(size)) { - if (is_long() == true) { - deallocate(); - short_init(); - } + constexpr void resize(size_type n, value_type c); - set_short_size(size); - func(get_short_data()); - null_terminate(); - } else { - if (is_long() == false) - long_init(); - if (get_long_cap() < size) - reallocate(size, copy_old); + constexpr void resize(size_type n) { + resize(n, value_type()); + } + + constexpr void reserve(size_type requested_capacity); - func(get_long_data()); - set_long_size(size); - null_terminate(); +#if PLUGIFY_HAS_CXX23 + /*template + constexpr void resize_and_overwrite(size_type n, Op op) { + size_type sz = size(); + size_type cap = capacity(); + if (n > cap) { + grow_by_without_replace(cap, n - cap, sz, sz, 0); } - } + annotate_delete(); + set_size(n); + annotate_new(n); + erase_to_end(std::move(op)(data(), auto(n))); + }*/ +#endif + + constexpr void shrink_to_fit() noexcept; + constexpr void clear() noexcept; - constexpr void internal_assign(const_pointer str, size_type size, bool copy_old = false) { - if (addr_in_range(str)) { - basic_string rstr(str, size); - internal_assign_impl([&](auto data) { Traits::copy(data, rstr.data(), size); }, size, copy_old); - } else - internal_assign_impl([&](auto data) { Traits::copy(data, str, size); }, size, copy_old); + [[nodiscard]] constexpr bool empty() const noexcept { + return size() == 0; } - constexpr void internal_assign(value_type ch, size_type count, bool copy_old = false) { - internal_assign_impl([&](auto data) { Traits::assign(data, count, ch); }, count, copy_old); + constexpr const_reference operator[](size_type pos) const noexcept { + PLUGIFY_ASSERT(pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(pos) && !fits_in_sso(pos)) { + return *(get_long_pointer() + pos); + } + return *(data() + pos); } - public: - explicit constexpr basic_string(detail::uninitialized_size_tag, size_type size, const Allocator& allocator) - : _allocator(allocator) { - PLUGIFY_ASSERT(size <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - if (fits_in_sso(size)) - short_init(); - else { - long_init(); - reallocate(size, false); + constexpr reference operator[](size_type pos) noexcept { + PLUGIFY_ASSERT(pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(pos) && !fits_in_sso(pos)) { + return *(get_long_pointer() + pos); } - set_size(size); + return *(get_pointer() + pos); } - constexpr basic_string() noexcept(std::is_nothrow_default_constructible::value) - : basic_string(Allocator()) {} + constexpr const_reference at(size_type n) const; + constexpr reference at(size_type n); - explicit constexpr basic_string(const Allocator& allocator) noexcept - : _allocator(allocator) { - short_init(); + constexpr basic_string& operator+=(const basic_string& str) { + return append(str); } - constexpr basic_string(size_type count, value_type ch, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(ch, count); + template T> + constexpr basic_string& operator+=(const T& t) { + self_view sv = t; + return append(sv); } - constexpr basic_string(const basic_string& str, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - auto len = std::min(count, str.size() - pos); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str.data() + pos, len); + constexpr basic_string& operator+=(const value_type* PLUGIFY_NO_NULL s) { + return append(s); } - constexpr basic_string(const basic_string& str, size_type pos, const Allocator& allocator = Allocator()) - : basic_string(str, pos, npos, allocator) {} - constexpr basic_string(const value_type* str, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str, count); + constexpr basic_string& operator+=(value_type c) { + push_back(c); + return *this; } - constexpr basic_string(const value_type* str, const Allocator& allocator = Allocator()) - : basic_string(str, Traits::length(str), allocator) {} - - template - constexpr basic_string(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - if constexpr (std::contiguous_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(first), len); - } else { - if constexpr (std::random_access_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - reserve(len); - } - for (auto it = first; it != last; ++it) { - push_back(*it); - } - } + constexpr basic_string& operator+=(std::initializer_list il) { + return append(il); } - constexpr basic_string(const basic_string& str, const Allocator& allocator) - : _allocator(allocator) { - auto len = str.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(str.data(), len); + constexpr basic_string& append(const basic_string& str) { + return append(str.data(), str.size()); } - constexpr basic_string(const basic_string& str) - : basic_string(str, str.get_allocator()) {} - constexpr basic_string(basic_string&& str) noexcept(std::is_nothrow_move_constructible::value) - : _allocator(std::move(str._allocator)), _storage(std::move(str._storage)) { - str.short_init(); + template T> + constexpr basic_string& append(const T& t) { + self_view sv = t; + return append(sv.data(), sv.size()); } - constexpr basic_string(basic_string&& str, const Allocator& allocator) - : _allocator(allocator) { - if constexpr (allocator_traits::is_always_equal::value) { - std::swap(_storage, str._storage); - } else { - if (!str.is_long() || get_allocator() == str.get_allocator()) { - std::swap(_storage, str._storage); - } else { - internal_assign(str.data(), str.size()); - str.deallocate(); - } + constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); + + template T> + constexpr basic_string& append(const T& t, size_type pos, size_type n = npos) { + self_view sv = t; + size_type sz = sv.size(); + if (pos > sz) { + throw_out_of_range(); } - str.short_init(); + return append(sv.data() + pos, std::min(n, sz - pos)); } - constexpr basic_string(std::initializer_list list, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - auto len = list.size(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(list.begin()), len); + constexpr basic_string& append(const value_type* s, size_type n); + constexpr basic_string& append(const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& append(size_type n, value_type c); + + template + constexpr basic_string& append(InputIterator first, InputIterator last) { + const basic_string temp(first, last, _alloc); + append(temp.data(), temp.size()); + return *this; } - template - requires (std::is_convertible_v) - constexpr basic_string(const Type& t, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - auto sv = sview_type(t); - PLUGIFY_ASSERT(pos <= sv.length(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - auto ssv = sv.substr(pos, count); - auto len = ssv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(ssv.data(), len); + template + constexpr basic_string& append(ForwardIterator first, ForwardIterator last) { + size_type sz = size(); + size_type cap = capacity(); + size_type n = static_cast(std::distance(first, last)); + if (n == 0) { + return *this; + } + + if (string_is_trivial_iterator_v && !addr_in_range(*first)) { + if (cap - sz < n) { + grow_by_without_replace(cap, sz + n - cap, sz, sz, 0); + } + annotate_increase(n); + auto end = copy_non_overlapping_range(first, last, std::to_address(get_pointer() + sz)); + traits_type::assign(*end, value_type()); + set_size(sz + n); + return *this; + } else { + const basic_string temp(first, last, _alloc); + return append(temp.data(), temp.size()); + } } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string(const Type& t, const Allocator& allocator = Allocator()) - : _allocator(allocator) { - sview_type sv(t); - auto len = sv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error); - internal_assign(sv.data(), len); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& append_range(Range&& range) { + insert_range(end(), std::forward(range)); + return *this; } +#endif - constexpr basic_string(basic_string&& str, size_type pos, size_type count, const Allocator& allocator = Allocator()) - : basic_string(std::move(str), allocator) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::basic_string(): pos out of range", std::out_of_range); - erase(pos, count); + constexpr basic_string& append(std::initializer_list il) { + return append(il.begin(), il.size()); } - constexpr basic_string(basic_string&& str, size_type pos, const Allocator& allocator = Allocator()) - : basic_string(std::move(str), pos, npos, allocator) {} + constexpr void push_back(value_type c); + constexpr void pop_back(); -#if __cplusplus > 202002L - basic_string(std::nullptr_t) = delete; -#endif + constexpr reference front() noexcept { + PLUGIFY_ASSERT(!empty(), "string::front(): string is empty"); + return *get_pointer(); + } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string(std::from_range_t, Range&& range, const Allocator& allocator = Allocator()) - : basic_string(std::ranges::begin(range), std::ranges::end(range), allocator) {} -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + constexpr const_reference front() const noexcept { + PLUGIFY_ASSERT(!empty(), "string::front(): string is empty"); + return *data(); + } - constexpr ~basic_string() { - deallocate(); + constexpr reference back() noexcept { + PLUGIFY_ASSERT(!empty(), "string::back(): string is empty"); + return *(get_pointer() + size() - 1); } - constexpr basic_string& operator=(const basic_string& str) { - return assign(str); + constexpr const_reference back() const noexcept { + PLUGIFY_ASSERT(!empty(), "string::back(): string is empty"); + return *(data() + size() - 1); } - constexpr basic_string& operator=(basic_string&& str) noexcept( - allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value) { - return assign(std::move(str)); + template T> + constexpr basic_string& assign(const T& t) { + self_view sv = t; + return assign(sv.data(), sv.size()); } - constexpr basic_string& operator=(const value_type* str) { - return assign(str, Traits::length(str)); + constexpr void move_assign(basic_string&& str, size_type pos, size_type len) { + // Pilfer the allocation from str. + PLUGIFY_ASSERT(_alloc == str._alloc, "move_assign called with wrong allocator"); + size_type old_sz = str.size(); + if (!str.is_long()) { + str.annotate_delete(); + } + _rep = str._rep; + str._rep = rep(); + str.annotate_new(0); + + Traits::move(data(), data() + pos, len); + set_size(len); + Traits::assign(data()[len], value_type()); + + if (!is_long()) { + annotate_new(len); + } else if (old_sz > len) { + annotate_shrink(old_sz); + } } - constexpr basic_string& operator=(value_type ch) { - return assign(std::addressof(ch), 1); + constexpr basic_string& assign(const basic_string& str) { + return *this = str; } - constexpr basic_string& operator=(std::initializer_list list) { - return assign(list.begin(), list.size()); + constexpr basic_string& + assign(basic_string&& str) noexcept(alloc_traits::propagate_on_container_move_assignment::value + ) { + *this = std::move(str); + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& operator=(const Type& t) { - sview_type sv(t); - return assign(sv); + constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); + + template T> + constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos) { + self_view sv = t; + size_type sz = sv.size(); + if (pos > sz) { + throw_out_of_range(); + } + return assign(sv.data() + pos, std::min(n, sz - pos)); } -#if __cplusplus > 202002L - constexpr basic_string& operator=(std::nullptr_t) = delete; -#endif + constexpr basic_string& assign(const value_type* s, size_type n); + constexpr basic_string& assign(const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& assign(size_type n, value_type c); - constexpr basic_string& assign(size_type count, value_type ch) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(ch, count); + template + constexpr basic_string& assign(InputIterator first, InputIterator last) { + assign_with_sentinel(first, last); return *this; } - constexpr basic_string& assign(const basic_string& str, size_type pos, size_type count = npos) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::assign(): pos out of range", std::out_of_range); - internal_assign(str.data(), std::min(count, str.size() - pos)); + template + constexpr basic_string& assign(ForwardIterator first, ForwardIterator last) { + if (string_is_trivial_iterator_v) { + size_type n = static_cast(std::distance(first, last)); + assign_trivial(first, last, n); + } else { + assign_with_sentinel(first, last); + } + return *this; } - constexpr basic_string& assign(const basic_string& str) { - if (this == &str) [[unlikely]] - return *this; +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& assign_range(Range&& range) { + if constexpr (string_is_trivial_iterator_v> + && (std::ranges::forward_range || std::ranges::sized_range) ) { + size_type n = static_cast(std::ranges::distance(range)); + assign_trivial(std::ranges::begin(range), std::ranges::end(range), n); - if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != str.get_allocator()) { - deallocate(); - short_init(); - } - } - _allocator = str._allocator; + } else { + assign_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } - internal_assign(str.data(), str.size()); return *this; } +#endif - constexpr basic_string& assign(basic_string&& str) noexcept( - allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value) { - if (this == &str) [[unlikely]] - return *this; + constexpr basic_string& assign(std::initializer_list il) { + return assign(il.begin(), il.size()); + } - if constexpr (allocator_traits::propagate_on_container_move_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != str.get_allocator()) { - deallocate(); - short_init(); - } - } - _allocator = std::move(str._allocator); + constexpr basic_string& insert(size_type pos1, const basic_string& str) { + return insert(pos1, str.data(), str.size()); + } + + template T> + constexpr basic_string& insert(size_type pos1, const T& t) { + self_view sv = t; + return insert(pos1, sv.data(), sv.size()); + } + + template T> + constexpr basic_string& + insert(size_type pos1, const T& t, size_type pos2, size_type n = npos) { + self_view sv = t; + size_type str_sz = sv.size(); + if (pos2 > str_sz) { + throw_out_of_range(); } + return insert(pos1, sv.data() + pos2, std::min(n, str_sz - pos2)); + } + + constexpr basic_string& + insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos); + constexpr basic_string& insert(size_type pos, const value_type* s, size_type n); + constexpr basic_string& insert(size_type pos, const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& insert(size_type pos, size_type n, value_type c); + constexpr iterator insert(const_iterator pos, value_type c); + +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr iterator insert_range(const_iterator position, Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + return insert_with_size(position, std::ranges::begin(range), std::ranges::end(range), n); - if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) { - deallocate(); - short_init(); - std::swap(_storage, str._storage); } else { - if (get_allocator() == str.get_allocator()) { - deallocate(); - short_init(); - std::swap(_storage, str._storage); - } else { - internal_assign(str.data(), str.size()); - } + basic_string temp(std::from_range, std::forward(range), _alloc); + return insert(position, temp.data(), temp.data() + temp.size()); } + } +#endif - return *this; + constexpr iterator insert(const_iterator pos, size_type n, value_type c) { + difference_type p = pos - begin(); + insert(static_cast(p), n, c); + return begin() + p; } - constexpr basic_string& assign(const value_type* str, size_type count) { - PLUGIFY_ASSERT(count <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(str, count); - return *this; + template + constexpr iterator insert(const_iterator pos, InputIterator first, InputIterator last) { + const basic_string temp(first, last, _alloc); + return insert(pos, temp.data(), temp.data() + temp.size()); } - constexpr basic_string& assign(const value_type* str) { - return assign(str, Traits::length(str)); + template + constexpr iterator insert(const_iterator pos, ForwardIterator first, ForwardIterator last) { + auto n = static_cast(std::distance(first, last)); + return insert_with_size(pos, first, last, n); } - template - constexpr basic_string& assign(InputIterator first, InputIterator last) { - if constexpr (std::contiguous_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(first), len); - } else { - if constexpr (std::random_access_iterator) { - auto len = size_type(std::distance(first, last)); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - reserve(len); - } - for (auto it = first; it != last; ++it) { - push_back(*it); - } - } - return *this; + constexpr iterator insert(const_iterator pos, std::initializer_list il) { + return insert(pos, il.begin(), il.end()); } - constexpr basic_string& assign(std::initializer_list list) { - auto len = list.size(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - internal_assign(const_pointer(list.begin()), len); - return *this; + constexpr basic_string& erase(size_type pos = 0, size_type n = npos); + constexpr iterator erase(const_iterator pos); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str) { + return replace(pos1, n1, str.data(), str.size()); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& assign(const Type& t) { - sview_type sv(t); - return assign(sv.data(), sv.length()); + template T> + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t) { + self_view sv = t; + return replace(pos1, n1, sv.data(), sv.size()); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& assign(const Type& t, size_type pos, size_type count = npos) { - auto sv = sview_type(t).substr(pos, count); - auto len = sv.length(); - PLUGIFY_ASSERT(len <= max_size(), "plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error); - return assign(sv.data(), len); + constexpr basic_string& + replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos); + + template T> + constexpr basic_string& + replace(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) { + self_view sv = t; + size_type str_sz = sv.size(); + if (pos2 > str_sz) { + throw_out_of_range(); + } + return replace(pos1, n1, sv.data() + pos2, std::min(n2, str_sz - pos2)); } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string& assign_range(Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(str.size() <= max_size(), "plg::basic_string::assign_range(): resulted string size would exceed max_size()", std::length_error); - return assign(std::move(str)); + constexpr basic_string& + replace(size_type pos, size_type n1, const value_type* s, size_type n2); + constexpr basic_string& + replace(size_type pos, size_type n1, const value_type* PLUGIFY_NO_NULL s); + constexpr basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); + + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, const basic_string& str) { + return replace( + static_cast(i1 - begin()), + static_cast(i2 - i1), + str.data(), + str.size() + ); } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr allocator_type get_allocator() const noexcept { - return _allocator; + template T> + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t) { + self_view sv = t; + return replace(i1 - begin(), i2 - i1, sv); } - constexpr reference operator[](size_type pos) { - return data()[pos]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), s, n); } - constexpr const_reference operator[](size_type pos) const { - return data()[pos]; + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), s); } - constexpr reference at(size_type pos) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::at(): pos out of range", std::out_of_range); - return data()[pos]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, size_type n, value_type c) { + return replace(static_cast(i1 - begin()), static_cast(i2 - i1), n, c); } - constexpr const_reference at(size_type pos) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::at(): pos out of range", std::out_of_range); - return data()[pos]; + template + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2) { + const basic_string temp(j1, j2, _alloc); + return replace(i1, i2, temp); } - constexpr reference front() { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::front(): vector is empty", std::length_error); - return data()[0]; +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr basic_string& + replace_with_range(const_iterator i1, const_iterator i2, Range&& range) { + basic_string temp(std::from_range, std::forward(range), _alloc); + return replace(i1, i2, temp); } +#endif - constexpr const_reference front() const { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::front(): vector is empty", std::length_error); - return data()[0]; + constexpr basic_string& + replace(const_iterator i1, const_iterator i2, std::initializer_list il) { + return replace(i1, i2, il.begin(), il.end()); } - constexpr reference back() { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::back(): vector is empty", std::length_error); - return data()[size() - 1]; + constexpr size_type copy(value_type* s, size_type n, size_type pos = 0) const; + + constexpr basic_string substr(size_type pos = 0, size_type n = npos) const& { + return basic_string(*this, pos, n); } - constexpr const_reference back() const { - PLUGIFY_ASSERT(!empty(), "plg::basic_string::back(): vector is empty", std::length_error); - return data()[size() - 1]; + constexpr basic_string substr(size_type pos = 0, size_type n = npos) && { + return basic_string(std::move(*this), pos, n); + } + + constexpr void swap(basic_string& str) noexcept; + + // [string.ops] + // ------------ + + constexpr const value_type* c_str() const noexcept { + return data(); } constexpr const value_type* data() const noexcept { - return is_long() ? get_long_data() : get_short_data(); + return std::to_address(get_pointer()); } constexpr value_type* data() noexcept { - return is_long() ? get_long_data() : get_short_data(); + return std::to_address(get_pointer()); } - constexpr const value_type* c_str() const noexcept { - return data(); + constexpr allocator_type get_allocator() const noexcept { + return _alloc; } - constexpr operator sview_type() const noexcept { - return view(); + // find + + constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find(str.data(), pos, str.size()); } - constexpr iterator begin() noexcept { - return data(); + template T> + constexpr size_type find(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find(sv.data(), pos, sv.size()); } - constexpr const_iterator begin() const noexcept { - return data(); + constexpr size_type find(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find(): received nullptr"); + return operator self_view().find(s, pos, n); } - constexpr const_iterator cbegin() const noexcept { - return data(); + constexpr size_type + find(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find(): received nullptr"); + return operator self_view().find(s, pos, traits_type::length(s)); } - constexpr iterator end() noexcept { - return data() + size(); + constexpr size_type find(value_type c, size_type pos = 0) const noexcept { + return operator self_view().find(c, pos); } - constexpr const_iterator end() const noexcept { - return data() + size(); + // rfind + + constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().rfind(str.data(), pos, str.size()); } - constexpr const_iterator cend() const noexcept { - return data() + size(); + template T> + constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().rfind(sv.data(), pos, sv.size()); } - constexpr reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); + constexpr size_type rfind(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::rfind(): received nullptr"); + return operator self_view().rfind(s, pos, n); } - constexpr const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); + constexpr size_type + rfind(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::rfind(): received nullptr"); + return operator self_view().rfind(s, pos, traits_type::length(s)); } - constexpr const_reverse_iterator crbegin() const noexcept { - return const_reverse_iterator(cend()); + constexpr size_type rfind(value_type c, size_type pos = npos) const noexcept { + return operator self_view().rfind(c, pos); } - constexpr reverse_iterator rend() noexcept { - return reverse_iterator(begin()); + // find_first_of + + constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find_first_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find_first_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_first_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_first_of(): received nullptr"); + return operator self_view().find_first_of(s, pos, n); + } + + constexpr size_type + find_first_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_first_of(): received nullptr"); + return operator self_view().find_first_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_first_of(value_type c, size_type pos = 0) const noexcept { + return find(c, pos); + } + + // find_last_of + + constexpr size_type + find_last_of(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().find_last_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_last_of(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().find_last_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_last_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_last_of(): received nullptr"); + return operator self_view().find_last_of(s, pos, n); + } + + constexpr size_type + find_last_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_last_of(): received nullptr"); + return operator self_view().find_last_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_last_of(value_type c, size_type pos = npos) const noexcept { + return rfind(c, pos); + } + + // find_first_not_of + + constexpr size_type + find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept { + return operator self_view().find_first_not_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept { + self_view sv = t; + return operator self_view().find_first_not_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_first_not_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_first_not_of(): received nullptr"); + return operator self_view().find_first_not_of(s, pos, n); + } + + constexpr size_type + find_first_not_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = 0) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_first_not_of(): received nullptr"); + return operator self_view().find_first_not_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept { + return operator self_view().find_first_not_of(c, pos); + } + + // find_last_not_of + + constexpr size_type + find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept { + return operator self_view().find_last_not_of(str.data(), pos, str.size()); + } + + template T> + constexpr size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept { + self_view sv = t; + return operator self_view().find_last_not_of(sv.data(), pos, sv.size()); + } + + constexpr size_type + find_last_not_of(const value_type* s, size_type pos, size_type n) const noexcept { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::find_last_not_of(): received nullptr"); + return operator self_view().find_last_not_of(s, pos, n); + } + + constexpr size_type + find_last_not_of(const value_type* PLUGIFY_NO_NULL s, size_type pos = npos) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::find_last_not_of(): received nullptr"); + return operator self_view().find_last_not_of(s, pos, traits_type::length(s)); + } + + constexpr size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept { + return operator self_view().find_last_not_of(c, pos); + } + + // compare + + constexpr int compare(const basic_string& str) const noexcept { + return compare(self_view(str)); + } + + template T> + constexpr int compare(const T& t) const noexcept { + self_view sv = t; + size_t lhs_sz = size(); + size_t rhs_sz = sv.size(); + int result = traits_type::compare(data(), sv.data(), std::min(lhs_sz, rhs_sz)); + if (result != 0) { + return result; + } + if (lhs_sz < rhs_sz) { + return -1; + } + if (lhs_sz > rhs_sz) { + return 1; + } + return 0; + } + + template T> + constexpr int compare(size_type pos1, size_type n1, const T& t) const { + self_view sv = t; + return compare(pos1, n1, sv.data(), sv.size()); + } + + constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const { + return compare(pos1, n1, str.data(), str.size()); + } + + constexpr int compare( + size_type pos1, + size_type n1, + const basic_string& str, + size_type pos2, + size_type n2 = npos + ) const { + return compare(pos1, n1, self_view(str), pos2, n2); + } + + template T> + inline constexpr int + compare(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) const { + self_view sv = t; + return self_view(*this).substr(pos1, n1).compare(sv.substr(pos2, n2)); + } + + constexpr int compare(const value_type* PLUGIFY_NO_NULL s) const noexcept { + PLUGIFY_ASSERT(s != nullptr, "string::compare(): received nullptr"); + return compare(0, npos, s, traits_type::length(s)); + } + + constexpr int + compare(size_type pos1, size_type n1, const value_type* PLUGIFY_NO_NULL s) const { + PLUGIFY_ASSERT(s != nullptr, "string::compare(): received nullptr"); + return compare(pos1, n1, s, traits_type::length(s)); + } + + constexpr int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; + + // starts_with + + constexpr bool starts_with(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).starts_with(sv); + } + + constexpr bool starts_with(value_type c) const noexcept { + return !empty() && Traits::eq(front(), c); + } + + constexpr bool starts_with(const value_type* PLUGIFY_NO_NULL s) const noexcept { + return starts_with(self_view(s)); + } + + // ends_with + + constexpr bool ends_with(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).ends_with(sv); + } + + constexpr bool ends_with(value_type c) const noexcept { + return !empty() && Traits::eq(back(), c); + } + + constexpr bool ends_with(const value_type* PLUGIFY_NO_NULL s) const noexcept { + return ends_with(self_view(s)); + } + + // contains + + constexpr bool contains(self_view sv) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).contains(sv); + } + + constexpr bool contains(value_type c) const noexcept { + return self_view(typename self_view::assume_valid(), data(), size()).contains(c); + } + + constexpr bool contains(const value_type* PLUGIFY_NO_NULL s) const { + return self_view(typename self_view::assume_valid(), data(), size()).contains(s); + } + + [[nodiscard]] constexpr bool invariants() const; + + private: + [[nodiscard]] constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS bool is_long() const noexcept { + if (std::is_constant_evaluated() && __builtin_constant_p(_rep.l._is_long)) { + return _rep.l._is_long; + } + return _rep.s._is_long; + } + + static constexpr bool fits_in_sso(size_type sz) { + return sz < min_cap; + } + + template + constexpr void assign_trivial(Iterator first, Sentinel last, size_type n); + + template + constexpr void assign_with_sentinel(Iterator first, Sentinel last); + + // Copy [first, last) into [dest, dest + (last - first)). Assumes that the ranges don't + // overlap. + template + static constexpr value_type* + copy_non_overlapping_range(ForwardIter first, Sent last, value_type* dest) { + if constexpr (std::contiguous_iterator + && std::is_same_v> + && std::is_same_v) { + PLUGIFY_ASSERT( + !is_overlapping_range(std::to_address(first), std::to_address(last), dest), + "copy_non_overlapping_range called with an overlapping range!" + ); + traits_type::copy(dest, std::to_address(first), last - first); + return dest + (last - first); + } else { + for (; first != last; ++first) { + traits_type::assign(*dest++, *first); + } + return dest; + } + } + + template + constexpr iterator + insert_from_safe_copy(size_type n, size_type ip, ForwardIterator first, Sentinel last) { + size_type sz = size(); + size_type cap = capacity(); + value_type* p; + if (cap - sz >= n) { + annotate_increase(n); + p = std::to_address(get_pointer()); + size_type n_move = sz - ip; + if (n_move != 0) { + traits_type::move(p + ip + n, p + ip, n_move); + } + } else { + grow_by_without_replace(cap, sz + n - cap, sz, ip, 0, n); + p = std::to_address(get_long_pointer()); + } + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + copy_non_overlapping_range(std::move(first), std::move(last), p + ip); + + return begin() + ip; + } + + template + constexpr iterator + insert_with_size(const_iterator pos, Iterator first, Sentinel last, size_type n); + + // internal buffer accessors + // ------------------------- + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void set_short_size(size_type s) noexcept { + PLUGIFY_ASSERT( + s < min_cap, + "s should never be greater than or equal to the short string capacity" + ); + _rep.s._spare_size = (min_cap - 1) - s; + _rep.s._is_long = false; + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS size_type get_short_size() const noexcept { + PLUGIFY_ASSERT(!_rep.s._is_long, "String has to be short when trying to get the short size"); + return (min_cap - 1) - _rep.s._spare_size; + } + + constexpr void set_long_size(size_type s) noexcept { + _rep.l._size = s; + } + + constexpr size_type get_long_size() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long size"); + return _rep.l._size; + } + + constexpr void set_size(size_type s) noexcept { + if (is_long()) { + set_long_size(s); + } else { + set_short_size(s); + } } - constexpr const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); + constexpr size_type get_long_cap() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long capacity"); + return _rep.l._cap * endian_factor; + } + + constexpr pointer get_long_pointer() noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long pointer"); + return PLUGIFY_ASAN_VOLATILE_WRAPPER(_rep.l._data); + } + + constexpr const_pointer get_long_pointer() const noexcept { + PLUGIFY_ASSERT(_rep.l._is_long, "String has to be long when trying to get the long pointer"); + return PLUGIFY_ASAN_VOLATILE_WRAPPER(_rep.l._data); + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS pointer get_short_pointer() noexcept { + return PLUGIFY_ASAN_VOLATILE_WRAPPER( + std::pointer_traits::pointer_to(_rep.s._data[0]) + ); + } + + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS const_pointer get_short_pointer() const noexcept { + return PLUGIFY_ASAN_VOLATILE_WRAPPER( + std::pointer_traits::pointer_to(_rep.s._data[0]) + ); + } + + constexpr pointer get_pointer() noexcept { + return is_long() ? get_long_pointer() : get_short_pointer(); + } + + constexpr const_pointer get_pointer() const noexcept { + return is_long() ? get_long_pointer() : get_short_pointer(); + } + + // Internal buffer management + // -------------------------- + // + // These functions are only responsible for managing the buffer itself, not the value inside + // the buffer. As such, none of these facilities ensure that there is a null terminator at + // `data()[size()]`. + + // Allocate a buffer of capacity size with alloc and return it + static constexpr long_ allocate_long_buffer(Allocator& alloc, size_type capacity) { + auto buffer = allocate_at_least(alloc, recommend(capacity) + 1); + + if (std::is_constant_evaluated()) { + for (size_type i = 0; i != buffer.count; ++i) { + std::construct_at(std::addressof(buffer.ptr[i])); + } + } + + return long_(buffer, capacity); + } + + // Deallocate the long buffer if it exists and clear the short buffer so we are an empty + // string + constexpr void reset_internal_buffer() { + annotate_delete(); + if (is_long()) { + alloc_traits::deallocate(_alloc, get_long_pointer(), get_long_cap()); + } + _rep.s = short_(); + } + + // Replace the current buffer with alloc; the first size elements constitute a string + constexpr void replace_internal_buffer(long_ alloc) { + reset_internal_buffer(); + _rep.l = alloc; + } + + // Initialize the internal buffer to hold size elements + // The elements and null terminator have to be set by the caller + constexpr pointer init_internal_buffer(size_type size) { + if (std::is_constant_evaluated()) { + _rep = rep(); + } + + if (size > max_size()) { + throw_length_error(); + } + + if (fits_in_sso(size)) { + set_short_size(size); + annotate_new(size); + return get_short_pointer(); + } else { + _rep.l = allocate_long_buffer(_alloc, size); + annotate_new(size); + return get_long_pointer(); + } + } + + // ASan annotation helpers + // ----------------------- + + // The following functions are no-ops outside of AddressSanitizer mode. + constexpr void annotate_contiguous_container( + const void* old_mid, + const void* new_mid + ) const { + if (!is_long()) { + return; + } + + plg::annotate_contiguous_container( + data(), + data() + capacity() + 1, + old_mid, + new_mid + ); } - constexpr const_reverse_iterator crend() const noexcept { - return const_reverse_iterator(cbegin()); + constexpr void annotate_new(size_type current_size) const noexcept { + annotate_contiguous_container(data() + capacity() + 1, data() + current_size + 1); } - constexpr bool empty() const noexcept { - return size() == 0; + constexpr void annotate_delete() const noexcept { + annotate_contiguous_container(data() + size() + 1, data() + capacity() + 1); } - constexpr size_type size() const noexcept { - return is_long() ? get_long_size() : get_short_size(); + constexpr void annotate_increase(size_type n) const noexcept { + annotate_contiguous_container(data() + size() + 1, data() + size() + 1 + n); } - constexpr size_type length() const noexcept { - return size(); + constexpr void annotate_shrink(size_type old_size) const noexcept { + annotate_contiguous_container(data() + old_size + 1, data() + size() + 1); } - constexpr size_type max_size() const noexcept { - // const size_type alignment = 16; - // size_type m = allocator_traits::max_size(_allocator); - // if (m <= std::numeric_limits::max() / 2) - // return m - alignment; - // else - //= return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ? m - alignment : (m / 2) - alignment; - return (allocator_traits::max_size(_allocator) - 1) / 2; - } + // Disable ASan annotations and enable them again when going out of scope. It is assumed + // that the string is in a valid state at that point, so `size()` can be called safely. + struct [[nodiscard]] annotation_guard { + annotation_guard(const annotation_guard&) = delete; + annotation_guard& operator=(const annotation_guard&) = delete; - constexpr size_type capacity() const noexcept { - return is_long() ? get_long_cap() : min_cap; - } + constexpr annotation_guard(basic_string& str) + : str(str) { + str.annotate_delete(); + } - constexpr void reserve(size_type cap) { - PLUGIFY_ASSERT(cap <= max_size(), "plg::basic_string::reserve(): allocated memory size would exceed max_size()", std::length_error); - if (cap <= capacity()) - return; + constexpr ~annotation_guard() { + str.annotate_new(str.size()); + } - auto new_cap = std::max(cap, size()); - if (new_cap == capacity()) - return; + basic_string& str; + }; - grow_to(new_cap); + template + static constexpr size_type align_it(size_type s) noexcept { + return (s + (a - 1)) & ~(a - 1); } - void reserve() { - shrink_to_fit(); - } + enum { alignment = 8 }; - constexpr void shrink_to_fit() { - if (is_long() == false) - return; + static constexpr size_type recommend(size_type s) noexcept { + if (s < min_cap) { + return min_cap - 1; + } + const size_type boundary = sizeof(value_type) < alignment ? alignment / sizeof(value_type) : endian_factor; + size_type guess = align_it(s + 1) - 1; + if (guess == min_cap) { + guess += endian_factor; + } - reallocate(size(), true); + PLUGIFY_ASSERT(guess >= s, "recommendation is below the requested size"); + return guess; + } + + inline constexpr void init(const value_type* s, size_type sz); + inline constexpr void init(size_type n, value_type c); + + // Slow path for the (inlined) copy constructor for 'long' strings. + // Always externally instantiated and not inlined. + // Requires that s is zero terminated. + // The main reason for this function to exist is because for unstable, we + // want to allow inlining of the copy constructor. However, we don't want + // to call the init() functions as those are marked as inline which may + // result in over-aggressive inlining by the compiler, where our aim is + // to only inline the fast path code directly in the ctor. + PLUGIFY_NOINLINE constexpr void init_copy_ctor_external(const value_type* s, size_type sz); + + template + inline constexpr void init(InputIterator first, InputIterator last); + + template + inline constexpr void init(ForwardIterator first, ForwardIterator last); + + template + constexpr void init_with_sentinel(InputIterator first, Sentinel last); + template + constexpr void init_with_size(InputIterator first, Sentinel last, size_type sz); + + constexpr void grow_by_without_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add = 0 + ); + constexpr void grow_by_and_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add, + const value_type* p_new_stuff + ); + + // assign_no_alias is invoked for assignment operations where we + // have proof that the input does not alias the current instance. + // For example, operator=(basic_string) performs a 'self' check. + template + PLUGIFY_NOINLINE constexpr basic_string& assign_no_alias(const value_type* s, size_type n); + + constexpr void erase_to_end(size_type pos) { + PLUGIFY_ASSERT( + pos <= capacity(), + "Trying to erase at position outside the strings capacity!" + ); + null_terminate_at(std::to_address(get_pointer()), pos); + } + + // erase_external_with_move is invoked for erase() invocations where + // `n ~= npos`, likely requiring memory moves on the string data. + PLUGIFY_NOINLINE constexpr void erase_external_with_move(size_type pos, size_type n); + + constexpr void copy_assign_alloc(const basic_string& str) { + copy_assign_alloc( + str, + std::integral_constant() + ); + } + + constexpr void copy_assign_alloc(const basic_string& str, std::true_type) { + if (_alloc == str._alloc) { + _alloc = str._alloc; + } else { + if (!str.is_long()) { + reset_internal_buffer(); + _alloc = str._alloc; + } else { + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + auto alloc = str._alloc; + replace_internal_buffer(allocate_long_buffer(alloc, str.size())); + _alloc = std::move(alloc); + } + } } - constexpr void clear() noexcept { - set_size(0); + constexpr void copy_assign_alloc(const basic_string&, std::false_type) noexcept { } - constexpr basic_string& insert(size_type pos, size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - insert(std::next(cbegin(), pos), count, ch); - return *this; + constexpr void + move_assign(basic_string& str, std::false_type) noexcept(alloc_traits::is_always_equal::value); + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void + move_assign(basic_string& str, std::true_type) noexcept; + + constexpr void move_assign_alloc( + basic_string& str + ) noexcept(!alloc_traits::propagate_on_container_move_assignment::value || std::is_nothrow_move_assignable_v) { + move_assign_alloc( + str, + std::integral_constant() + ); } - constexpr basic_string& insert(size_type pos, const value_type* str) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - auto len = Traits::length(str); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, str, len); - return *this; + constexpr void move_assign_alloc( + basic_string& c, + std::true_type + ) noexcept(std::is_nothrow_move_assignable_v) { + _alloc = std::move(c._alloc); } - constexpr basic_string& insert(size_type pos, const value_type* str, size_type count) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - internal_insert(pos, str, count); - return *this; + constexpr void move_assign_alloc(basic_string&, std::false_type) noexcept { } - constexpr basic_string& insert(size_type pos, const basic_string& str) { - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - internal_insert(pos, const_pointer(str.data()), str.size()); + PLUGIFY_NOINLINE constexpr basic_string& assign_external(const value_type* s); + PLUGIFY_NOINLINE constexpr basic_string& assign_external(const value_type* s, size_type n); + + // Assigns the value in s, guaranteed to be n < min_cap in length. + inline constexpr basic_string& assign_short(const value_type* s, size_type n) { + size_type old_size = size(); + if (n > old_size) { + annotate_increase(n - old_size); + } + pointer p; + if (is_long()) { + set_long_size(n); + p = get_long_pointer(); + } else { + set_short_size(n); + p = get_short_pointer(); + } + traits_type::move(std::to_address(p), s, n); + traits_type::assign(p[n], value_type()); + if (old_size > n) { + annotate_shrink(old_size); + } return *this; } - constexpr basic_string& insert(size_type pos, const basic_string& str, size_type pos_str, size_type count = npos) { - PLUGIFY_ASSERT(pos <= size() && pos_str <= str.size(), "plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range); - count = std::min(count, str.length() - pos_str); - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - return insert(pos, str.data() + pos_str, count); + constexpr basic_string& null_terminate_at(value_type* p, size_type newsz) { + size_type old_size = size(); + if (newsz > old_size) { + annotate_increase(newsz - old_size); + } + set_size(newsz); + traits_type::assign(p[newsz], value_type()); + if (old_size > newsz) { + annotate_shrink(old_size); + } + return *this; } - constexpr iterator insert(const_iterator pos, value_type ch) { - return insert(pos, 1, ch); + template + constexpr bool addr_in_range(const T& v) const { + return is_pointer_in_range(data(), data() + size() + 1, std::addressof(v)); } - constexpr iterator insert(const_iterator pos, size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - auto spos = std::distance(cbegin(), pos); - internal_insert(spos, ch, count); - return std::next(begin(), spos); + [[noreturn]] static void throw_length_error() { + PLUGIFY_THROW("constructed string size would exceed max_size()", std::length_error); } - template - constexpr iterator insert(const_iterator pos, InputIterator first, InputIterator last) { - auto spos = std::distance(cbegin(), pos); - auto len = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(spos, const_pointer(first), len); - return std::next(begin(), spos); - } - - constexpr iterator insert(const_iterator pos, std::initializer_list list) { - PLUGIFY_ASSERT(size() + list.size() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - auto spos = std::distance(cbegin(), pos); - internal_insert(spos, const_pointer(list.begin()), list.size()); - return std::next(begin(), spos); - } - - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& insert(size_type pos, const Type& t) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::insert(): pos out of range", std::out_of_range); - sview_type sv(t); - PLUGIFY_ASSERT(size() + sv.length() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, const_pointer(sv.data()), sv.length()); - return *this; + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& insert(size_type pos, const Type& t, size_type pos_str, size_type count = npos) { - auto sv = sview_type(t); - PLUGIFY_ASSERT(pos <= size() && pos_str <= sv.length(), "plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range); - auto ssv = sv.substr(pos_str, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error); - internal_insert(pos, const_pointer(ssv.data()), ssv.length()); - return *this; - } + friend constexpr basic_string + concatenate_strings<>(const Allocator&, std::type_identity_t, std::type_identity_t); -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr iterator insert_range(const_iterator pos, Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error); - return insert(pos - begin(), str); - } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + friend inline constexpr bool + operator==(const basic_string&, const CharT2*) noexcept; + }; - constexpr basic_string& erase(size_type pos = 0, size_type count = npos) { - auto sz = size(); - auto buffer = data(); + template < + std::input_iterator InputIterator, + class CharT = std::iter_value_t, + is_allocator Allocator = allocator> + basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string, Allocator>; + + template > + explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) + -> basic_string; + + template < + class CharT, + is_char_traits Traits, + is_allocator Allocator = allocator, + class Sz = typename std::allocator_traits::size_type> + basic_string(std::basic_string_view, Sz, Sz, const Allocator& = Allocator()) + -> basic_string; + +#if PLUGIFY_HAS_CXX23 + template < + std::ranges::input_range Range, + is_allocator Allocator = std::allocator>> + basic_string(std::from_range_t, Range&&, Allocator = Allocator()) -> basic_string< + std::ranges::range_value_t, + std::char_traits>, + Allocator>; +#endif - PLUGIFY_ASSERT(pos <= sz, "plg::basic_string::erase(): pos out of range", std::out_of_range); + template + constexpr void basic_string::init(const value_type* s, size_type sz) { + pointer p = init_internal_buffer(sz); + traits_type::copy(std::to_address(p), s, sz); + traits_type::assign(p[sz], value_type()); + } - count = std::min(count, sz - pos); + template + PLUGIFY_NOINLINE constexpr void + basic_string::init_copy_ctor_external(const value_type* s, size_type sz) { + pointer p = init_internal_buffer(sz); + traits_type::copy(std::to_address(p), s, sz + 1); + } - auto left = sz - (pos + count); - if (left != 0) - Traits::move(buffer + pos, buffer + pos + count, left); + template + constexpr void basic_string::init(size_type n, value_type c) { + pointer p = init_internal_buffer(n); + traits_type::assign(std::to_address(p), n, c); + traits_type::assign(p[n], value_type()); + } - auto new_size = pos + left; - set_size(new_size); - null_terminate(); + template + template + constexpr void + basic_string::init(InputIterator first, InputIterator last) { + init_with_sentinel(std::move(first), std::move(last)); + } - return *this; + template + template + constexpr void + basic_string::init_with_sentinel(InputIterator first, Sentinel last) { + _rep = rep(); + annotate_new(0); + +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + for (; first != last; ++first) { + push_back(*first); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + reset_internal_buffer(); + throw; } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr iterator erase(const_iterator position) { - auto pos = std::distance(cbegin(), position); - erase(pos, 1); - return begin() + pos; - } + template + template + constexpr void + basic_string::init(ForwardIterator first, ForwardIterator last) { + size_type sz = static_cast(std::distance(first, last)); + init_with_size(first, last, sz); + } - constexpr iterator erase(const_iterator first, const_iterator last) { - auto pos = std::distance(cbegin(), first); - auto len = std::distance(first, last); - erase(pos, len); - return begin() + pos; - } + template + template + constexpr void basic_string::init_with_size( + InputIterator first, + Sentinel last, + size_type sz + ) { + pointer p = init_internal_buffer(sz); + +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + auto end = copy_non_overlapping_range(std::move(first), std::move(last), std::to_address(p)); + traits_type::assign(*end, value_type()); +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + reset_internal_buffer(); + throw; + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr void push_back(value_type ch) { - PLUGIFY_ASSERT(size() + 1 <= max_size(), "plg::basic_string::push_back(): resulted string size would exceed max_size()", std::length_error); - append(1, ch); - } + template + constexpr void basic_string::grow_by_and_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add, + const value_type* p_new_stuff + ) { + size_type ms = max_size(); + if (delta_cap > ms - old_cap) { + throw_length_error(); + } + pointer old_p = get_pointer(); + size_type cap = old_cap < ms / 2 - alignment + ? recommend(std::max(old_cap + delta_cap, 2 * old_cap)) + : ms; + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + long_ buffer = allocate_long_buffer(_alloc, cap); + if (n_copy != 0) { + traits_type::copy(std::to_address(buffer._data), std::to_address(old_p), n_copy); + } + if (n_add != 0) { + traits_type::copy(std::to_address(buffer._data) + n_copy, p_new_stuff, n_add); + } + size_type sec_cp_sz = old_sz - n_del - n_copy; + if (sec_cp_sz != 0) { + traits_type::copy( + std::to_address(buffer._data) + n_copy + n_add, + std::to_address(old_p) + n_copy + n_del, + sec_cp_sz + ); + } + buffer._size = n_copy + n_add + sec_cp_sz; + traits_type::assign(buffer._data[buffer._size], value_type()); + replace_internal_buffer(buffer); + } - constexpr void pop_back() { - erase(end() - 1); - } + template + constexpr void basic_string::grow_by_without_replace( + size_type old_cap, + size_type delta_cap, + size_type old_sz, + size_type n_copy, + size_type n_del, + size_type n_add + ) { + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + size_type ms = max_size(); + if (delta_cap > ms - old_cap) { + this->throw_length_error(); + } + pointer old_p = get_pointer(); + size_type cap = old_cap < ms / 2 - alignment + ? recommend(std::max(old_cap + delta_cap, 2 * old_cap)) + : ms; + long_ buffer = allocate_long_buffer(_alloc, cap); + if (n_copy != 0) { + traits_type::copy(std::to_address(buffer._data), std::to_address(old_p), n_copy); + } + size_type sec_cp_sz = old_sz - n_del - n_copy; + if (sec_cp_sz != 0) { + traits_type::copy( + std::to_address(buffer._data) + n_copy + n_add, + std::to_address(old_p) + n_copy + n_del, + sec_cp_sz + ); + } + + // This is -1 to make sure the caller sets the size properly, since old versions of this + // function didn't set the size at all. + buffer._size = npos; + replace_internal_buffer(buffer); + set_long_size(old_sz - n_del + n_add); + } - constexpr basic_string& append(size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ch, count); - return *this; - } + // assign - constexpr basic_string& append(const basic_string& str) { - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(str.data(), str.size()); + template + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_no_alias(const value_type* s, size_type n) { + const auto cap = is_short ? min_cap : get_long_cap(); + const auto size = is_short ? get_short_size() : get_long_size(); + if (n >= cap) { + grow_by_and_replace(cap - 1, n - cap + 1, size, 0, size, n, s); return *this; } - constexpr basic_string& append(const basic_string& str, size_type pos, size_type count = npos) { - PLUGIFY_ASSERT(pos <= str.size(), "plg::basic_string::append(): pos out of range", std::out_of_range); - auto ssv = sview_type(str).substr(pos, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ssv.data(), ssv.length()); - return *this; + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + pointer p; + if (is_short) { + p = get_short_pointer(); + set_short_size(n); + } else { + p = get_long_pointer(); + set_long_size(n); } + traits_type::copy(std::to_address(p), s, n); + traits_type::assign(p[n], value_type()); + return *this; + } - constexpr basic_string& append(const value_type* str, size_type count) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(str, count); + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_external(const value_type* s, size_type n) { + const auto cap = capacity(); + const auto sz = size(); + if (cap >= n) { + if (n > sz) { + annotate_increase(n - sz); + } + value_type* p = std::to_address(get_pointer()); + traits_type::move(p, s, n); + return null_terminate_at(p, n); + } else { + grow_by_and_replace(cap, n - cap, sz, 0, sz, n, s); return *this; } + } - constexpr basic_string& append(const value_type* str) { - auto len = Traits::length(str); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - return append(str, len); - } + template + constexpr basic_string& + basic_string::assign(const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::assign received nullptr"); + return (__builtin_constant_p(n) && fits_in_sso(n)) ? assign_short(s, n) + : assign_external(s, n); + } - template - constexpr basic_string& append(InputIterator first, InputIterator last) { - auto len = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(size() + len <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(const_pointer(first), len); - return *this; - } + template + constexpr basic_string& + basic_string::assign(size_type n, value_type c) { + size_type cap = capacity(); + size_type old_size = size(); + if (cap < n) { + grow_by_without_replace(cap, n - cap, old_size, 0, old_size); + annotate_increase(n); + } else if (n > old_size) { + annotate_increase(n - old_size); + } + value_type* p = std::to_address(get_pointer()); + traits_type::assign(p, n, c); + return null_terminate_at(p, n); + } - constexpr basic_string& append(std::initializer_list list) { - PLUGIFY_ASSERT(size() + list.size() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(const_pointer(list.begin()), list.size()); - return *this; - } + template + constexpr basic_string& + basic_string::operator=(value_type c) { + size_type old_size = size(); + if (old_size == 0) { + annotate_increase(1); + } + pointer p; + if (is_long()) { + p = get_long_pointer(); + set_long_size(1); + } else { + p = get_short_pointer(); + set_short_size(1); + } + traits_type::assign(*p, c); + traits_type::assign(*++p, value_type()); + if (old_size > 1) { + annotate_shrink(old_size); + } + return *this; + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& append(const Type& t) { - sview_type sv(t); - PLUGIFY_ASSERT(size() + sv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(sv.data(), sv.size()); + template + constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS basic_string& + basic_string::operator=(const basic_string& str) { + if (this == std::addressof(str)) { return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& append(const Type& t, size_type pos, size_type count = npos) { - sview_type sv(t); - PLUGIFY_ASSERT(pos <= sv.length(), "plg::basic_string::append(): pos out of range", std::out_of_range); - auto ssv = sv.substr(pos, count); - PLUGIFY_ASSERT(size() + ssv.length() <= max_size(), "plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error); - internal_append(ssv.data(), ssv.length()); - return *this; - } + copy_assign_alloc(str); -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr basic_string& append_range(Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - PLUGIFY_ASSERT(size() + str.size() <= max_size(), "plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error); - return append(str); + if (is_long()) { + return assign_no_alias(str.data(), str.size()); } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr basic_string& operator+=(const basic_string& str) { - return append(str); + if (str.is_long()) { + return assign_no_alias(str.data(), str.size()); } - constexpr basic_string& operator+=(value_type ch) { - push_back(ch); - return *this; - } + annotate_delete(); + [[maybe_unused]] auto guard = make_scope_guard(annotate_new_size(*this)); + _rep = str._rep; - constexpr basic_string& operator+=(const value_type* str) { - return append(str); - } + return *this; + } - constexpr basic_string& operator+=(std::initializer_list list) { - return append(list); + template + inline constexpr void + basic_string::move_assign(basic_string& str, std::false_type) noexcept( + alloc_traits::is_always_equal::value + ) { + if (_alloc != str._alloc) { + assign(str); + } else { + move_assign(str, std::true_type()); } + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& operator+=(const Type& t) { - return append(sview_type(t)); + template + inline constexpr PLUGIFY_INTERNAL_MEMORY_ACCESS void + basic_string::move_assign(basic_string& str, std::true_type) noexcept { + annotate_delete(); + if (is_long()) { + reset_internal_buffer(); + } + size_type str_old_size = str.size(); + bool str_was_short = !str.is_long(); + + move_assign_alloc(str); + _rep = str._rep; + str.set_short_size(0); + traits_type::assign(str.get_short_pointer()[0], value_type()); + + if (str_was_short && this != std::addressof(str)) { + str.annotate_shrink(str_old_size); + } else { + // ASan annotations: was long, so object memory is unpoisoned as new. + // Or is same as *this, and annotate_delete() was called. + str.annotate_new(0); + } + + // ASan annotations: Guard against `std::string s; s = std::move(s);` + // You can find more here: https://en.cppreference.com/w/cpp/utility/move + // Quote: "Unless otherwise specified, all standard library objects that have been moved + // from are placed in a "valid but unspecified state", meaning the object's class + // invariants hold (so functions without preconditions, such as the assignment operator, + // can be safely used on the object after it was moved from):" + // Quote: "v = std::move(v); // the value of v is unspecified" + if (!is_long() && std::addressof(str) != this) { + // If it is long string, delete was never called on original str's buffer. + annotate_new(get_short_size()); } + } - constexpr int compare(const basic_string& str) const noexcept { - return view().compare(str.view()); - } + template + template + constexpr void + basic_string::assign_with_sentinel(InputIterator first, Sentinel last) { + const basic_string temp(init_with_sentinel_tag(), std::move(first), std::move(last), _alloc); + assign(temp.data(), temp.size()); + } - constexpr int compare(size_type pos1, size_type count1, const basic_string& str) const { - return view().compare(pos1, count1, str.view()); + template + template + constexpr void + basic_string::assign_trivial(Iterator first, Sentinel last, size_type n) { + PLUGIFY_ASSERT( + string_is_trivial_iterator_v, + "The iterator type given to `assign_trivial` must be trivial" + ); + + size_type old_size = size(); + size_type cap = capacity(); + if (cap < n) { + // Unlike `append` functions, if the input range points into the string itself, there is + // no case that the input range could get invalidated by reallocation: + // 1. If the input range is a subset of the string itself, its size cannot exceed the + // capacity of the string, + // thus no reallocation would happen. + // 2. In the exotic case where the input range is the byte representation of the string + // itself, the string + // object itself stays valid even if reallocation happens. + size_type sz = size(); + grow_by_without_replace(cap, n - cap, sz, 0, sz); + annotate_increase(n); + } else if (n > old_size) { + annotate_increase(n - old_size); + } + pointer p = get_pointer(); + for (; first != last; ++p, (void) ++first) { + traits_type::assign(*p, *first); + } + traits_type::assign(*p, value_type()); + set_size(n); + if (n < old_size) { + annotate_shrink(old_size); } + } - constexpr int compare(size_type pos1, size_type count1, const basic_string& str, size_type pos2, size_type count2 = npos) const { - return view().compare(pos1, count1, str.view(), pos2, count2); + template + constexpr basic_string& + basic_string::assign(const basic_string& str, size_type pos, size_type n) { + size_type sz = str.size(); + if (pos > sz) { + this->throw_out_of_range(); } + return assign(str.data() + pos, std::min(n, sz - pos)); + } - constexpr int compare(const value_type* str) const { - return view().compare(str); - } + template + PLUGIFY_NOINLINE constexpr basic_string& + basic_string::assign_external(const value_type* s) { + return assign_external(s, traits_type::length(s)); + } - constexpr int compare(size_type pos1, size_type count1, const value_type* str) const { - return view().compare(pos1, count1, str); + template + constexpr basic_string& + basic_string::assign(const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::assign received nullptr"); + if (auto len = traits_type::length(s); __builtin_constant_p(len) && fits_in_sso(len)) { + return assign_short(s, len); } + return assign_external(s); + } - constexpr int compare(size_type pos1, size_type count1, const value_type* str, size_type count2) const { - return view().compare(pos1, count1, str, count2); - } + // append - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(const Type& t) const noexcept(noexcept(std::is_nothrow_convertible_v)) { - return view().compare(sview_type(t)); + template + constexpr basic_string& + basic_string::append(const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::append received nullptr"); + size_type cap = capacity(); + size_type sz = size(); + if (cap - sz < n) { + grow_by_and_replace(cap, sz + n - cap, sz, sz, 0, n, s); + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(size_type pos1, size_type count1, const Type& t) const { - return view().compare(pos1, count1, sview_type(t)); + if (n == 0) { + return *this; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr int compare(size_type pos1, size_type count1, const Type& t, size_type pos2, size_type count2 = npos) const { - return view().compare(pos1, count1, sview_type(t), pos2, count2); - } + annotate_increase(n); + value_type* p = std::to_address(get_pointer()); + traits_type::copy(p + sz, s, n); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr bool starts_with(sview_type sv) const noexcept { - return view().starts_with(sv); + template + constexpr basic_string& + basic_string::append(size_type n, value_type c) { + if (n == 0) { + return *this; } - constexpr bool starts_with(Char ch) const noexcept { - return view().starts_with(ch); + size_type cap = capacity(); + size_type sz = size(); + if (cap - sz < n) { + grow_by_without_replace(cap, sz + n - cap, sz, sz, 0); } + annotate_increase(n); + pointer p = get_pointer(); + traits_type::assign(std::to_address(p) + sz, n, c); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr bool starts_with(const Char* str) const { - return view().starts_with(str); - } + template + constexpr void basic_string::push_back(value_type c) { + bool is_short = !is_long(); + size_type cap; + size_type sz; + if (is_short) { + cap = min_cap - 1; + sz = get_short_size(); + } else { + cap = get_long_cap() - 1; + sz = get_long_size(); + } + if (sz == cap) { + grow_by_without_replace(cap, 1, sz, sz, 0); + is_short = false; // the string is always long after grow_by + } + annotate_increase(1); + pointer p; + if (is_short) { + p = get_short_pointer() + sz; + set_short_size(sz + 1); + } else { + p = get_long_pointer() + sz; + set_long_size(sz + 1); + } + traits_type::assign(*p, c); + traits_type::assign(*++p, value_type()); + } - constexpr bool ends_with(sview_type sv) const noexcept { - return view().ends_with(sv); + template + constexpr basic_string& + basic_string::append(const basic_string& str, size_type pos, size_type n) { + size_type sz = str.size(); + if (pos > sz) { + this->throw_out_of_range(); } + return append(str.data() + pos, std::min(n, sz - pos)); + } - constexpr bool ends_with(Char ch) const noexcept { - return view().ends_with(ch); - } + template + constexpr basic_string& + basic_string::append(const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::append received nullptr"); + return append(s, traits_type::length(s)); + } - constexpr bool ends_with(const Char* str) const { - return view().ends_with(str); - } + // insert - constexpr bool contains(sview_type sv) const noexcept { - return view().contains(sv); + template + constexpr basic_string& + basic_string::insert(size_type pos, const value_type* s, size_type n) { + PLUGIFY_ASSERT(n == 0 || s != nullptr, "string::insert received nullptr"); + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } + size_type cap = capacity(); - constexpr bool contains(Char ch) const noexcept { - return view().contains(ch); + if (cap - sz < n) { + grow_by_and_replace(cap, sz + n - cap, sz, pos, 0, n, s); + return *this; } - constexpr bool contains(const Char* str) const { - return view().contains(str); + if (n == 0) { + return *this; } - constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - return replace(pos, count, str, 0, str.length()); + annotate_increase(n); + value_type* p = std::to_address(get_pointer()); + size_type n_move = sz - pos; + if (n_move != 0) { + if (is_pointer_in_range(p + pos, p + sz, s)) { + s += n; + } + traits_type::move(p + pos + n, p + pos, n_move); } + traits_type::move(p + pos, s, n); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const basic_string& str) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - return replace(pos, count, str, 0, str.length()); + template + constexpr basic_string& + basic_string::insert(size_type pos, size_type n, value_type c) { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } - constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2 = npos) { - PLUGIFY_ASSERT(pos <= size() && pos2 <= str.size(), "plg::basic_string::replace(): pos or pos_str out of range", std::out_of_range); - count2 = std::min(count2, str.length() - pos2); - auto ssv = sview_type(str).substr(pos2, count2); - return replace(pos, count, ssv.data(), ssv.length()); + if (n == 0) { + return *this; } - template - constexpr basic_string& replace(const_iterator first, const_iterator last, InputIterator first2, InputIterator last2) { - return replace(first, last, const_pointer(first2), std::distance(first2, last2)); - } + size_type cap = capacity(); + value_type* p; + if (cap - sz >= n) { + annotate_increase(n); + p = std::to_address(get_pointer()); + size_type n_move = sz - pos; + if (n_move != 0) { + traits_type::move(p + pos + n, p + pos, n_move); + } + } else { + grow_by_without_replace(cap, sz + n - cap, sz, pos, 0, n); + p = std::to_address(get_long_pointer()); + } + traits_type::assign(p + pos, n, c); + sz += n; + set_size(sz); + traits_type::assign(p[sz], value_type()); + return *this; + } - constexpr basic_string& replace(size_type pos, size_type count, const value_type* str, size_type count2) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - count = std::min(count, length() - pos); - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - internal_replace(pos, const_pointer(str), count, count2); - return *this; + template + template + constexpr typename basic_string::iterator + basic_string::insert_with_size( + const_iterator pos, + Iterator first, + Sentinel last, + size_type n + ) { + size_type ip = static_cast(pos - begin()); + if (n == 0) { + return begin() + ip; + } + + if (string_is_trivial_iterator_v && !addr_in_range(*first)) { + return insert_from_safe_copy(n, ip, std::move(first), std::move(last)); + } else { + const basic_string temp(init_with_sentinel_tag(), std::move(first), std::move(last), _alloc); + return insert_from_safe_copy(n, ip, temp.begin(), temp.end()); } + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const value_type* str, size_type count2) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - return replace(pos, count, str, count2); - } + template + constexpr basic_string& basic_string::insert( + size_type pos1, + const basic_string& str, + size_type pos2, + size_type n + ) { + size_type str_sz = str.size(); + if (pos2 > str_sz) { + this->throw_out_of_range(); + } + return insert(pos1, str.data() + pos2, std::min(n, str_sz - pos2)); + } - constexpr basic_string& replace(size_type pos, size_type count, const value_type* str) { - return replace(pos, count, str, Traits::length(str)); - } + template + constexpr basic_string& + basic_string::insert(size_type pos, const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::insert received nullptr"); + return insert(pos, s, traits_type::length(s)); + } - constexpr basic_string& replace(const_iterator first, const_iterator last, const value_type* str) { - return replace(first, last, str, Traits::length(str)); + template + constexpr typename basic_string::iterator + basic_string::insert(const_iterator pos, value_type c) { + size_type ip = static_cast(pos - begin()); + size_type sz = size(); + size_type cap = capacity(); + value_type* p; + if (cap == sz) { + grow_by_without_replace(cap, 1, sz, ip, 0, 1); + p = std::to_address(get_long_pointer()); + } else { + annotate_increase(1); + p = std::to_address(get_pointer()); + size_type n_move = sz - ip; + if (n_move != 0) { + traits_type::move(p + ip + 1, p + ip, n_move); + } } + traits_type::assign(p[ip], c); + traits_type::assign(p[++sz], value_type()); + set_size(sz); + return begin() + static_cast(ip); + } - constexpr basic_string& replace(size_type pos, size_type count, size_type count2, value_type ch) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - count = std::min(count, length() - pos); - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - internal_replace(pos, ch, count, count2); + // replace + + template + constexpr basic_string& + basic_string::replace( + size_type pos, + size_type n1, + const value_type* s, + size_type n2 + ) { + PLUGIFY_ASSERT(n2 == 0 || s != nullptr, "string::replace received nullptr"); + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); + } + n1 = std::min(n1, sz - pos); + size_type cap = capacity(); + if (cap - sz + n1 < n2) { + grow_by_and_replace(cap, sz - n1 + n2 - cap, sz, pos, n1, n2, s); return *this; } - constexpr basic_string& replace(const_iterator first, const_iterator last, size_type count2, value_type ch) { - auto pos = std::distance(cbegin(), first); - auto count = std::distance(first, last); - - PLUGIFY_ASSERT(size() - count + count2 <= max_size(), "plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error); - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - internal_replace(pos, ch, count, count2); - return *this; + value_type* p = std::to_address(get_pointer()); + if (n1 != n2) { + if (n2 > n1) { + annotate_increase(n2 - n1); + } + size_type n_move = sz - pos - n1; + if (n_move != 0) { + if (n1 > n2) { + traits_type::move(p + pos, s, n2); + traits_type::move(p + pos + n2, p + pos + n1, n_move); + return null_terminate_at(p, sz + (n2 - n1)); + } + if (is_pointer_in_range(p + pos + 1, p + sz, s)) { + if (p + pos + n1 <= s) { + s += n2 - n1; + } else { // p + pos < s < p + pos + n1 + traits_type::move(p + pos, s, n1); + pos += n1; + s += n2; + n2 -= n1; + n1 = 0; + } + } + traits_type::move(p + pos + n2, p + pos + n1, n_move); + } } + traits_type::move(p + pos, s, n2); + return null_terminate_at(p, sz + (n2 - n1)); + } - constexpr basic_string& replace(const_iterator first, const_iterator last, std::initializer_list list) { - return replace(first, last, const_pointer(list.begin()), list.size()); + template + constexpr basic_string& + basic_string::replace(size_type pos, size_type n1, size_type n2, value_type c) { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); + } + n1 = std::min(n1, sz - pos); + size_type cap = capacity(); + value_type* p; + if (cap - sz + n1 >= n2) { + p = std::to_address(get_pointer()); + if (n1 != n2) { + if (n2 > n1) { + annotate_increase(n2 - n1); + } + size_type n_move = sz - pos - n1; + if (n_move != 0) { + traits_type::move(p + pos + n2, p + pos + n1, n_move); + } + } + } else { + grow_by_without_replace(cap, sz - n1 + n2 - cap, sz, pos, n1, n2); + p = std::to_address(get_long_pointer()); } + traits_type::assign(p + pos, n2, c); + return null_terminate_at(p, sz - (n1 - n2)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(size_type pos, size_type count, const Type& t) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - sview_type sv(t); - return replace(pos, count, sv.data(), sv.length()); - } + template + constexpr basic_string& + basic_string::replace( + size_type pos1, + size_type n1, + const basic_string& str, + size_type pos2, + size_type n2 + ) { + size_type str_sz = str.size(); + if (pos2 > str_sz) { + this->throw_out_of_range(); + } + return replace(pos1, n1, str.data() + pos2, std::min(n2, str_sz - pos2)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(const_iterator first, const_iterator last, const Type& t) { - sview_type sv(t); - return replace(first, last, sv.data(), sv.length()); - } + template + constexpr basic_string& + basic_string::replace(size_type pos, size_type n1, const value_type* s) { + PLUGIFY_ASSERT(s != nullptr, "string::replace received nullptr"); + return replace(pos, n1, s, traits_type::length(s)); + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr basic_string& replace(size_type pos, size_type count, const Type& t, size_type pos2, size_type count2 = npos) { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::replace(): pos out of range", std::out_of_range); - auto sv = sview_type(t).substr(pos2, count2); - return replace(pos, count, sv.data(), sv.length()); - } + // erase -#if PLUGIFY_STRING_CONTAINERS_RANGES - template Range> - constexpr iterator replace_with_range(const_iterator first, const_iterator last, Range&& range) { - auto str = basic_string(std::from_range, std::forward(range), _allocator); - return replace(first, last, str);// replace checks for max_size() + // 'externally instantiated' erase() implementation, called when n != npos. + // Does not check pos against size() + template + PLUGIFY_NOINLINE constexpr void + basic_string::erase_external_with_move(size_type pos, size_type n) { + if (n == 0) { + return; } -#endif // PLUGIFY_STRING_CONTAINERS_RANGES - constexpr basic_string substr(size_type pos = 0, size_type count = npos) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::substr(): pos out of range", std::out_of_range); - return basic_string(*this, pos, count); + size_type sz = size(); + value_type* p = std::to_address(get_pointer()); + n = std::min(n, sz - pos); + size_type n_move = sz - pos - n; + if (n_move != 0) { + traits_type::move(p + pos, p + pos + n, n_move); } + null_terminate_at(p, sz - n); + } - constexpr size_type copy(value_type* str, size_type count, size_type pos = 0) const { - PLUGIFY_ASSERT(pos <= size(), "plg::basic_string::copy(): pos out of range", std::out_of_range); - return view().copy(str, count, pos); + template + constexpr basic_string& + basic_string::erase(size_type pos, size_type n) { + if (pos > size()) { + this->throw_out_of_range(); } - - constexpr void resize(size_type count, value_type ch) { - PLUGIFY_ASSERT(size() + count <= max_size(), "plg::basic_string::resize(): resulted string size would exceed max_size()", std::length_error); - auto cap = capacity(); - auto sz = size(); - auto rsz = count + sz; - - if (sz < rsz) { - if (cap < rsz) - grow_to(rsz); - Traits::assign(data() + sz, count, ch); - } - set_size(rsz); - null_terminate(); + if (n == npos) { + erase_to_end(pos); + } else { + erase_external_with_move(pos, n); } + return *this; + } - constexpr void resize(size_type count) { - resize(count, _terminator); - } + template + inline constexpr typename basic_string::iterator + basic_string::erase(const_iterator pos) { + PLUGIFY_ASSERT(pos != end(), "string::erase(iterator) called with a non-dereferenceable iterator"); + iterator b = begin(); + size_type r = static_cast(pos - b); + erase(r, 1); + return b + static_cast(r); + } - template - constexpr void resize_and_overwrite(size_type, Operation) { - static_assert(detail::dependent_false, "plg::basic_string::resize_and_overwrite(count, op) not implemented!"); - } + template + inline constexpr typename basic_string::iterator + basic_string::erase(const_iterator first, const_iterator last) { + PLUGIFY_ASSERT(first <= last, "string::erase(first, last) called with invalid range"); + iterator b = begin(); + size_type r = static_cast(first - b); + erase(r, static_cast(last - first)); + return b + static_cast(r); + } - constexpr void swap(basic_string& other) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value) { - using std::swap; - if constexpr (allocator_traits::propagate_on_container_swap::value) { - swap(_allocator, other._allocator); - } - swap(_storage, other._storage); - } + template + inline constexpr void basic_string::pop_back() { + PLUGIFY_ASSERT(!empty(), "string::pop_back(): string is already empty"); + erase_to_end(size() - 1); + } - constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept { - return view().find(sview_type(str), pos); + template + inline constexpr void basic_string::clear() noexcept { + size_type old_size; + if (is_long()) { + old_size = get_long_size(); + traits_type::assign(*get_long_pointer(), value_type()); + set_long_size(0); + } else { + old_size = get_short_size(); + traits_type::assign(*get_short_pointer(), value_type()); + set_short_size(0); } + annotate_shrink(old_size); + } - constexpr size_type find(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find(str, pos, count); + template + constexpr void basic_string::resize(size_type n, value_type c) { + size_type sz = size(); + if (n > sz) { + append(n - sz, c); + } else { + erase_to_end(n); } + } - constexpr size_type find(const value_type* str, size_type pos = 0) const noexcept { - return view().find(str, pos); + template + constexpr void basic_string::reserve(size_type requested_capacity) { + if (requested_capacity > max_size()) { + this->throw_length_error(); } - constexpr size_type find(value_type ch, size_type pos = 0) const noexcept { - return view().find(ch, pos); + // Make sure reserve(n) never shrinks. This is technically only required in C++20 + // and later (since P0966R1), however we provide consistent behavior in all Standard + // modes because this function is instantiated in the shared library. + if (requested_capacity <= capacity()) { + return; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find(sview_type(t), pos); - } + [[maybe_unused]] annotation_guard g(*this); + long_ buffer = allocate_long_buffer(_alloc, requested_capacity); + buffer._size = size(); + traits_type::copy(std::to_address(buffer._data), data(), buffer._size + 1); + replace_internal_buffer(buffer); + } - constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept { - return view().rfind(sview_type(str), pos); + template + inline constexpr void basic_string::shrink_to_fit() noexcept { + size_type target_capacity = recommend(size()); + if (target_capacity == capacity()) { + return; } - constexpr size_type rfind(const value_type* str, size_type pos, size_type count) const noexcept { - return view().rfind(str, pos, count); - } + PLUGIFY_ASSERT(is_long(), "Trying to shrink small string"); - constexpr size_type rfind(const value_type* str, size_type pos = npos) const noexcept { - return view().rfind(str, pos); - } + // We're a long string and we're shrinking into the small buffer. + const auto ptr = get_long_pointer(); + const auto size = get_long_size(); + const auto cap = get_long_cap(); - constexpr size_type rfind(value_type ch, size_type pos = npos) const noexcept { - return view().rfind(ch, pos); + if (fits_in_sso(target_capacity)) { + [[maybe_unused]] annotation_guard g(*this); + set_short_size(size); + traits_type::copy(std::to_address(get_short_pointer()), std::to_address(ptr), size + 1); + alloc_traits::deallocate(_alloc, ptr, cap); + return; } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type rfind(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().rfind(sview_type(t), pos); - } +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + [[maybe_unused]] annotation_guard g(*this); + long_ buffer = allocate_long_buffer(_alloc, size); - constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept { - return view().find_first_of(sview_type(str), pos); - } + // The Standard mandates shrink_to_fit() does not increase the capacity. + // With equal capacity keep the existing buffer. This avoids extra work + // due to swapping the elements. + if (buffer._cap * endian_factor - 1 >= capacity()) { + alloc_traits::deallocate(_alloc, buffer._data, buffer._cap * endian_factor); + return; + } - constexpr size_type find_first_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_first_of(str, pos, count); - } + traits_type::copy( + std::to_address(buffer._data), + std::to_address(get_long_pointer()), + size + 1 + ); + replace_internal_buffer(buffer); +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + return; + } +#endif // PLUGIFY_HAS_EXCEPTIONS + } - constexpr size_type find_first_of(const value_type* str, size_type pos = 0) const noexcept { - return view().find_first_of(str, pos); + template + constexpr typename basic_string::const_reference + basic_string::at(size_type n) const { + if (n >= size()) { + this->throw_out_of_range(); } + return (*this)[n]; + } - constexpr size_type find_first_of(value_type ch, size_type pos = 0) const noexcept { - return view().find_first_of(ch, pos); + template + constexpr typename basic_string::reference + basic_string::at(size_type n) { + if (n >= size()) { + this->throw_out_of_range(); } + return (*this)[n]; + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_first_of(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find_first_of(sview_type(t), pos); + template + constexpr typename basic_string::size_type + basic_string::copy(value_type* s, size_type n, size_type pos) const { + size_type sz = size(); + if (pos > sz) { + this->throw_out_of_range(); } + size_type rlen = std::min(n, sz - pos); + traits_type::copy(s, data() + pos, rlen); + return rlen; + } - constexpr size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept { - return view().find_first_not_of(sview_type(str), pos); + template + inline constexpr void basic_string::swap(basic_string& str) noexcept { + PLUGIFY_ASSERT( + alloc_traits::propagate_on_container_swap::value || alloc_traits::is_always_equal::value || _alloc == str._alloc, + "swapping non-equal allocators" + ); + if (!is_long()) { + annotate_delete(); } - - constexpr size_type find_first_not_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_first_not_of(str, pos, count); + if (this != std::addressof(str) && !str.is_long()) { + str.annotate_delete(); } - - constexpr size_type find_first_not_of(const value_type* str, size_type pos = 0) const noexcept { - return view().find_first_not_of(str, pos); + std::swap(_rep, str._rep); + swap_allocator(_alloc, str._alloc); + if (!is_long()) { + annotate_new(get_short_size()); } - - constexpr size_type find_first_not_of(value_type ch, size_type pos = 0) const noexcept { - return view().find_first_not_of(ch, pos); + if (this != std::addressof(str) && !str.is_long()) { + str.annotate_new(str.get_short_size()); } + } - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_first_not_of(const Type& t, size_type pos = 0) const noexcept(std::is_nothrow_convertible_v) { - return view().find_first_not_of(sview_type(t), pos); + // compare + + template + inline constexpr int basic_string::compare( + size_type pos1, + size_type n1, + const value_type* s, + size_type n2 + ) const { + PLUGIFY_ASSERT(n2 == 0 || s != nullptr, "string::compare(): received nullptr"); + size_type sz = size(); + if (pos1 > sz || n2 == npos) { + this->throw_out_of_range(); + } + size_type rlen = std::min(n1, sz - pos1); + int r = traits_type::compare(data() + pos1, s, std::min(rlen, n2)); + if (r == 0) { + if (rlen < n2) { + r = -1; + } else if (rlen > n2) { + r = 1; + } } + return r; + } - constexpr size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept { - return view().find_last_of(sview_type(str), pos); - } + // invariants - constexpr size_type find_last_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_last_of(str, pos, count); + template + inline constexpr bool basic_string::invariants() const { + if (size() > capacity()) { + return false; } - - constexpr size_type find_last_of(const value_type* str, size_type pos = npos) const noexcept { - return view().find_last_of(str, pos); + if (capacity() < min_cap - 1) { + return false; } - - constexpr size_type find_last_of(value_type ch, size_type pos = npos) const noexcept { - return view().find_last_of(ch, pos); + if (data() == nullptr) { + return false; } - - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_last_of(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().find_last_of(sview_type(t), pos); + if (!Traits::eq(data()[size()], value_type())) { + return false; } + return true; + } - constexpr size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept { - return view().find_last_not_of(sview_type(str), pos); - } + // operator== - constexpr size_type find_last_not_of(const value_type* str, size_type pos, size_type count) const noexcept { - return view().find_last_not_of(str, pos, count); - } + template + inline constexpr bool operator==( + const basic_string& lhs, + const basic_string& rhs + ) noexcept { + size_t lhs_sz = lhs.size(); + return lhs_sz == rhs.size() && Traits::compare(lhs.data(), rhs.data(), lhs_sz) == 0; + } - constexpr size_type find_last_not_of(const value_type* str, size_type pos = npos) const noexcept { - return view().find_last_not_of(str, pos); - } + template + inline constexpr bool operator==( + const basic_string& lhs, + const CharT* PLUGIFY_NO_NULL rhs + ) noexcept { + PLUGIFY_ASSERT(rhs != nullptr, "operator==(basic_string, char*): received nullptr"); - constexpr size_type find_last_not_of(value_type ch, size_type pos = npos) const noexcept { - return view().find_last_not_of(ch, pos); - } + using String = basic_string; - template - requires (std::is_convertible_v && - !std::is_convertible_v) - constexpr size_type find_last_not_of(const Type& t, size_type pos = npos) const noexcept(std::is_nothrow_convertible_v) { - return view().find_last_not_of(sview_type(t), pos); + size_t rhs_len = Traits::length(rhs); + if (__builtin_constant_p(rhs_len) && !String::fits_in_sso(rhs_len)) { + if (!lhs.is_long()) { + return false; + } } - - friend constexpr basic_string operator+(const basic_string& lhs, const basic_string& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::copy(buffer + lhs_sz, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; + if (rhs_len != lhs.size()) { + return false; } + return lhs.compare(0, String::npos, rhs, rhs_len) == 0; + } - friend constexpr basic_string operator+(basic_string&& lhs, const basic_string& rhs) { - return std::move(lhs.append(rhs)); - } + template + constexpr auto operator<=>( + const basic_string& lhs, + const basic_string& rhs + ) noexcept { + return std::basic_string_view(lhs) + <=> std::basic_string_view(rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, basic_string&& rhs) { - return std::move(rhs.insert(0, lhs)); - } + template + constexpr auto operator<=>(const basic_string& lhs, const CharT* rhs) { + return std::basic_string_view(lhs) + <=> std::basic_string_view(rhs); + } - friend constexpr basic_string operator+(basic_string&& lhs, basic_string&& rhs) { - return std::move(lhs.append(rhs)); - } + // operator + + + template + constexpr basic_string concatenate_strings( + const Allocator& alloc, + std::type_identity_t> str1, + std::type_identity_t> str2 + ) { + using String = basic_string; + String r( + uninitialized_size_tag(), + str1.size() + str2.size(), + String::alloc_traits::select_on_container_copy_construction(alloc) + ); + auto ptr = std::to_address(r.get_pointer()); + Traits::copy(ptr, str1.data(), str1.size()); + Traits::copy(ptr + str1.size(), str2.data(), str2.size()); + Traits::assign(ptr[str1.size() + str2.size()], CharT()); + return r; + } - friend constexpr basic_string operator+(const Char* lhs, const basic_string& rhs) { - auto lhs_sz = Traits::length(lhs); - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(rhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs, lhs_sz); - Traits::copy(buffer + lhs_sz, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; - } + template + constexpr basic_string operator+( + const basic_string& lhs, + const basic_string& rhs + ) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const Char* lhs, basic_string&& rhs) { - return std::move(rhs.insert(0, lhs)); - } + template + constexpr basic_string + operator+(const CharT* lhs, const basic_string& rhs) { + return concatenate_strings(rhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(Char lhs, const basic_string& rhs) { - auto rhs_sz = rhs.size(); - basic_string ret(detail::uninitialized_size_tag(), rhs_sz + 1, basic_string::allocator_traits::select_on_container_copy_construction(rhs._allocator)); - auto buffer = ret.data(); - Traits::assign(buffer, 1, lhs); - Traits::copy(buffer + 1, rhs.data(), rhs_sz); - ret.null_terminate(); - return ret; - } + // extern template string operator+ , allocator >(char + // const*, string const&); + + template + constexpr basic_string + operator+(CharT lhs, const basic_string& rhs) { + return concatenate_strings( + rhs.get_allocator(), + std::basic_string_view(std::addressof(lhs), 1), + rhs + ); + } - friend constexpr basic_string operator+(Char lhs, basic_string&& rhs) { - rhs.insert(rhs.begin(), lhs); - return std::move(rhs); - } + template + constexpr basic_string + operator+(const basic_string& lhs, const CharT* rhs) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, const Char* rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = Traits::length(rhs); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + rhs_sz, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::copy(buffer + lhs_sz, rhs, rhs_sz); - ret.null_terminate(); - return ret; - } + template + constexpr basic_string + operator+(const basic_string& lhs, CharT rhs) { + return concatenate_strings( + lhs.get_allocator(), + lhs, + std::basic_string_view(std::addressof(rhs), 1) + ); + } +#if PLUGIFY_HAS_CXX26 + + template + constexpr basic_string operator+( + const basic_string& lhs, + std::type_identity_t> rhs + ) { + return concatenate_strings(lhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(basic_string&& lhs, const Char* rhs) { - return std::move(lhs.append(rhs)); - } + template + constexpr basic_string operator+( + std::type_identity_t> lhs, + const basic_string& rhs + ) { + return concatenate_strings(rhs.get_allocator(), lhs, rhs); + } - friend constexpr basic_string operator+(const basic_string& lhs, Char rhs) { - auto lhs_sz = lhs.size(); - basic_string ret(detail::uninitialized_size_tag(), lhs_sz + 1, basic_string::allocator_traits::select_on_container_copy_construction(lhs._allocator)); - auto buffer = ret.data(); - Traits::copy(buffer, lhs.data(), lhs_sz); - Traits::assign(buffer + lhs_sz, 1, rhs); - ret.null_terminate(); - return ret; - } +#endif // PLUGIFY_HAS_CXX26 - friend constexpr basic_string operator+(basic_string&& lhs, Char rhs) { - lhs.push_back(rhs); - return std::move(lhs); - } - }; + template + inline constexpr basic_string operator+( + basic_string&& lhs, + const basic_string& rhs + ) { + return std::move(lhs.append(rhs)); + } - template - constexpr bool operator==(const basic_string& lhs, const basic_string& rhs) noexcept { - return lhs.compare(rhs) == 0; + template + inline constexpr basic_string operator+( + const basic_string& lhs, + basic_string&& rhs + ) { + return std::move(rhs.insert(0, lhs)); } - template - constexpr bool operator==(const basic_string& lhs, const Char* rhs) { - return lhs.compare(rhs) == 0; + template + inline constexpr basic_string + operator+(basic_string&& lhs, basic_string&& rhs) { + return std::move(lhs.append(rhs)); } - template - constexpr std::strong_ordering operator<=>(const basic_string& lhs, const basic_string& rhs) noexcept { - return lhs.compare(rhs) <=> 0; + template + inline constexpr basic_string + operator+(const CharT* lhs, basic_string&& rhs) { + return std::move(rhs.insert(0, lhs)); } - template - constexpr std::strong_ordering operator<=>(const basic_string& lhs, const Char* rhs) { - return lhs.compare(rhs) <=> 0; + template + inline constexpr basic_string + operator+(CharT lhs, basic_string&& rhs) { + rhs.insert(rhs.begin(), lhs); + return std::move(rhs); } - // swap - template - constexpr void swap(basic_string& lhs, basic_string& rhs) noexcept(noexcept(lhs.swap(rhs))) { - lhs.swap(rhs); + template + inline constexpr basic_string + operator+(basic_string&& lhs, const CharT* rhs) { + return std::move(lhs.append(rhs)); } - // erasure - template - constexpr typename basic_string::size_type erase(basic_string& c, const U& value) { - auto it = std::remove(c.begin(), c.end(), value); - auto r = std::distance(it, c.end()); - c.erase(it, c.end()); - return r; + template + inline constexpr basic_string + operator+(basic_string&& lhs, CharT rhs) { + lhs.push_back(rhs); + return std::move(lhs); } - template - constexpr typename basic_string::size_type erase_if(basic_string& c, Pred pred) { - auto it = std::remove_if(c.begin(), c.end(), pred); - auto r = std::distance(it, c.end()); - c.erase(it, c.end()); - return r; +#if PLUGIFY_HAS_CXX26 + + template + constexpr basic_string operator+( + basic_string&& lhs, + std::type_identity_t> rhs + ) { + return std::move(lhs.append(rhs)); + } + + template + constexpr basic_string operator+( + std::type_identity_t> lhs, + basic_string&& rhs + ) { + return std::move(rhs.insert(0, lhs)); } - // deduction guides - template::value_type>> - basic_string(InputIterator, InputIterator, Allocator = Allocator()) -> basic_string::value_type, std::char_traits::value_type>, Allocator>; +#endif // PLUGIFY_HAS_CXX26 - template> - explicit basic_string(std::basic_string_view, const Allocator& = Allocator()) -> basic_string; + // swap + + template + inline constexpr void swap( + basic_string& lhs, + basic_string& rhs + ) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); + } - template> - basic_string(std::basic_string_view, typename basic_string::size_type, typename basic_string::size_type, const Allocator& = Allocator()) -> basic_string; + template + inline constexpr typename basic_string::size_type + erase(basic_string& str, const Up& v) { + auto old_size = str.size(); + str.erase(std::remove(str.begin(), str.end(), v), str.end()); + return old_size - str.size(); + } -#if PLUGIFY_STRING_CONTAINERS_RANGES - template>> - basic_string(std::from_range_t, Range&&, Allocator = Allocator()) -> basic_string, std::char_traits>, Allocator>; -#endif // PLUGIFY_STRING_CONTAINERS_RANGES + template + inline constexpr typename basic_string::size_type + erase_if(basic_string& str, Predicate pred) { + auto old_size = str.size(); + str.erase(std::remove_if(str.begin(), str.end(), pred), str.end()); + return old_size - str.size(); + } // basic_string typedef-names using string = basic_string; @@ -1702,8 +3618,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtol(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return static_cast(ret); } @@ -1713,8 +3630,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtol(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1724,8 +3642,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoll(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1735,8 +3654,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoul(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1746,8 +3666,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtoull(cstr, &ptr, base); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1757,8 +3678,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtof(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1768,8 +3690,9 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtod(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } @@ -1779,19 +3702,22 @@ namespace plg { char* ptr = const_cast(cstr); auto ret = strtold(cstr, &ptr); - if (pos != nullptr) + if (pos != nullptr) { *pos = static_cast(cstr - ptr); + } return ret; } namespace detail { - template - PLUGIFY_FORCE_INLINE constexpr S to_string(V v) { + template + constexpr S to_string(V v) { // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers. // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented), // so we need +1 here. - constexpr std::size_t bufSize = std::numeric_limits::digits10 + 2; // +1 for minus, +1 for digits10 + constexpr std::size_t bufSize = std::numeric_limits::digits10 + 2; // +1 for minus, + // +1 for + // digits10 char buf[bufSize]; const auto res = std::to_chars(buf, buf + bufSize, v); return S(buf, res.ptr); @@ -1800,7 +3726,12 @@ namespace plg { typedef int (*wide_printf)(wchar_t* __restrict, std::size_t, const wchar_t* __restrict, ...); #if PLUGIFY_COMPILER_MSVC - inline int truncate_snwprintf(wchar_t* __restrict buffer, std::size_t count, const wchar_t* __restrict format, ...) { + inline int truncate_snwprintf( + wchar_t* __restrict buffer, + std::size_t count, + const wchar_t* __restrict format, + ... + ) { int r; va_list args; va_start(args, format); @@ -1810,16 +3741,19 @@ namespace plg { } #endif - PLUGIFY_FORCE_INLINE constexpr wide_printf get_swprintf() noexcept { + constexpr wide_printf get_swprintf() noexcept { #if PLUGIFY_COMPILER_MSVC - return static_cast(truncate_snwprintf); + return static_cast< + int(__cdecl*)(wchar_t* __restrict, std::size_t, const wchar_t* __restrict, ...)>( + truncate_snwprintf + ); #else return swprintf; #endif } - template - PLUGIFY_FORCE_INLINE constexpr S as_string(P sprintf_like, const typename S::value_type* fmt, V v) { + template + constexpr S as_string(P sprintf_like, const typename S::value_type* fmt, V v) { typedef typename S::size_type size_type; S s; s.resize(s.capacity()); @@ -1832,7 +3766,7 @@ namespace plg { s.resize(used); break; } - available = used; // Assume this is advice of how much space we need. + available = used; // Assume this is advice of how much space we need. } else { available = available * 2 + 1; } @@ -1840,7 +3774,7 @@ namespace plg { } return s; } - }// namespace detail + } // namespace detail inline string to_string(int val) { return detail::to_string(val); } inline string to_string(unsigned val) { return detail::to_string(val); } @@ -1861,49 +3795,61 @@ namespace plg { inline wstring to_wstring(float val) { return detail::as_string(detail::get_swprintf(), L"%f", val); } inline wstring to_wstring(double val) { return detail::as_string(detail::get_swprintf(), L"%f", val); } inline wstring to_wstring(long double val) { return detail::as_string(detail::get_swprintf(), L"%Lf", val); } -#endif // PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS +#endif // PLUGIFY_STRING_NO_NUMERIC_CONVERSIONS #ifndef PLUGIFY_STRING_NO_STD_HASH // hash support namespace detail { - template, Allocator>> + template < + typename Char, + typename Allocator, + typename String = basic_string, Allocator> + > struct string_hash_base { constexpr std::size_t operator()(const String& str) const noexcept { - return std::hash{}(typename String::sview_type(str)); + return std::hash{}(typename String::self_view(str)); } }; - }// namespace detail -#endif // PLUGIFY_STRING_NO_STD_HASH + } // namespace detail +#endif // PLUGIFY_STRING_NO_STD_HASH #ifndef PLUGIFY_STRING_NO_STD_FORMAT // format support namespace detail { - template + template static constexpr const Char* format_string() { - if constexpr (std::is_same_v || std::is_same_v) + if constexpr (std::is_same_v || std::is_same_v) { return "{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return L"{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return u"{}"; - if constexpr (std::is_same_v) + } + if constexpr (std::is_same_v) { return U"{}"; + } return ""; } - template, Allocator>> + template < + typename Char, + typename Allocator, + typename String = basic_string, Allocator> + > struct string_formatter_base { constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } - template + template auto format(const String& str, FormatContext& ctx) const { return std::format_to(ctx.out(), format_string(), str.c_str()); } }; } -#endif // PLUGIFY_STRING_NO_STD_FORMAT +#endif // PLUGIFY_STRING_NO_STD_FORMAT inline namespace literals { inline namespace string_literals { @@ -1916,6 +3862,7 @@ namespace plg { #elif PLUGIFY_COMPILER_MSVC PLUGIFY_WARN_IGNORE(4455) #endif + // suffix for basic_string literals constexpr string operator""s(const char* str, std::size_t len) { return string{str, len}; } constexpr u8string operator""s(const char8_t* str, std::size_t len) { return u8string{str, len}; } @@ -1924,29 +3871,34 @@ namespace plg { constexpr wstring operator""s(const wchar_t* str, std::size_t len) { return wstring{str, len}; } PLUGIFY_WARN_POP() - }// namespace string_literals - }// namespace literals -}// namespace plg + } // namespace string_literals + } // namespace literals +} // namespace plg #ifndef PLUGIFY_STRING_NO_STD_HASH // hash support namespace std { - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; - template - struct hash, Allocator>> : plg::detail::string_hash_base {}; -}// namespace std -#endif // PLUGIFY_STRING_NO_STD_HASH + template + struct hash, Allocator>> + : plg::detail::string_hash_base {}; +} // namespace std +#endif // PLUGIFY_STRING_NO_STD_HASH #ifndef PLUGIFY_STRING_NO_STD_FORMAT // format support @@ -1955,24 +3907,29 @@ namespace fmt { #else namespace std { #endif - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; - template - struct formatter, Allocator>> : plg::detail::string_formatter_base {}; -}// namespace std -#endif // PLUGIFY_STRING_NO_STD_FORMAT + template + struct formatter, Allocator>> + : plg::detail::string_formatter_base {}; +} // namespace std +#endif // PLUGIFY_STRING_NO_STD_FORMAT -template +template std::ostream& operator<<(std::ostream& os, const plg::basic_string& str) { os << str.c_str(); return os; @@ -1982,30 +3939,24 @@ std::ostream& operator<<(std::ostream& os, const plg::basic_string namespace plg { - namespace detail { - // Concept to match string-like types including char* and const char* - template - concept is_string_like = requires(T v) { - { std::string_view(v) }; - }; - } - - template + template constexpr string join(const Range& range, std::string_view separator) { string result; auto it = range.cbegin(); auto end = range.cend(); - if (it == end) return result; + if (it == end) { + return result; + } // First pass: compute total size size_t total_size = 0; size_t count = 0; for (auto tmp = it; tmp != end; ++tmp) { - using Elem = std::decay_t; - if constexpr (detail::is_string_like) { + using elem = std::decay_t; + if constexpr (string_like) { total_size += std::string_view(*tmp).size(); } else { total_size += std::formatted_size("{}", *tmp); @@ -2020,9 +3971,7 @@ namespace plg { auto in = std::back_inserter(result); // Second pass: actual formatting - /*if (it != end)*/ { - std::format_to(in, "{}", *it++); - } + /*if (it != end)*/ { std::format_to(in, "{}", *it++); } while (it != end) { std::format_to(in, "{}{}", separator, *it++); } @@ -2030,14 +3979,16 @@ namespace plg { return result; } - template + template constexpr string join(const Range& range, Proj&& proj, std::string_view separator) { string result; auto it = range.cbegin(); auto end = range.cend(); - if (it == end) return result; + if (it == end) { + return result; + } // First pass: compute total size size_t total_size = 0; @@ -2045,9 +3996,8 @@ namespace plg { for (auto tmp = it; tmp != end; ++tmp) { auto&& projected = std::invoke(std::forward(proj), *tmp); - using Elem = std::decay_t; - - if constexpr (detail::is_string_like) { + using elem = std::decay_t; + if constexpr (string_like) { total_size += std::string_view(*projected).size(); } else { total_size += std::formatted_size("{}", projected); @@ -2073,5 +4023,5 @@ namespace plg { return result; } -} // namespace plugify -#endif // PLUGIFY_STRING_NO_STD_FORMAT \ No newline at end of file +} // namespace plugify +#endif // PLUGIFY_STRING_NO_STD_FORMAT \ No newline at end of file diff --git a/test/example_plugin/external/plugify/include/plg/uninitialized.hpp b/test/example_plugin/external/plugify/include/plg/uninitialized.hpp new file mode 100644 index 0000000..9cc3400 --- /dev/null +++ b/test/example_plugin/external/plugify/include/plg/uninitialized.hpp @@ -0,0 +1,157 @@ +#pragma once + +namespace plg { + template + struct has_construct_impl : std::false_type {}; + + template + struct has_construct_impl< + decltype((void) std::declval().construct(std::declval()...)), + Alloc, + Args...> : std::true_type {}; + + template + struct has_construct : has_construct_impl {}; + + // __has_destroy + template + struct has_destroy : std::false_type {}; + + template + struct has_destroy().destroy(std::declval()))> + : std::true_type {}; + + template + struct allocator_has_trivial_move_construct : std::negation> {}; + + template + struct allocator_has_trivial_move_construct, Type> : std::true_type {}; + + template + struct allocator_has_trivial_destroy : std::negation> {}; + + template + struct allocator_has_trivial_destroy, U> : std::true_type {}; + + template + struct allocator_has_trivial_copy_construct + : std::negation> {}; + + template + struct allocator_has_trivial_copy_construct, Type> : std::true_type {}; + + // Destroy all elements in [__first, __last) from left to right using allocator destruction. + template + void allocator_destroy(Alloc& alloc, Iter first, Sent last) { + for (; first != last; ++first) + std::allocator_traits::destroy(alloc, std::to_address(first)); + } + + template + class AllocatorDestroyRangeReverse { + public: + AllocatorDestroyRangeReverse(Alloc& alloc, Iter& first, Iter& last) + : _alloc(alloc), _first(first), _last(last) {} + + void operator()() const { + allocator_destroy(_alloc, std::reverse_iterator(_last), std::reverse_iterator(_first)); + } + + private: + Alloc& _alloc; + Iter& _first; + Iter& _last; + }; + + // Copy-construct [first1, last1) in [first2, first2 + N), where N is + // distance(first1, last1). + // + // The caller has to ensure that first2 can hold at least N uninitialized elements. If an + // exception is thrown the already copied elements are destroyed in reverse order of their + // construction. + template + Iter2 uninitialized_allocator_copy_impl( + Alloc& alloc, + Iter1 first1, + Sent1 last1, + Iter2 first2 + ) { + auto destruct_first = first2; + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(alloc, destruct_first, first2) + ); + while (first1 != last1) { + std::allocator_traits::construct(alloc, std::to_address(first2), *first1); + ++first1; + ++first2; + } + guard.complete(); + return first2; + } + + template < + class Alloc, + class In, + class RawTypeIn = std::remove_const_t, + class Out> + // using RawTypeIn because of the allocator extension + requires (std::is_trivially_copy_constructible_v && + std::is_trivially_copy_assignable_v && + std::is_same_v, std::remove_const_t> && + allocator_has_trivial_copy_construct::value) + Out* uninitialized_allocator_copy_impl(Alloc&, In* first1, In* last1, Out* first2) { + return std::copy(first1, last1, const_cast(first2)); + } + + template + Iter2 uninitialized_allocator_copy(Alloc& alloc, Iter1 first1, Sent1 last1, Iter2 first2) { + return uninitialized_allocator_copy_impl(alloc, std::move(first1), std::move(last1), std::move(first2)); + } + + // __uninitialized_allocator_relocate relocates the objects in [__first, __last) into + // __result. + // Relocation means that the objects in [__first, __last) are placed into __result as-if by + // move-construct and destroy, except that the move constructor and destructor may never be + // called if they are known to be equivalent to a memcpy. + // + // Preconditions: __result doesn't contain any objects and [__first, __last) contains + // objects Postconditions: __result contains the objects from [__first, __last) and + // [__first, __last) doesn't contain any objects + // + // The strong exception guarantee is provided if any of the following are true: + // - is_nothrow_move_constructible + // - is_copy_constructible + // - is_trivially_relocatable + template + void uninitialized_allocator_relocate(Alloc& alloc, T* first, T* last, T* result) { + if (std::is_constant_evaluated() || + !is_trivially_relocatable::value || + !allocator_has_trivial_move_construct::value || + !allocator_has_trivial_destroy::value + ) { + auto destruct_first = result; + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(alloc, destruct_first, result) + ); + auto iter = first; + while (iter != last) { + std::allocator_traits::construct( + alloc, + result, +#if PLUGIFY_HAS_EXCEPTIONS + std::move_if_noexcept(*iter) +#else + std::move(*iter) +#endif // PLUGIFY_HAS_EXCEPTIONS + ); + ++iter; + ++result; + } + guard.complete(); + allocator_destroy(alloc, first, last); + } else { + // Casting to void* to suppress clang complaining that this is technically UB. + std::memcpy(static_cast(result), first, sizeof(T) * static_cast(last - first)); + } + } +}; // namespace plg diff --git a/test/example_plugin/external/plugify/include/plg/variant.hpp b/test/example_plugin/external/plugify/include/plg/variant.hpp index e9ee06b..9e7ada0 100644 --- a/test/example_plugin/external/plugify/include/plg/variant.hpp +++ b/test/example_plugin/external/plugify/include/plg/variant.hpp @@ -1,11 +1,9 @@ #pragma once -#include #include #include // swap #include // used for index_type #include -#include #ifndef PLUGIFY_VARIANT_NO_CONSTEXPR_EMPLACE # include @@ -20,39 +18,41 @@ #define PLG_FWD(x) static_cast(x) #define PLG_MOV(x) static_cast< std::remove_reference_t&& >(x) -#include "plg/macro.hpp" +#include "plg/config.hpp" +#include "plg/concepts.hpp" // from https://github.com/groundswellaudio/swl-variant namespace plg { -#if PLUGIFY_EXCEPTIONS +#if PLUGIFY_HAS_EXCEPTIONS class bad_variant_access : public std::exception { - const char* message = ""; // llvm test requires a well formed what() on default init - public : + public: explicit bad_variant_access(const char* str) noexcept : message{str} {} bad_variant_access() noexcept = default; bad_variant_access(const bad_variant_access&) noexcept = default; bad_variant_access& operator=(const bad_variant_access&) noexcept = default; const char* what() const noexcept override { return message; } + private: + const char* message = ""; // llvm test requires a well formed what() on default init }; -#endif // PLUGIFY_EXCEPTIONS +#endif // PLUGIFY_HAS_EXCEPTIONS namespace detail { //struct variant_tag{}; struct emplacer_tag{}; - } - + } // namespace detail + template struct in_place_type_t : private detail::emplacer_tag {}; - + template struct in_place_index_t : private detail::emplacer_tag {}; - + template inline static constexpr in_place_index_t in_place_index; - + template inline static constexpr in_place_type_t in_place_type; - + namespace detail { template constexpr int find_first_true(bool (&&arr)[N]) { @@ -186,7 +186,6 @@ namespace plg { template<> struct node_trait { - template static constexpr auto elem_size = not(std::is_same_v) ? 2 : 1; @@ -343,9 +342,7 @@ namespace plg { // Ts... must be sorted in ascending size template using smallest_suitable_integer_type = - type_pack_element<(static_cast(Num > std::numeric_limits::max()) + ...), - Ts... - >; + type_pack_element<(static_cast((Num > std::numeric_limits::max())) + ...), Ts...>; // why do we need this again? i think something to do with GCC? namespace swap_trait { @@ -356,7 +353,7 @@ namespace plg { template inline constexpr bool nothrow = noexcept(swap(std::declval(), std::declval())); - } + } // namespace swap_trait #ifndef PLUGIFY_VARIANT_NO_STD_HASH template @@ -500,13 +497,13 @@ namespace plg { #undef CAT2 #undef INJECTSEQ - } // inline namespace v1 + } // namespace v1 struct variant_npos_t { template constexpr bool operator==(T idx) const noexcept { return idx == std::numeric_limits::max(); } }; - } + } // namespace detail inline static constexpr detail::variant_npos_t variant_npos; @@ -556,6 +553,8 @@ namespace plg { static constexpr bool trivial_dtor = std::is_trivially_destructible_v; public: + using trivially_relocatable = std::conditional_t...>, variant, void>; + template using alternative = std::remove_reference_t().template get())>; @@ -578,12 +577,12 @@ namespace plg { requires std::is_default_constructible_v> : _storage{in_place_index<0>}, _current{0} {} - + // copy constructor (trivial) constexpr variant(const variant&) requires trivial_copy_ctor = default; - + // note : both the copy and move constructor cannot be meaningfully constexpr without std::construct_at // copy constructor constexpr variant(const variant& o) @@ -591,7 +590,7 @@ namespace plg { : _storage{detail::dummy_type{}} { construct_from(o); } - + // move constructor (trivial) constexpr variant(variant&&) requires trivial_move_ctor @@ -636,7 +635,7 @@ namespace plg { explicit constexpr variant(in_place_index_t tag, std::initializer_list list, Args&&... args) : _storage{tag, list, PLG_FWD(args)...}, _current{Index} {} - + template requires ( detail::appears_exactly_once @@ -684,12 +683,12 @@ namespace plg { }); return *this; } - + // move assignment(trivial) constexpr variant& operator=(variant&& o) requires (trivial_move_assign and trivial_move_ctor and trivial_dtor) = default; - + // move assignment constexpr variant& operator=(variant&& o) noexcept((std::is_nothrow_move_constructible_v && ...) && (std::is_nothrow_move_assignable_v && ...)) @@ -705,7 +704,7 @@ namespace plg { }); return *this; } - + // generic assignment template requires detail::has_non_ambiguous_match @@ -714,14 +713,14 @@ namespace plg { && std::is_nothrow_constructible_v, T&&>) { using related_type = detail::best_overload_match; constexpr auto new_index = index_of; - + if (_current == new_index) unsafe_get() = PLG_FWD(t); else { constexpr bool do_simple_emplace = std::is_nothrow_constructible_v or not std::is_nothrow_move_constructible_v; - + if constexpr (do_simple_emplace) emplace(PLG_FWD(t)); else { @@ -729,12 +728,12 @@ namespace plg { emplace(PLG_MOV(tmp)); } } - + return *this; } - + // ================================== modifiers (20.7.3.5) - + template requires (std::is_constructible_v && detail::appears_exactly_once) constexpr T& emplace(Args&&... args) { @@ -789,7 +788,7 @@ namespace plg { full._current = npos; }; - switch(static_cast(index() == npos) + static_cast(o.index() == npos) * 2) { + switch (static_cast(index() == npos) + static_cast(o.index() == npos) * 2) { case 0 : break; case 1 : @@ -806,7 +805,7 @@ namespace plg { } } - assert(not(valueless_by_exception() && o.valueless_by_exception())); + PLUGIFY_ASSERT(not(valueless_by_exception() && o.valueless_by_exception()), ""); detail::visit_with_index(o, [&o, this](auto&& elem, auto index_cst) { if (index() == index_cst) { @@ -827,7 +826,7 @@ namespace plg { // we could refactor this detail::destruct>(elem); - o.template emplace_no_dtor<(unsigned)(this_index) >(PLG_MOV(tmp)); + o.template emplace_no_dtor(this_index)>(PLG_MOV(tmp)); }); }); } @@ -838,28 +837,28 @@ namespace plg { template constexpr auto& unsafe_get() & noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return _storage.template get(); } template constexpr auto&& unsafe_get() && noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return PLG_MOV(_storage.template get()); } template constexpr const auto& unsafe_get() const & noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return _storage.template get(); } template constexpr const auto&& unsafe_get() const && noexcept { static_assert(Idx < size); - assert(_current == Idx); + PLUGIFY_ASSERT(_current == Idx, ""); return PLG_MOV(_storage.template get()); } @@ -876,7 +875,7 @@ namespace plg { return; } } - assert(not o.valueless_by_exception()); + PLUGIFY_ASSERT(not o.valueless_by_exception(), ""); detail::visit_with_index(PLG_FWD(o), PLG_FWD(fn)); } @@ -938,7 +937,7 @@ namespace plg { // destroy the current element without checking for valueless constexpr void reset_no_check() { - assert(index() < size); + PLUGIFY_ASSERT(index() < size, ""); if constexpr (not trivial_dtor) { detail::visit_with_index(*this, [](auto& elem, auto index_cst) { detail::destruct>(elem); @@ -973,8 +972,8 @@ namespace plg { template constexpr bool holds_alternative(const variant& v) noexcept { static_assert((std::is_same_v || ...), "Requested type is not contained in the variant"); - constexpr auto Index = variant::template index_of; - return v.index() == Index; + constexpr auto index = variant::template index_of; + return v.index() == index; } // ========= get by index @@ -982,7 +981,9 @@ namespace plg { template constexpr auto& get(variant& v) { static_assert(Idx < sizeof...(Ts), "Index exceeds the variant size. "); - PLUGIFY_ASSERT(v.index() == Idx, "plg::variant:get(): Bad variant access in get.", bad_variant_access); + if (v.index() != Idx) { + PLUGIFY_THROW("bad variant access in get", bad_variant_access); + } return (v.template unsafe_get()); } @@ -1061,8 +1062,9 @@ namespace plg { template constexpr decltype(auto) visit(Fn&& fn, Vs&&... vs) { if constexpr ((std::decay_t::can_be_valueless || ...)) - PLUGIFY_ASSERT(!(vs.valueless_by_exception() || ...), "plg::variant:visit(): Bad variant access in visit.", bad_variant_access); - + if ((vs.valueless_by_exception() || ...)) { + PLUGIFY_THROW("bad variant access in visit", bad_variant_access); + } if constexpr (sizeof...(Vs) == 1) return detail::visit(PLG_FWD(fn), PLG_FWD(vs)...); else @@ -1151,10 +1153,9 @@ namespace plg { struct monostate{}; constexpr bool operator==(monostate, monostate) noexcept { return true; } - constexpr bool operator> (monostate, monostate) noexcept { return false; } - constexpr bool operator< (monostate, monostate) noexcept { return false; } - constexpr bool operator<=(monostate, monostate) noexcept { return true; } - constexpr bool operator>=(monostate, monostate) noexcept { return true; } + constexpr std::strong_ordering operator<=>(monostate, monostate) noexcept { + return std::strong_ordering::equal; + } // ===================================== specialized algorithms (20.7.10) @@ -1239,7 +1240,7 @@ namespace std { template<> struct hash { - constexpr std::size_t operator()(plg::monostate) const noexcept { return static_cast(-1); } + constexpr std::size_t operator()(plg::monostate) const noexcept { return static_cast(66740831); } }; } // namespace std #endif // PLUGIFY_VARIANT_NO_STD_HASH diff --git a/test/example_plugin/external/plugify/include/plg/vector.hpp b/test/example_plugin/external/plugify/include/plg/vector.hpp index 11aada1..cd26021 100644 --- a/test/example_plugin/external/plugify/include/plg/vector.hpp +++ b/test/example_plugin/external/plugify/include/plg/vector.hpp @@ -1,1032 +1,1538 @@ #pragma once +#include +#include +#include +#include +#include +#include #include -#include -#include +#include #include #include -#include -#include -#include -#include #include - -#include -#include -#include - -#if PLUGIFY_VECTOR_CONTAINERS_RANGES && (__cplusplus <= 202002L || !__has_include() || !defined(__cpp_lib_containers_ranges)) -# undef PLUGIFY_VECTOR_CONTAINERS_RANGES -# define PLUGIFY_VECTOR_CONTAINERS_RANGES 0 -#endif - -#if PLUGIFY_VECTOR_CONTAINERS_RANGES -# include -#endif +#include +#include +#include #include "plg/allocator.hpp" +#include "plg/guards.hpp" +#include "plg/split_buffer.hpp" +#include "plg/uninitialized.hpp" + +// Just in case, because we can't ignore some warnings from `-Wpedantic` (about zero size arrays and anonymous structs when gnu extensions are disabled) on gcc +#if PLUGIFY_COMPILER_CLANG +# pragma clang system_header +#elif PLUGIFY_COMPILER_GCC +# pragma GCC system_header +#endif +// from https://github.com/llvm/llvm-project/blob/main/libcxx/include/vector namespace plg { namespace detail { - template - concept is_alloc = requires(Alloc& a, std::size_t n) { - typename std::allocator_traits::value_type; - typename std::allocator_traits::pointer; - typename std::allocator_traits::const_pointer; - typename std::allocator_traits::size_type; - typename std::allocator_traits::difference_type; - - { std::allocator_traits::allocate(a, n) } - -> std::convertible_to::pointer>; - - requires requires(typename std::allocator_traits::pointer p) { - std::allocator_traits::deallocate(a, p, n); - }; - }; - - struct initialized_value_tag {}; + template + struct temp_value { + using allocator_traits = std::allocator_traits; -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template - concept vector_compatible_range = std::ranges::input_range && std::convertible_to, Type>; -#endif - } // namespace detail + union { + T v; + }; + PLUGIFY_NO_UNIQUE_ADDRESS Alloc& a; - template - struct vector_iterator { - using allocator_traits = std::allocator_traits; - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename allocator_traits::value_type; - using difference_type = std::ptrdiff_t; - using pointer = typename allocator_traits::pointer; - using reference = value_type&; - protected: - pointer _current; - public: - constexpr vector_iterator() = default; - constexpr vector_iterator(const vector_iterator& other) = default; - constexpr vector_iterator(vector_iterator&& other) = default; - constexpr vector_iterator(pointer ptr) - : _current(ptr) {} - constexpr vector_iterator& operator=(const vector_iterator& other) = default; - constexpr vector_iterator& operator=(vector_iterator&& other) = default; - constexpr ~vector_iterator() = default; - public: - constexpr reference operator*() const noexcept { - return *_current; - } - constexpr pointer operator->() const noexcept { - return _current; - } - constexpr vector_iterator& operator++() noexcept { - ++_current; - return *this; - } - constexpr vector_iterator operator++(int) const noexcept { - return vector_iterator(_current++); - } - constexpr vector_iterator& operator--() noexcept { - --_current; - return *this; - } - constexpr vector_iterator operator--(int) const noexcept { - return vector_iterator(_current--); - } - constexpr vector_iterator& operator+=(const difference_type n) noexcept { - _current += n; - return *this; - } - constexpr vector_iterator operator+(const difference_type n) const noexcept { - vector_iterator temp = *this; - return temp += n; - } - constexpr vector_iterator& operator-=(const difference_type n) noexcept { - _current -= n; - return *this; - } - constexpr vector_iterator operator-(const difference_type n) const noexcept { - vector_iterator temp = *this; - return temp -= n; - } - constexpr reference operator[](const difference_type n) const noexcept { - return _current[n]; - } - template - constexpr friend typename vector_iterator::difference_type operator-(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_iterator& lhs, const vector_iterator& rhs) noexcept; - operator const pointer() const noexcept { - return _current; - } -#endif // __cpp_impl_three_way_comparison - pointer base() const noexcept { - return _current; - } - }; + constexpr T* addr() { + return std::addressof(v); + } - template - constexpr typename vector_iterator::difference_type operator-(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - using difference_type = typename vector_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } -#if __cpp_impl_three_way_comparison - template - constexpr auto operator<=>(const vector_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); - } -#endif // __cpp_impl_three_way_comparison + constexpr T& get() { + return *addr(); + } - template - struct vector_const_iterator { - using allocator_traits = std::allocator_traits; - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename allocator_traits::value_type; - using difference_type = std::ptrdiff_t; - using pointer = typename allocator_traits::const_pointer; - using reference = const value_type&; - protected: - pointer _current; - public: - constexpr vector_const_iterator() = default; - constexpr vector_const_iterator(const vector_const_iterator& other) = default; - constexpr vector_const_iterator(vector_const_iterator&& other) = default; - constexpr vector_const_iterator(pointer ptr) - : _current(ptr) {} - constexpr vector_const_iterator(const vector_iterator& other) // allow only iterator to const_iterator conversion - : _current(other.base()) {} - constexpr vector_const_iterator& operator=(const vector_const_iterator& other) = default; - constexpr vector_const_iterator& operator=(vector_const_iterator&& other) = default; - constexpr ~vector_const_iterator() = default; - public: - constexpr reference operator*() const noexcept { - return *_current; - } - constexpr pointer operator->() const noexcept { - return _current; - } - constexpr vector_const_iterator& operator++() noexcept { - ++_current; - return *this; - } - constexpr vector_const_iterator operator++(int) noexcept { - return vector_const_iterator(_current++); - } - constexpr vector_const_iterator& operator--() noexcept { - --_current; - return *this; - } - constexpr vector_const_iterator operator--(int) noexcept { - return vector_const_iterator(_current--); - } - constexpr vector_const_iterator& operator+=(const difference_type n) noexcept { - _current += n; - return *this; - } - constexpr vector_const_iterator operator+(const difference_type n) const noexcept { - vector_const_iterator temp = *this; - return temp += n; - } - constexpr vector_const_iterator& operator-=(const difference_type n) noexcept { - _current -= n; - return *this; - } - constexpr vector_const_iterator operator-(const difference_type n) const noexcept { - vector_const_iterator temp = *this; - return temp -= n; - } - constexpr reference operator[](const difference_type n) const noexcept { - return _current[n]; - } - template - constexpr friend typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept; -#endif // __cpp_impl_three_way_comparison - template - constexpr friend typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; - template - constexpr friend bool operator==(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; -#if __cpp_impl_three_way_comparison - template - constexpr friend auto operator<=>(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept; - operator const pointer() const noexcept { - return _current; - } -#endif // __cpp_impl_three_way_comparison - pointer base() const noexcept { - return _current; - } - }; + template + PLUGIFY_NO_CFI constexpr + explicit temp_value(Alloc& alloc, Args&&... args) + : a(alloc) { + allocator_traits::construct(a, addr(), std::forward(args)...); + } - template - constexpr typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - using difference_type = typename vector_const_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } - template - constexpr auto operator<=>(const vector_const_iterator& lhs, const vector_const_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); - } - template - constexpr typename vector_const_iterator::difference_type operator-(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - using difference_type = typename vector_const_iterator::difference_type; - return difference_type(lhs.base() - rhs.base()); - } - template - constexpr bool operator==(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() == rhs.base(); - } - template - constexpr auto operator<=>(const vector_const_iterator& lhs, const vector_iterator& rhs) noexcept { - return lhs.base() <=> rhs.base(); + constexpr ~temp_value() { + allocator_traits::destroy(a, addr()); + } + }; } - // vector - // based on implementations from libc++, libstdc++ and Microsoft STL - template> + template > class vector { - using allocator_traits = std::allocator_traits; + template + using split_buffer = split_buffer; public: + // + // Types + // using value_type = T; using allocator_type = Allocator; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; + using alloc_traits = std::allocator_traits; using reference = value_type&; using const_reference = const value_type&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; - using iterator = vector_iterator; - using const_iterator = vector_const_iterator; + using size_type = typename alloc_traits::size_type; + using difference_type = typename alloc_traits::difference_type; + using pointer = typename alloc_traits::pointer; + using const_pointer = typename alloc_traits::const_pointer; + using iterator = pointer; + using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - protected: - PLUGIFY_NO_UNIQUE_ADDRESS - allocator_type _allocator; - pointer _begin; - pointer _end; - pointer _capacity; + //static_assert(std::check_valid_allocator::value, ""); + static_assert( + std::is_same_v, + "Allocator::value_type must be same type as value_type" + ); - private: - constexpr static size_type growth_factor = 2; // When resizing, what number to scale by + // + // [vector.cons], construct/copy/destroy + // + constexpr vector() noexcept(std::is_nothrow_default_constructible_v) = default; - constexpr void copy_constructor(const vector& other) { - const size_type capacity = other.capacity(); - _begin = allocator_traits::allocate(_allocator, capacity); - std::uninitialized_copy(other.begin(), other.end(), begin()); - _end = _begin + other.size(); - _capacity = _begin + capacity; + constexpr explicit vector(const allocator_type& a) noexcept + : _alloc(a) { } - template - constexpr void range_constructor(InputIterator first, InputIterator last) { - const size_type count = static_cast(std::distance(first, last)); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_copy(first, last, _begin); - _capacity = _begin + count; - _end = _begin + count; + constexpr explicit vector(size_type n) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n); + } + guard.complete(); } - constexpr bool is_full() const { - return _end == _capacity; + constexpr + explicit vector(size_type n, const allocator_type& a) + : _alloc(a) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n); + } + guard.complete(); } - constexpr size_type calculate_new_capacity() const { - const size_type old_capacity = capacity(); - return old_capacity == 0 ? 1 : growth_factor * old_capacity; + constexpr vector(size_type n, const value_type& x) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n, x); + } + guard.complete(); } - constexpr iterator const_iterator_cast(const_iterator iter) noexcept { - return begin() + (iter - cbegin()); + constexpr + vector(size_type n, const value_type& x, const allocator_type& a) + : _alloc(a) { + auto guard = make_exception_guard(destroy_vector(*this)); + if (n > 0) { + vallocate(n); + construct_at_end(n, x); + } + guard.complete(); } - constexpr void reallocate(size_type new_capacity) { - reallocate(new_capacity, [](pointer const) {}); + template + constexpr + vector(InputIterator first, InputIterator last) { + init_with_sentinel(first, last); } - template - constexpr void reallocate(size_type new_capacity, const F& construct) { - const size_type old_size = size(); - const size_type old_capacity = capacity(); - PLUGIFY_ASSERT(new_capacity >= old_size, "plg::vector::reallocate(): resulted vector size would exceed size()", std::length_error); - if (new_capacity == old_capacity) - return; - - pointer const new_begin = allocator_traits::allocate(_allocator, new_capacity); - construct(new_begin); - std::uninitialized_move(_begin, _end, new_begin); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + old_size; - _capacity = _begin + new_capacity; - } + template + constexpr + vector(InputIterator first, InputIterator last, const allocator_type& a) + : _alloc(a) { + init_with_sentinel(first, last); + } + + template + constexpr + vector(ForwardIterator first, ForwardIterator last) { + size_type n = static_cast(std::distance(first, last)); + init_with_size(first, last, n); + } + + template + constexpr + vector(ForwardIterator first, ForwardIterator last, const allocator_type& a) + : _alloc(a) { + size_type n = static_cast(std::distance(first, last)); + init_with_size(first, last, n); + } + +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr vector( + std::from_range_t, + Range&& range, + const allocator_type& alloc = allocator_type() + ) : _alloc(alloc) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + init_with_size(std::ranges::begin(range), std::ranges::end(range), n); - template - constexpr void emplace_at_end(const F& construct) { - if (is_full()) { - reallocate(calculate_new_capacity(), construct); } else { - construct(_begin); + init_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } } +#endif - template - constexpr void resize_to(size_type count, const V& value) { - if (count < size()) { - std::destroy(_begin + count, _end); - _end = _begin + count; - } else if (count > size()) { - const size_type old_size = size(); - auto construct = [&](pointer const data) { - if constexpr (std::is_same_v) { - std::uninitialized_fill(data + old_size, data + count, value); - } else { - std::uninitialized_value_construct(data + old_size, data + count); - } - }; - if (count > capacity()) { - reallocate(count, construct); - } else { - construct(_begin); + private: + class destroy_vector { + public: + constexpr explicit destroy_vector(vector& vec) + : vec_(vec) { + } + + constexpr void operator()() { + if (vec_._begin != nullptr) { + vec_.clear(); + vec_.annotate_delete(); + alloc_traits::deallocate(vec_._alloc, vec_._begin, vec_.capacity()); } - _end = _begin + count; } - } - constexpr void swap_without_allocator(vector&& other) noexcept { - using std::swap; - swap(_begin, other._begin); - swap(_end, other._end); - swap(_capacity, other._capacity); - } + private: + vector& vec_; + }; public: - // constructor - constexpr vector() noexcept(std::is_nothrow_default_constructible::value) - : _allocator(Allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { + constexpr ~vector() { + destroy_vector (*this)(); + } + + constexpr vector(const vector& x) + : _alloc(alloc_traits::select_on_container_copy_construction(x._alloc)) { + init_with_size(x._begin, x._end, x.size()); } - constexpr explicit vector(const Allocator& allocator) noexcept - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { + constexpr + vector(const vector& x, const std::type_identity_t& a) + : _alloc(a) { + init_with_size(x._begin, x._end, x.size()); } - constexpr vector(size_type count, const T& value, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_fill_n(_begin, count, value); - _capacity = _begin + count; - _end = _begin + count; + constexpr vector& operator=(const vector& x); + + constexpr vector(std::initializer_list il) { + init_with_size(il.begin(), il.end(), il.size()); } - constexpr explicit vector(size_type count, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - _begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_value_construct_n(_begin, count); - _capacity = _begin + count; - _end = _begin + count; + constexpr + vector(std::initializer_list il, const allocator_type& a) + : _alloc(a) { + init_with_size(il.begin(), il.end(), il.size()); } - template - constexpr vector(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(static_cast(std::distance(first, last)) <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - range_constructor(first, last); + constexpr vector& + operator=(std::initializer_list il) { + assign(il.begin(), il.end()); + return *this; } - constexpr vector(const vector& other) - : _allocator(other.get_allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - copy_constructor(other); + constexpr vector(vector&& x) noexcept; + + constexpr + vector(vector&& x, const std::type_identity_t& a); + + constexpr vector& operator=(vector&& x) noexcept( + std::allocator_traits::propagate_on_container_move_assignment::value || + std::allocator_traits::is_always_equal::value) + { + move_assign( + x, + std::integral_constant() + ); + return *this; } - constexpr vector(const vector& other, const Allocator& allocator) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - copy_constructor(other); + template + constexpr void + assign(InputIterator first, InputIterator last) { + assign_with_sentinel(first, last); } - constexpr vector(vector&& other) noexcept(std::is_nothrow_move_constructible::value) - : _allocator(Allocator()), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - swap(other); + template + constexpr void + assign(ForwardIterator first, ForwardIterator last) { + assign_with_size(first, last, std::distance(first, last)); } - constexpr vector(vector&& other, const Allocator& allocator) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - if constexpr (allocator_traits::is_always_equal::value) { - swap_without_allocator(std::move(other)); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr void assign_range(Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + assign_with_size(std::ranges::begin(range), std::ranges::end(range), n); + } else { - if (get_allocator() == other.get_allocator()) { - swap_without_allocator(std::move(other)); - } else { - const size_type capacity = other.capacity(); - _begin = allocator_traits::allocate(_allocator, capacity); - std::uninitialized_move(other.begin(), other.end(), begin()); - _end = _begin + other.size(); - _capacity = _begin + capacity; - } + assign_with_sentinel(std::ranges::begin(range), std::ranges::end(range)); } } +#endif - constexpr vector(std::initializer_list list, const Allocator& allocator = Allocator()) - : _allocator(allocator), _begin{nullptr}, _end{nullptr}, _capacity{nullptr} { - PLUGIFY_ASSERT(list.size() <= max_size(), "plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error); - range_constructor(list.begin(), list.end()); + constexpr void + assign(size_type n, const_reference u); + + constexpr void + assign(std::initializer_list il) { + assign(il.begin(), il.end()); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr vector(std::from_range_t, Range&& range, const Allocator& alloc = Allocator()) - : vector(std::ranges::begin(range), std::ranges::end(range), alloc) {} -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES + [[nodiscard]] constexpr allocator_type + get_allocator() const noexcept { + return this->_alloc; + } - // destructor - constexpr ~vector() { - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); + // + // Iterators + // + [[nodiscard]] constexpr iterator begin() noexcept { + return make_iter(add_alignment_assumption(this->_begin)); } - // operator= - constexpr vector& operator=(const vector& other) { - if (this == &other) [[unlikely]] { - return *this; - } + [[nodiscard]] constexpr const_iterator + begin() const noexcept { + return make_iter(add_alignment_assumption(this->_begin)); + } - clear(); - if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != other.get_allocator()) { - allocator_traits::deallocate(_allocator, _begin, capacity()); - } - } - _allocator = other.get_allocator(); - } + [[nodiscard]] constexpr iterator end() noexcept { + return make_iter(add_alignment_assumption(this->_end)); + } - assign(other.begin(), other.end()); - return *this; + [[nodiscard]] constexpr const_iterator + end() const noexcept { + return make_iter(add_alignment_assumption(this->_end)); } - constexpr vector& operator=(vector&& other) noexcept( - std::allocator_traits::propagate_on_container_move_assignment::value || - std::allocator_traits::is_always_equal::value) { - if (this == &other) [[unlikely]] { - return *this; - } + [[nodiscard]] constexpr reverse_iterator + rbegin() noexcept { + return reverse_iterator(end()); + } - clear(); - if constexpr (allocator_traits::propagate_on_container_move_assignment::value) { - if constexpr (!allocator_traits::is_always_equal::value) { - if (get_allocator() != other.get_allocator()) { - allocator_traits::deallocate(_allocator, _begin, capacity()); - } - } - _allocator = other.get_allocator(); - } + [[nodiscard]] constexpr const_reverse_iterator + rbegin() const noexcept { + return const_reverse_iterator(end()); + } - if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) { - swap_without_allocator(std::move(other)); - } else { - if (get_allocator() == other.get_allocator()) { - swap_without_allocator(std::move(other)); - } else { - assign(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end())); - other.clear(); - } - } - return *this; + [[nodiscard]] constexpr reverse_iterator + rend() noexcept { + return reverse_iterator(begin()); } - constexpr vector& operator=(std::initializer_list list) { - assign(list.begin(), list.end()); - return *this; + [[nodiscard]] constexpr const_reverse_iterator + rend() const noexcept { + return const_reverse_iterator(begin()); } - // assign - constexpr void assign(size_type count, const T& value) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error); - if (count > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_fill_n(new_begin, count, value); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _capacity = _begin + count; - } else if (size() >= count) { - std::fill_n(_begin, count, value); - std::destroy(_begin + count, _end); - } else { - std::fill_n(_begin, size(), value); - std::uninitialized_fill_n(_begin + size(), count - size(), value); - } - _end = _begin + count; + [[nodiscard]] constexpr const_iterator + cbegin() const noexcept { + return begin(); } - template - constexpr void assign(InputIterator first, InputIterator last) { - const size_type count = static_cast(std::distance(first, last)); - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error); - if (count > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, count); - std::uninitialized_copy(first, last, new_begin); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _capacity = _begin + count; - } else if (size() >= count) { - std::copy(first, last, _begin); - std::destroy(_begin + count, _end); - } else { - std::copy(first, first + size(), _begin); - std::uninitialized_copy(first + size(), last, _begin + size()); - } - _end = _begin + count; + [[nodiscard]] constexpr const_iterator + cend() const noexcept { + return end(); } - constexpr void assign(std::initializer_list list) { - assign(list.begin(), list.end()); + [[nodiscard]] constexpr const_reverse_iterator + crbegin() const noexcept { + return rbegin(); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr void assign_range(Range&& range) { - assign(std::ranges::begin(range), std::ranges::end(range)); + [[nodiscard]] constexpr const_reverse_iterator + crend() const noexcept { + return rend(); } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - // get_allocator - constexpr allocator_type get_allocator() const { - return _allocator; + // + // [vector.capacity], capacity + // + [[nodiscard]] constexpr size_type size() const noexcept { + return static_cast(this->_end - this->_begin); } - // element access - constexpr reference at(size_type position) { - PLUGIFY_ASSERT(position < size(), "plg::vector::at(): input index is out of bounds", std::out_of_range); - return *(_begin + position); + [[nodiscard]] constexpr size_type + capacity() const noexcept { + return static_cast(this->_cap - this->_begin); } - constexpr const_reference at(size_type position) const { - PLUGIFY_ASSERT(position < size(), "plg::vector::at(): input index is out of bounds", std::out_of_range); - return *(_begin + position); + [[nodiscard]] constexpr bool + empty() const noexcept { + return this->_begin == this->_end; } - constexpr reference operator[](size_type position) noexcept { - return *(_begin + position); + [[nodiscard]] constexpr size_type + max_size() const noexcept { + return std::min( + alloc_traits::max_size(this->_alloc), + std::numeric_limits::max() + ); } - constexpr const_reference operator[](size_type position) const noexcept { - return *(_begin + position); + constexpr void reserve(size_type n); + constexpr void shrink_to_fit() noexcept; + + // + // element access + // + [[nodiscard]] constexpr reference + operator[](size_type n) noexcept { + PLUGIFY_ASSERT(n < size(), "vector[] index out of bounds"); + return this->_begin[n]; } - constexpr reference front() { - PLUGIFY_ASSERT(!empty(), "plg::vector::front(): vector is empty", std::length_error); - return *_begin; + [[nodiscard]] constexpr const_reference + operator[](size_type n) const noexcept { + PLUGIFY_ASSERT(n < size(), "vector[] index out of bounds"); + return this->_begin[n]; } - constexpr const_reference front() const { - PLUGIFY_ASSERT(!empty(), "plg::vector::front(): vector is empty", std::length_error); - return *_begin; + [[nodiscard]] constexpr reference at(size_type n) { + if (n >= size()) { + this->throw_out_of_range(); + } + return this->_begin[n]; } - constexpr reference back() { - PLUGIFY_ASSERT(!empty(), "plg::vector::back(): vector is empty", std::length_error); - return *(_end - 1); + [[nodiscard]] constexpr const_reference + at(size_type n) const { + if (n >= size()) { + this->throw_out_of_range(); + } + return this->_begin[n]; } - constexpr const_reference back() const { - PLUGIFY_ASSERT(!empty(), "plg::vector::back(): vector is empty", std::length_error); - return *(_end - 1); + [[nodiscard]] constexpr reference front() noexcept { + PLUGIFY_ASSERT(!empty(), "front() called on an empty vector"); + return *this->_begin; } - constexpr T* data() noexcept { - return _begin; + [[nodiscard]] constexpr const_reference + front() const noexcept { + PLUGIFY_ASSERT(!empty(), "front() called on an empty vector"); + return *this->_begin; } - constexpr const T* data() const noexcept { - return _begin; + [[nodiscard]] constexpr reference back() noexcept { + PLUGIFY_ASSERT(!empty(), "back() called on an empty vector"); + return *(this->_end - 1); } - // iterators - constexpr iterator begin() noexcept { - return iterator(_begin); + [[nodiscard]] constexpr const_reference + back() const noexcept { + PLUGIFY_ASSERT(!empty(), "back() called on an empty vector"); + return *(this->_end - 1); } - constexpr const_iterator begin() const noexcept { - return const_iterator(_begin); + // + // [vector.data], data access + // + [[nodiscard]] constexpr value_type* + data() noexcept { + return std::to_address(this->_begin); } - constexpr const_iterator cbegin() const noexcept { - return const_iterator(_begin); + [[nodiscard]] constexpr const value_type* + data() const noexcept { + return std::to_address(this->_begin); } - constexpr iterator end() noexcept { - return iterator(_end); + // + // [vector.modifiers], modifiers + // + constexpr void push_back(const_reference x) { + emplace_back(x); } - constexpr const_iterator end() const noexcept { - return const_iterator(_end); + constexpr void push_back(value_type&& x) { + emplace_back(std::move(x)); } - constexpr const_iterator cend() const noexcept { - return const_iterator(_end); + template + constexpr + reference + emplace_back(Args&&... args); + + template + constexpr void + emplace_back_assume_capacity(Args&&... args) { + PLUGIFY_ASSERT( + size() < capacity(), + "We assume that we have enough space to insert an element at the end of the vector" + ); + ConstructTransaction tx(*this, 1); + alloc_traits::construct(this->_alloc, std::to_address(tx.pos_), std::forward(args)...); + ++tx.pos_; } - constexpr reverse_iterator rbegin() noexcept { - return reverse_iterator(_end); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr void append_range(Range&& range) { + insert_range(end(), std::forward(range)); + } +#endif + + constexpr void pop_back() { + PLUGIFY_ASSERT(!empty(), "vector::pop_back called on an empty vector"); + this->destruct_at_end(this->_end - 1); } - constexpr const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(_end); + constexpr iterator + insert(const_iterator position, const_reference x); + + constexpr iterator + insert(const_iterator position, value_type&& x); + template + constexpr iterator + emplace(const_iterator position, Args&&... args); + + constexpr iterator + insert(const_iterator position, size_type n, const_reference x); + + template + constexpr iterator + insert(const_iterator position, InputIterator first, InputIterator last) { + return insert_with_sentinel(position, first, last); } - constexpr const_reverse_iterator crbegin() const noexcept { - return const_reverse_iterator(_end); + template + constexpr iterator + insert(const_iterator position, ForwardIterator first, ForwardIterator last) { + return insert_with_size(position, first, last, std::distance(first, last)); } - constexpr reverse_iterator rend() noexcept { - return reverse_iterator(_begin); +#if PLUGIFY_HAS_CXX23 + template Range> + constexpr iterator + insert_range(const_iterator position, Range&& range) { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) { + auto n = static_cast(std::ranges::distance(range)); + return insert_with_size(position, std::ranges::begin(range), std::ranges::end(range), n); + + } else { + return insert_with_sentinel(position, std::ranges::begin(range), std::ranges::end(range)); + } } +#endif - constexpr const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(_begin); + constexpr iterator + insert(const_iterator position, std::initializer_list il) { + return insert(position, il.begin(), il.end()); } - constexpr const_reverse_iterator crend() const noexcept { - return const_reverse_iterator(_begin); + constexpr iterator erase(const_iterator position); + constexpr iterator + erase(const_iterator first, const_iterator last); + + constexpr void clear() noexcept { + size_type old_size = size(); + base_destruct_at_end(this->_begin); + annotate_shrink(old_size); } - // capacity - constexpr bool empty() const { - return (_begin == _end); + constexpr void resize(size_type sz); + constexpr void + resize(size_type sz, const_reference x); + + constexpr void swap(vector&) noexcept; + + constexpr bool invariants() const; + + private: + pointer _begin = nullptr; + pointer _end = nullptr; + pointer _cap = nullptr; + PLUGIFY_NO_UNIQUE_ADDRESS + allocator_type _alloc; + + // Allocate space for n objects + // throws length_error if n > max_size() + // throws (probably bad_alloc) if memory run out + // Precondition: _begin == _end == _cap == nullptr + // Precondition: n > 0 + // Postcondition: capacity() >= n + // Postcondition: size() == 0 + constexpr void vallocate(size_type n) { + if (n > max_size()) { + this->throw_length_error(); + } + auto allocation = allocate_at_least(this->_alloc, n); + _begin = allocation.ptr; + _end = allocation.ptr; + _cap = _begin + allocation.count; + annotate_new(0); + } + + constexpr void vdeallocate() noexcept; + constexpr size_type recommend(size_type new_size) const; + constexpr void construct_at_end(size_type n); + constexpr void + construct_at_end(size_type n, const_reference x); + + template + constexpr void + init_with_size(InputIterator first, Sentinel last, size_type n) { + auto guard = make_exception_guard(destroy_vector(*this)); + + if (n > 0) { + vallocate(n); + construct_at_end(std::move(first), std::move(last), n); + } + + guard.complete(); } - constexpr size_type size() const noexcept { - return static_cast(_end - _begin); + template + constexpr void + init_with_sentinel(InputIterator first, Sentinel last) { + auto guard = make_exception_guard(destroy_vector(*this)); + + for (; first != last; ++first) { + emplace_back(*first); + } + + guard.complete(); } - constexpr size_type max_size() const noexcept { - return allocator_traits::max_size(_allocator); + template + constexpr void + assign_with_sentinel(Iterator first, Sentinel last); + + // The `Iterator` in `*_with_size` functions can be input-only only if called from + // `*_range` (since C++23). Otherwise, `Iterator` is a forward iterator. + + template + constexpr void + assign_with_size(Iterator first, Sentinel last, difference_type n); + + template + requires (!std::same_as())&&, value_type&&>) + constexpr void + insert_assign_n_unchecked(Iterator first, difference_type n, pointer position) { + for (pointer end_position = position + n; position != end_position; + ++position, (void) ++first) { + detail::temp_value tmp(this->_alloc, *first); + *position = std::move(tmp.get()); + } } - constexpr void reserve(size_type new_capacity) { - PLUGIFY_ASSERT(new_capacity <= max_size(), "plg::vector::reserve(): allocated memory size would exceed max_size()", std::length_error); - if (new_capacity > capacity()) { - reallocate(new_capacity); + template + requires (std::same_as())&&, value_type&&>) + constexpr void + insert_assign_n_unchecked(Iterator first, difference_type n, pointer position) { +#if PLUGIFY_HAS_CXX23 + if constexpr (!std::forward_iterator) { + // Handles input-only sized ranges for insert_range + std::ranges::copy_n(std::move(first), n, position); + } else +#endif + { + std::copy_n(first, n, position); } } - constexpr size_type capacity() const noexcept { - return static_cast(_capacity - _begin); + template + constexpr iterator + insert_with_sentinel(const_iterator position, InputIterator first, Sentinel last); + + template + constexpr iterator + insert_with_size(const_iterator position, Iterator first, Sentinel last, difference_type n); + + template + constexpr void + construct_at_end(InputIterator first, Sentinel last, size_type n); + + constexpr void append(size_type n); + constexpr void + append(size_type n, const_reference x); + + constexpr iterator make_iter(pointer p) noexcept { + return iterator(p); } - constexpr void shrink_to_fit() { - reallocate(size()); + constexpr const_iterator make_iter(const_pointer p) const noexcept { + return const_iterator(p); } - // modifiers - constexpr void clear() noexcept { - std::destroy(_begin, _end); - _end = _begin; - } - - constexpr iterator insert(const_iterator position, const T& value) { - return emplace(position, value); - } - - constexpr iterator insert(const_iterator position, T&& value) { - return emplace(position, std::move(value)); - } - - constexpr iterator insert(const_iterator position, size_type count, const T& value) { - const size_type sz = size(); - const size_type new_size = sz + count; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::insert(): pos out of range", std::out_of_range); - if (count != 0) { - if (new_size > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, new_size); - pointer const old_position = _begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - pointer const new_position = new_begin + position_distance; - std::uninitialized_fill_n(new_position, count, value); - std::uninitialized_move(old_position, _end, new_position + count); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _end; - } else { - pointer const pointer_position = _begin + position_distance; - std::uninitialized_fill_n(_end, count, value); - _end += count; - std::rotate(pointer_position, _end - count, _end); - } - } - return begin() + position_distance; + constexpr void + swap_out_circular_buffer(split_buffer& v); + constexpr pointer + swap_out_circular_buffer(split_buffer& v, pointer p); + constexpr void + move_range(pointer from_s, pointer from_e, pointer to); + constexpr void + move_assign(vector& c, std::true_type) noexcept(std::is_nothrow_move_assignable::value); + constexpr void + move_assign(vector& c, std::false_type) noexcept(alloc_traits::is_always_equal::value); + + constexpr void + destruct_at_end(pointer new_last) noexcept { + size_type old_size = size(); + base_destruct_at_end(new_last); + annotate_shrink(old_size); } - template - constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last) { - const size_type sz = size(); - const size_type count = static_cast(std::distance(first, last)); - const size_type new_size = sz + count; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::insert(): pos out of range", std::out_of_range); - if (count != 0) { - if (new_size > capacity()) { - pointer const new_begin = allocator_traits::allocate(_allocator, new_size); - pointer const old_position = _begin + position_distance; - pointer const new_position = new_begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - std::uninitialized_copy(first, last, new_position); - std::uninitialized_move(old_position, _end, new_position + count); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _end; - } else { - pointer const pointer_position = _begin + position_distance; - std::uninitialized_copy(first, last, _end); - _end += count; - std::rotate(pointer_position, _end - count, _end); - } - } - return begin() + position_distance; + template + constexpr inline pointer + emplace_back_slow_path(Args&&... args); + + // The following functions are no-ops outside of AddressSanitizer mode. + // We call annotations for every allocator, unless explicitly disabled. + // + // To disable annotations for a particular allocator, change value of + // asan_annotate_container_with_allocator to false. + // For more details, see the "Using libc++" documentation page or + // the documentation for sanitizer_annotate_contiguous_container. + + constexpr void + annotate_contiguous_container( + [[maybe_unused]] const void* old_mid, + [[maybe_unused]] const void* new_mid + ) const { + plg::annotate_contiguous_container(data(), data() + capacity(), old_mid, new_mid); } - constexpr iterator insert(const_iterator position, std::initializer_list list) { - return insert(position, list.begin(), list.end()); + constexpr void + annotate_new(size_type current_size) const noexcept { + annotate_contiguous_container(data() + capacity(), data() + current_size); } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr iterator insert_range(const_iterator pos, Range&& range) { - return insert(pos - begin(), std::ranges::begin(range), std::ranges::end(range)); + constexpr void annotate_delete() const noexcept { + annotate_contiguous_container(data() + size(), data() + capacity()); } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - template - iterator emplace(const_iterator position, Args&&... args) { - const size_type sz = size(); - const size_type new_size = sz + 1; - PLUGIFY_ASSERT(new_size <= max_size(), "plg::vector::emplace(): resulted vector size would exceed max_size()", std::length_error); - const size_type position_distance = static_cast(position - cbegin()); - PLUGIFY_ASSERT(position_distance <= sz, "plg::vector::emplace(): pos out of range", std::out_of_range); - if (position == cend()) { - emplace_back(std::forward(args)...); - } else { - if (is_full()) { - const size_type new_capacity = calculate_new_capacity(); - pointer const new_begin = allocator_traits::allocate(_allocator, new_capacity); - pointer const old_position = _begin + position_distance; - pointer const new_position = new_begin + position_distance; - std::uninitialized_move(_begin, old_position, new_begin); - std::construct_at(new_position, std::forward(args)...); - std::uninitialized_move(old_position, _end, new_position + 1); - std::destroy(_begin, _end); - allocator_traits::deallocate(_allocator, _begin, capacity()); - _begin = new_begin; - _end = _begin + new_size; - _capacity = _begin + new_capacity; - } else { - pointer const pointer_position = _begin + position_distance; - std::construct_at(_end, std::forward(args)...); - ++_end; - std::rotate(pointer_position, _end - 1, _end); - } - } - return begin() + position_distance; + constexpr void + annotate_increase(size_type n) const noexcept { + annotate_contiguous_container(data() + size(), data() + size() + n); } - constexpr iterator erase(const_iterator position) { - iterator nonconst_position = const_iterator_cast(position); - if (nonconst_position + 1 != end()) { - std::rotate(nonconst_position, nonconst_position + 1, end()); + constexpr void + annotate_shrink(size_type old_size) const noexcept { + annotate_contiguous_container(data() + old_size, data() + size()); + } + + struct ConstructTransaction { + constexpr + explicit ConstructTransaction(vector& v, size_type n) + : v_(v) + , pos_(v._end) + , new_end_(v._end + n) { + v.annotate_increase(n); } - --_end; - std::destroy_at(_end); - return nonconst_position; - } - - constexpr iterator erase(const_iterator first, const_iterator last) { - PLUGIFY_ASSERT(first <= last, "plg::vector::erase(): called with invalid range", std::out_of_range); - iterator nonconst_first = const_iterator_cast(first); - iterator nonconst_last = const_iterator_cast(last); - if (nonconst_first != nonconst_last) { - if (nonconst_last != end()) { - std::rotate(nonconst_first, nonconst_last, end()); + + constexpr ~ConstructTransaction() { + v_._end = pos_; + if (pos_ != new_end_) { + v_.annotate_shrink(new_end_ - v_._begin); } - _end = nonconst_first.base() + static_cast(end() - nonconst_last); - std::destroy(_end, _end + static_cast(std::distance(first, last))); } - return nonconst_first; - } - constexpr void push_back(const T& value) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, value); - }); - ++_end; + vector& v_; + pointer pos_; + const const_pointer new_end_; + + ConstructTransaction(const ConstructTransaction&) = delete; + ConstructTransaction& operator=(const ConstructTransaction&) = delete; + }; + + constexpr void + base_destruct_at_end(pointer new_last) noexcept { + pointer soon_to_be_end = this->_end; + while (new_last != soon_to_be_end) { + alloc_traits::destroy(this->_alloc, std::to_address(--soon_to_be_end)); + } + this->_end = new_last; } - constexpr void push_back(T&& value) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, std::move(value)); - }); - ++_end; + constexpr void copy_assign_alloc(const vector& c) { + copy_assign_alloc( + c, + std::integral_constant() + ); } - template - constexpr reference emplace_back(Args&&... args) { - const size_type sz = size(); - PLUGIFY_ASSERT(sz + 1 <= max_size(), "plg::vector::emplace_back(): resulted vector size would exceed max_size()", std::length_error); - emplace_at_end([&](pointer const data) { - std::construct_at(data + sz, std::forward(args)...); - }); - ++_end; - return back(); + constexpr void + move_assign_alloc(vector& c) noexcept( + !alloc_traits::propagate_on_container_move_assignment::value + || std::is_nothrow_move_assignable::value + ) { + move_assign_alloc( + c, + std::integral_constant() + ); } - constexpr void pop_back() { - PLUGIFY_ASSERT(!empty(), "plg::vector::pop_back(): vector is empty", std::length_error); - --_end; - std::destroy_at(_end); + [[noreturn]] static void throw_length_error() { + PLUGIFY_THROW("allocated memory size would exceed max_size()", std::length_error); } - constexpr void resize(size_type count) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error); - resize_to(count, detail::initialized_value_tag{}); + [[noreturn]] static void throw_out_of_range() { + PLUGIFY_THROW("input index is out of bounds", std::out_of_range); } - constexpr void resize(size_type count, const T& value) { - PLUGIFY_ASSERT(count <= max_size(), "plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error); - resize_to(count, value); + constexpr void + copy_assign_alloc(const vector& c, std::true_type) { + if (this->_alloc != c._alloc) { + clear(); + annotate_delete(); + alloc_traits::deallocate(this->_alloc, this->_begin, capacity()); + this->_begin = this->_end = this->_cap = nullptr; + } + this->_alloc = c._alloc; } - constexpr vector& operator+=(const T& value) { - push_back(value); - return *this; + constexpr void + copy_assign_alloc(const vector&, std::false_type) { } - constexpr vector& operator+=(T&& value) { - push_back(std::move(value)); - return *this; + constexpr void + move_assign_alloc(vector& c, std::true_type) noexcept( + std::is_nothrow_move_assignable_v + ) { + this->_alloc = std::move(c._alloc); } - constexpr vector& operator+=(const vector& other) { - insert(end(), other.begin(), other.end()); - return *this; + constexpr void + move_assign_alloc(vector&, std::false_type) noexcept { } - constexpr vector& operator+=(vector&& other) { - if (this == &other) [[unlikely]] { - return *this; + template + requires(std::is_pointer_v) + static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(Ptr p) noexcept { + if (!std::is_constant_evaluated()) { + return static_cast(std::assume_aligned(p)); } - - insert(end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end())); - return *this; + return p; } -#if PLUGIFY_VECTOR_CONTAINERS_RANGES - template Range> - constexpr void append_range(Range&& range) { - return insert(end(), std::ranges::begin(range), std::ranges::end(range)); + template + requires(!std::is_pointer_v) + static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(Ptr p) noexcept { + return p; } -#endif // PLUGIFY_VECTOR_CONTAINERS_RANGES - constexpr void swap(vector& other) noexcept(std::allocator_traits::propagate_on_container_swap::value || std::allocator_traits::is_always_equal::value) { - using std::swap; - if constexpr (allocator_traits::propagate_on_container_swap::value) { - swap(_allocator, other._allocator); - } - swap(_begin, other._begin); - swap(_end, other._end); - swap(_capacity, other._capacity); + constexpr void + swap_layouts(split_buffer& sb) { + auto vector_begin = _begin; + auto vector_sentinel = _end; + auto vector_cap = _cap; + + auto sb_begin = sb.begin(); + auto sb_sentinel = sb.raw_sentinel(); + auto sb_cap = sb.raw_capacity(); + + // TODO: replace with set_valid_range and set_capacity when vector supports it. + _begin = sb_begin; + _end = sb_sentinel; + _cap = sb_cap; + + sb.set_valid_range(vector_begin, vector_sentinel); + sb.set_capacity(vector_cap); } + }; + + template < + std::input_iterator InputIterator, + is_allocator Alloc> + vector(InputIterator, InputIterator, Alloc = Alloc()) + -> vector, Alloc>; + +#if PLUGIFY_HAS_CXX23 + template < + std::ranges::input_range Range, + is_allocator Alloc> + vector(std::from_range_t, Range&&, Alloc = Alloc()) + -> vector, Alloc>; +#endif + + // swap_out_circular_buffer relocates the objects in [_begin, _end) into the front of v and + // swaps the buffers of *this and v. It is assumed that v provides space for exactly (_end - + // _begin) objects in the front. This function has a strong exception guarantee. + template + constexpr void + vector::swap_out_circular_buffer(split_buffer& v) { + annotate_delete(); + auto new_begin = v.begin() - size(); + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(_begin), + std::to_address(_end), + std::to_address(new_begin) + ); + v.set_valid_range(new_begin, v.end()); + _end = _begin; // All the objects have been destroyed by relocating them. + + swap_layouts(v); + v.set_data(v.begin()); + annotate_new(size()); + } - constexpr operator std::span() noexcept { - return std::span(data(), size()); + // swap_out_circular_buffer relocates the objects in [_begin, p) into the front of v, the + // objects in [p, _end) into the back of v and swaps the buffers of *this and v. It is assumed + // that v provides space for exactly (p - _begin) objects in the front and space for at least + // (_end - p) objects in the back. This function has a strong exception guarantee if _begin == p + // || _end == p. + template + constexpr typename vector::pointer + vector::swap_out_circular_buffer( + split_buffer& v, + pointer p + ) { + annotate_delete(); + pointer ret = v.begin(); + + // Relocate [p, _end) first to avoid having a hole in [_begin, _end) + // in case something in [_begin, p) throws. + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(p), + std::to_address(_end), + std::to_address(v.end()) + ); + auto relocated_so_far = _end - p; + v.set_sentinel(v.end() + relocated_so_far); + _end = p; // The objects in [p, _end) have been destroyed by relocating them. + auto new_begin = v.begin() - (p - _begin); + + uninitialized_allocator_relocate( + this->_alloc, + std::to_address(_begin), + std::to_address(p), + std::to_address(new_begin) + ); + v.set_valid_range(new_begin, v.end()); + _end = _begin; // All the objects have been destroyed by relocating them. + swap_layouts(v); + v.set_data(v.begin()); + annotate_new(size()); + return ret; + } + + template + constexpr void vector::vdeallocate() noexcept { + if (this->_begin != nullptr) { + clear(); + annotate_delete(); + alloc_traits::deallocate(this->_alloc, this->_begin, capacity()); + this->_begin = this->_end = this->_cap = nullptr; } + } - constexpr operator std::span() const noexcept { - return std::span(data(), size()); + // Precondition: new_size > capacity() + template + constexpr inline + typename vector::size_type + vector::recommend(size_type new_size) const { + const size_type ms = max_size(); + if (new_size > ms) { + this->throw_length_error(); + } + const size_type cap = capacity(); + if (cap >= ms / 2) { + return ms; } + return std::max(2 * cap, new_size); + } - constexpr std::span span() const noexcept { - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == size() + n + template + constexpr void vector::construct_at_end(size_type n) { + ConstructTransaction tx(*this, n); + const_pointer new_end = tx.new_end_; + for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos)); } + } - constexpr std::span span() noexcept { - return std::span(data(), size()); + // Copy constructs n objects starting at _end from x + // throws if construction throws + // Precondition: n > 0 + // Precondition: size() + n <= capacity() + // Postcondition: size() == old size() + n + // Postcondition: [i] == x for all i in [size() - n, n) + template + constexpr inline void + vector::construct_at_end(size_type n, const_reference x) { + ConstructTransaction tx(*this, n); + const_pointer new_end = tx.new_end_; + for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos), x); } + } + + template + template + constexpr void + vector::construct_at_end(InputIterator first, Sentinel last, size_type n) { + ConstructTransaction tx(*this, n); + tx.pos_ = uninitialized_allocator_copy( + this->_alloc, + std::move(first), + std::move(last), + tx.pos_ + ); + } - template - constexpr std::span span_size() { - PLUGIFY_ASSERT(size() == Size, "plg::vector::span_size(): const_span_size argument does not match size of vector", std::length_error); - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Postcondition: size() == size() + n + // Exception safety: strong. + template + constexpr void vector::append(size_type n) { + if (static_cast(this->_cap - this->_end) >= n) { + this->construct_at_end(n); + } else { + split_buffer v(recommend(size() + n), size(), this->_alloc); + v.construct_at_end(n); + swap_out_circular_buffer(v); } + } - template - constexpr std::span const_span_size() const { - PLUGIFY_ASSERT(size() == Size, "plg::vector::const_span_size(): const_span_size argument does not match size of vector", std::length_error); - return std::span(data(), size()); + // Default constructs n objects starting at _end + // throws if construction throws + // Postcondition: size() == size() + n + // Exception safety: strong. + template + constexpr void + vector::append(size_type n, const_reference x) { + if (static_cast(this->_cap - this->_end) >= n) { + this->construct_at_end(n, x); + } else { + split_buffer v(recommend(size() + n), size(), this->_alloc); + v.construct_at_end(n, x); + swap_out_circular_buffer(v); } + } + + template + constexpr inline + vector::vector(vector&& x) noexcept + : _alloc(std::move(x._alloc)) { + this->_begin = x._begin; + this->_end = x._end; + this->_cap = x._cap; + x._begin = x._end = x._cap = nullptr; + } - constexpr std::span byte_span() const noexcept { - return std::as_bytes(span()); + template + constexpr inline + vector::vector(vector&& x, const std::type_identity_t& a) + : _alloc(a) { + if (a == x._alloc) { + this->_begin = x._begin; + this->_end = x._end; + this->_cap = x._cap; + x._begin = x._end = x._cap = nullptr; + } else { + using Ip = std::move_iterator; + init_with_size(Ip(x.begin()), Ip(x.end()), x.size()); } + } - constexpr std::span byte_span() noexcept { - return std::as_writable_bytes(span()); + template + constexpr void + vector::move_assign(vector& c, std::false_type) noexcept( + alloc_traits::is_always_equal::value + ) { + if (this->_alloc != c._alloc) { + using Ip = std::move_iterator; + assign(Ip(c.begin()), Ip(c.end())); + } else { + move_assign(c, std::true_type()); } + } - constexpr bool contains(const T& elem) const { - return std::find(begin(), end(), elem) != end(); + template + constexpr void + vector::move_assign(vector& c, std::true_type) noexcept( + std::is_nothrow_move_assignable::value + ) { + vdeallocate(); + move_assign_alloc(c); // this can throw + this->_begin = c._begin; + this->_end = c._end; + this->_cap = c._cap; + c._begin = c._end = c._cap = nullptr; + } + + template + constexpr inline vector& + vector::operator=(const vector& x) { + if (this != std::addressof(x)) { + copy_assign_alloc(x); + assign(x._begin, x._end); } + return *this; + } - template - constexpr bool contains_if(F predicate) { - return std::find_if(begin(), end(), predicate) != end(); + template + template + constexpr void + vector::assign_with_sentinel(Iterator first, Sentinel last) { + pointer cur = _begin; + for (; first != last && cur != _end; ++first, (void) ++cur) { + *cur = *first; + } + if (cur != _end) { + destruct_at_end(cur); + } else { + for (; first != last; ++first) { + emplace_back(*first); + } } + } - constexpr auto find(const T& value) const { - return std::find(begin(), end(), value); + template + template + constexpr void + vector::assign_with_size(Iterator first, Sentinel last, difference_type n) { + size_type new_size = static_cast(n); + if (new_size <= capacity()) { + if (new_size > size()) { +#if PLUGIFY_HAS_CXX23 + auto mid = std::ranges::copy_n(std::move(first), size(), this->_begin).in; + construct_at_end(std::move(mid), std::move(last), new_size - size()); +#else + Iterator mid = std::next(first, size()); + std::copy(first, mid, this->_begin); + construct_at_end(mid, last, new_size - size()); +#endif + } else { + pointer m = std::copy(std::move(first), last, this->_begin); + this->destruct_at_end(m); + } + } else { + vdeallocate(); + vallocate(recommend(new_size)); + construct_at_end(std::move(first), std::move(last), new_size); } + } - constexpr auto find(const T& value) { - return std::find(begin(), end(), value); + template + constexpr void + vector::assign(size_type n, const_reference u) { + if (n <= capacity()) { + size_type s = size(); + std::fill_n(this->_begin, std::min(n, s), u); + if (n > s) { + construct_at_end(n - s, u); + } else { + this->destruct_at_end(this->_begin + n); + } + } else { + vdeallocate(); + vallocate(recommend(static_cast(n))); + construct_at_end(n, u); } + } - template - constexpr auto find_if(F predicate) const { - return std::find_if(begin(), end(), predicate); + template + constexpr void vector::reserve(size_type n) { + if (n > capacity()) { + if (n > max_size()) { + this->throw_length_error(); + } + split_buffer v(n, size(), this->_alloc); + swap_out_circular_buffer(v); } + } - template - constexpr auto find_if(F predicate) { - return std::find_if(begin(), end(), predicate); + template + constexpr void vector::shrink_to_fit() noexcept { + if (capacity() > size()) { +#if PLUGIFY_HAS_EXCEPTIONS + try { +#endif // PLUGIFY_HAS_EXCEPTIONS + split_buffer v(size(), size(), this->_alloc); + // The Standard mandates shrink_to_fit() does not increase the capacity. + // With equal capacity keep the existing buffer. This avoids extra work + // due to swapping the elements. + if (v.capacity() < capacity()) { + swap_out_circular_buffer(v); + } +#if PLUGIFY_HAS_EXCEPTIONS + } catch (...) { + } +#endif // PLUGIFY_HAS_EXCEPTIONS } + } + + template + template + constexpr typename vector::pointer + vector::emplace_back_slow_path(Args&&... args) { + split_buffer v(recommend(size() + 1), size(), this->_alloc); + // v.emplace_back(std::forward(args)...); + pointer end = v.end(); + alloc_traits::construct(this->_alloc, std::to_address(end), std::forward(args)...); + v.set_sentinel(++end); + swap_out_circular_buffer(v); + return this->_end; + } - constexpr std::optional find_index(const T& value) { - const auto iter = std::find(begin(), end(), value); - if (iter == end()) { - return {}; + // This makes the compiler inline `else()` if `cond` is known to be false. Currently LLVM + // doesn't do that without the `builtin_constant_p`, since it considers `else` unlikely even + // through it's known to be run. See https://llvm.org/PR154292 + template + constexpr void + if_likely_else(bool cond, If _if, Else _else) { + if (__builtin_constant_p(cond)) { + if (cond) { + _if(); + } else { + _else(); + } + } else { + if (cond) [[likely]] { + _if(); } else { - return iter - begin(); + _else(); } } + } - constexpr std::optional find_index(const T& value) const { - const auto iter = std::find(begin(), end(), value); - if (iter == end()) { - return {}; - } else { - return iter - begin(); + template + template + constexpr inline + typename vector::reference + vector::emplace_back(Args&&... args) { + pointer end = this->_end; + if_likely_else( + end < this->_cap, + [&] { + emplace_back_assume_capacity(std::forward(args)...); + ++end; + }, + [&] { end = emplace_back_slow_path(std::forward(args)...); } + ); + + this->_end = end; + return *(end - 1); + } + + template + constexpr inline + typename vector::iterator + vector::erase(const_iterator position) { + PLUGIFY_ASSERT( + position != end(), + "vector::erase(iterator) called with a non-dereferenceable iterator" + ); + difference_type ps = position - cbegin(); + pointer p = this->_begin + ps; + this->destruct_at_end(std::move(p + 1, this->_end, p)); + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::erase(const_iterator first, const_iterator last) { + PLUGIFY_ASSERT( + first <= last, + "vector::erase(first, last) called with invalid range" + ); + pointer p = this->_begin + (first - begin()); + if (first != last) { + this->destruct_at_end(std::move(p + (last - first), this->_end, p)); + } + return make_iter(p); + } + + template + constexpr void + vector::move_range(pointer from_s, pointer from_e, pointer to) { + pointer old_last = this->_end; + difference_type n = old_last - to; + { + pointer i = from_s + n; + ConstructTransaction tx(*this, from_e - i); + for (pointer pos = tx.pos_; i < from_e; ++i, (void) ++pos, tx.pos_ = pos) { + alloc_traits::construct(this->_alloc, std::to_address(pos), std::move(*i)); } } + std::move_backward(from_s, from_s + n, old_last); + } - template - constexpr std::optional find_index_if(F predicate) { - const auto iter = std::find_if(begin(), end(), predicate); - if (iter == end()) { - return {}; + template + constexpr typename vector::iterator + vector::insert(const_iterator position, const_reference x) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(x); } else { - return iter - begin(); + move_range(p, this->_end, p + 1); + const_pointer xr = std::pointer_traits::pointer_to(x); + if (is_pointer_in_range( + std::to_address(p), + std::to_address(_end), + std::addressof(x) + )) { + ++xr; + } + *p = *xr; + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(x); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::insert(const_iterator position, value_type&& x) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(std::move(x)); + } else { + move_range(p, this->_end, p + 1); + *p = std::move(x); + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(std::move(x)); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + template + constexpr typename vector::iterator + vector::emplace(const_iterator position, Args&&... args) { + pointer p = this->_begin + (position - begin()); + if (this->_end < this->_cap) { + if (p == this->_end) { + emplace_back_assume_capacity(std::forward(args)...); + } else { + detail::temp_value tmp(this->_alloc, std::forward(args)...); + move_range(p, this->_end, p + 1); + *p = std::move(tmp.get()); + } + } else { + split_buffer v( + recommend(size() + 1), + p - this->_begin, + this->_alloc + ); + v.emplace_back(std::forward(args)...); + p = swap_out_circular_buffer(v, p); + } + return make_iter(p); + } + + template + constexpr typename vector::iterator + vector::insert(const_iterator position, size_type n, const_reference x) { + pointer p = this->_begin + (position - begin()); + if (n > 0) { + if (n <= static_cast(this->_cap - this->_end)) { + size_type old_n = n; + pointer old_last = this->_end; + if (n > static_cast(this->_end - p)) { + size_type cx = n - (this->_end - p); + construct_at_end(cx, x); + n -= cx; + } + if (n > 0) { + move_range(p, old_last, p + old_n); + const_pointer xr = std::pointer_traits::pointer_to(x); + if (is_pointer_in_range( + std::to_address(p), + std::to_address(_end), + std::addressof(x) + )) { + xr += old_n; + } + std::fill_n(p, n, *xr); + } + } else { + split_buffer v( + recommend(size() + n), + p - this->_begin, + this->_alloc + ); + v.construct_at_end(n, x); + p = swap_out_circular_buffer(v, p); } } + return make_iter(p); + } + + template + template + constexpr typename vector::iterator + vector::insert_with_sentinel( + const_iterator position, + InputIterator first, + Sentinel last + ) { + difference_type off = position - begin(); + pointer p = this->_begin + off; + pointer old_last = this->_end; + for (; this->_end != this->_cap && first != last; ++first) { + emplace_back_assume_capacity(*first); + } + + if (first == last) { + (void) std::rotate(p, old_last, this->_end); + } else { + split_buffer v(_alloc); + auto guard = make_exception_guard( + AllocatorDestroyRangeReverse(_alloc, old_last, this->_end) + ); + v.construct_at_end_with_sentinel(std::move(first), std::move(last)); + split_buffer merged( + recommend(size() + v.size()), + off, + _alloc + ); // has `off` positions available at the front + uninitialized_allocator_relocate( + _alloc, + std::to_address(old_last), + std::to_address(this->_end), + std::to_address(merged.end()) + ); + guard.complete(); // Release the guard once objects in [old_last_, _end) have been + // successfully relocated. + merged.set_sentinel(merged.end() + (this->_end - old_last)); + this->_end = old_last; + uninitialized_allocator_relocate( + _alloc, + std::to_address(v.begin()), + std::to_address(v.end()), + std::to_address(merged.end()) + ); + merged.set_sentinel(merged.size() + v.size()); + v.set_sentinel(v.begin()); + p = swap_out_circular_buffer(merged, p); + } + return make_iter(p); + } - template - constexpr std::optional find_index_if(F predicate) const { - const auto iter = std::find_if(begin(), end(), predicate); - if (iter == end()) { - return {}; + template + template + constexpr typename vector::iterator + vector::insert_with_size( + const_iterator position, + Iterator first, + Sentinel last, + difference_type n + ) { + pointer p = this->_begin + (position - begin()); + if (n > 0) { + if (n <= this->_cap - this->_end) { + pointer old_last = this->_end; + difference_type dx = this->_end - p; + if (n > dx) { +#if PLUGIFY_HAS_CXX23 + if constexpr (!std::forward_iterator) { + construct_at_end(std::move(first), std::move(last), n); + std::rotate(p, old_last, this->_end); + } else +#endif + { + Iterator m = std::next(first, dx); + construct_at_end(m, last, n - dx); + if (dx > 0) { + move_range(p, old_last, p + n); + insert_assign_n_unchecked(first, dx, p); + } + } + } else { + move_range(p, old_last, p + n); + insert_assign_n_unchecked(std::move(first), n, p); + } } else { - return iter - begin(); + split_buffer v( + recommend(size() + n), + p - this->_begin, + this->_alloc + ); + v.construct_at_end_with_size(std::move(first), n); + p = swap_out_circular_buffer(v, p); } } - }; + return make_iter(p); + } + + template + constexpr void vector::resize(size_type sz) { + size_type cs = size(); + if (cs < sz) { + this->append(sz - cs); + } else if (cs > sz) { + this->destruct_at_end(this->_begin + sz); + } + } + + template + constexpr void + vector::resize(size_type sz, const_reference x) { + size_type cs = size(); + if (cs < sz) { + this->append(sz - cs, x); + } else if (cs > sz) { + this->destruct_at_end(this->_begin + sz); + } + } + + template + constexpr void vector::swap(vector& x) + noexcept + { + PLUGIFY_ASSERT( + alloc_traits::propagate_on_container_swap::value || this->_alloc == x._alloc, + "vector::swap: Either propagate_on_container_swap must be true" + " or the allocators must compare equal" + ); + std::swap(this->_begin, x._begin); + std::swap(this->_end, x._end); + std::swap(this->_cap, x._cap); + swap_allocator(this->_alloc, x._alloc); + } + + template + constexpr bool vector::invariants() const { + if (this->_begin == nullptr) { + if (this->_end != nullptr || this->_cap != nullptr) { + return false; + } + } else { + if (this->_begin > this->_end) { + return false; + } + if (this->_begin == this->_cap) { + return false; + } + if (this->_end > this->_cap) { + return false; + } + } + return true; + } // comparisons template @@ -1046,7 +1552,7 @@ namespace plg { } template - constexpr typename vector::size_type erase(vector& c, const U& value) { + constexpr vector::size_type erase(vector& c, const U& value) { auto it = std::remove(c.begin(), c.end(), value); auto r = std::distance(it, c.end()); c.erase(it, c.end()); @@ -1054,20 +1560,15 @@ namespace plg { } template - constexpr typename vector::size_type erase_if(vector& c, Pred pred) { + constexpr vector::size_type erase_if(vector& c, Pred pred) { auto it = std::remove_if(c.begin(), c.end(), pred); auto r = std::distance(it, c.end()); c.erase(it, c.end()); return r; } - // deduction guides - template::value_type>> - vector(InputIterator, InputIterator, Allocator = Allocator()) -> vector::value_type, Allocator>; - namespace pmr { template using vector = ::plg::vector>; } // namespace pmr - } // namespace plg diff --git a/test/example_plugin/external/plugify/include/plg/version.hpp b/test/example_plugin/external/plugify/include/plg/version.hpp index 6089f12..b8e8c00 100644 --- a/test/example_plugin/external/plugify/include/plg/version.hpp +++ b/test/example_plugin/external/plugify/include/plg/version.hpp @@ -13,15 +13,15 @@ #include #endif -#ifndef PLUGIFY_VECTOR_NO_STD_FORMAT -#include "plg/format.hpp" -#endif - +#include "plg/config.hpp" #include "plg/hash.hpp" -#include "plg/macro.hpp" #include "plg/string.hpp" #include "plg/vector.hpp" +#ifndef PLUGIFY_VECTOR_NO_STD_FORMAT +#include "plg/format.hpp" +#endif + // from https://github.com/Neargye/semver namespace plg { namespace detail { @@ -70,7 +70,7 @@ namespace plg { class version_parser; class prerelease_comparator; - } + } // namespace detail template class version { @@ -78,6 +78,11 @@ namespace plg { friend class detail::prerelease_comparator; public: + using trivially_relocatable = std::conditional_t< + is_trivially_relocatable::value && + is_trivially_relocatable::value && + is_trivially_relocatable::value, version, void>; + constexpr version() = default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase constexpr version(const version&) = default; constexpr version(version&&) = default; @@ -86,38 +91,38 @@ namespace plg { constexpr version& operator=(const version&) = default; constexpr version& operator=(version&&) = default; - constexpr I1 major() const noexcept { return major_; } - constexpr I2 minor() const noexcept { return minor_; } - constexpr I3 patch() const noexcept { return patch_; } + constexpr I1 major() const noexcept { return _major; } + constexpr I2 minor() const noexcept { return _minor; } + constexpr I3 patch() const noexcept { return _patch; } - constexpr const string& prerelease_tag() const { return prerelease_tag_; } - constexpr const string& build_metadata() const { return build_metadata_; } + constexpr const string& prerelease_tag() const { return _prerelease_tag; } + constexpr const string& build_metadata() const { return _build_metadata; } constexpr string to_string() const; private: - I1 major_ = 0; - I2 minor_ = 1; - I3 patch_ = 0; - string prerelease_tag_; - string build_metadata_; + I1 _major = 0; + I2 _minor = 1; + I3 _patch = 0; + string _prerelease_tag; + string _build_metadata; - vector prerelease_identifiers; + vector _prerelease_identifiers; constexpr std::size_t length() const noexcept { - return detail::length(major_) + detail::length(minor_) + detail::length(patch_) + 2 - + (prerelease_tag_.empty() ? 0 : prerelease_tag_.length() + 1) - + (build_metadata_.empty() ? 0 : build_metadata_.length() + 1); + return detail::length(_major) + detail::length(_minor) + detail::length(_patch) + 2 + + (_prerelease_tag.empty() ? 0 : _prerelease_tag.length() + 1) + + (_build_metadata.empty() ? 0 : _build_metadata.length() + 1); } constexpr void clear() noexcept { - major_ = 0; - minor_ = 1; - patch_ = 0; + _major = 0; + _minor = 1; + _patch = 0; - prerelease_tag_.clear(); - prerelease_identifiers.clear(); - build_metadata_.clear(); + _prerelease_tag.clear(); + _prerelease_identifiers.clear(); + _build_metadata.clear(); } }; @@ -126,24 +131,24 @@ namespace plg { string result; detail::resize_uninitialized{}.resize(result, length()); - auto it = result.end(); - if (!build_metadata_.empty()) { - it = std::copy_backward(build_metadata_.begin(), build_metadata_.end(), it); + auto* it = result.end(); + if (!_build_metadata.empty()) { + it = std::copy_backward(_build_metadata.begin(), _build_metadata.end(), it); *(--it) = '+'; } - if (!prerelease_tag_.empty()) { - it = std::copy_backward(prerelease_tag_.begin(), prerelease_tag_.end(), it); + if (!_prerelease_tag.empty()) { + it = std::copy_backward(_prerelease_tag.begin(), _prerelease_tag.end(), it); *(--it) = '-'; } - it = detail::to_chars(it, patch_); + it = detail::to_chars(it, _patch); *(--it) = '.'; - it = detail::to_chars(it, minor_); + it = detail::to_chars(it, _minor); *(--it) = '.'; - it = detail::to_chars(it, major_); + it = detail::to_chars(it, _major); return result; } @@ -160,7 +165,7 @@ namespace plg { [[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; } }; #endif - + enum class version_compare_option : std::uint8_t { exclude_prerelease, include_prerelease @@ -192,25 +197,22 @@ namespace plg { } template - constexpr bool cmp_less(T t, U u) noexcept - { + constexpr bool cmp_less(T t, U u) noexcept { if constexpr (std::is_signed_v == std::is_signed_v) - return t < u; - else if constexpr (std::is_signed_v) - return t < 0 || std::make_unsigned_t(t) < u; - else - return u >= 0 && t < std::make_unsigned_t(u); -} + return t < u; + else if constexpr (std::is_signed_v) + return t < 0 || std::make_unsigned_t(t) < u; + else + return u >= 0 && t < std::make_unsigned_t(u); + } template - constexpr bool cmp_less_equal(T t, U u) noexcept - { + constexpr bool cmp_less_equal(T t, U u) noexcept { return !cmp_less(u, t); } template - constexpr bool cmp_greater_equal(T t, U u) noexcept - { + constexpr bool cmp_greater_equal(T t, U u) noexcept { return !cmp_less(t, u); } @@ -220,28 +222,7 @@ namespace plg { } constexpr int compare(std::string_view lhs, std::string_view rhs) { -#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) - // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html - // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html - constexpr bool workaround = true; -#else - constexpr bool workaround = false; -#endif - - if constexpr (workaround) { - const auto size = std::min(lhs.size(), rhs.size()); - for (std::size_t i = 0; i < size; ++i) { - if (lhs[i] < rhs[i]) { - return -1; - } else if (lhs[i] > rhs[i]) { - return 1; - } - } - - return static_cast(lhs.size() - rhs.size()); - } else { - return lhs.compare(rhs); - } + return lhs.compare(rhs); } constexpr int compare_numerically(std::string_view lhs, std::string_view rhs) { @@ -292,28 +273,28 @@ namespace plg { class token_stream { public: constexpr token_stream() = default; - constexpr explicit token_stream(vector tokens) noexcept : tokens_(std::move(tokens)) {} + constexpr explicit token_stream(vector tokens) noexcept : _tokens(std::move(tokens)) {} constexpr void push(const token& token) noexcept { - tokens_.push_back(token); + _tokens.push_back(token); } constexpr token advance() noexcept { - const token token = get(current_); - ++current_; + const token token = get(_current); + ++_current; return token; } constexpr token peek(std::size_t k = 0) const noexcept { - return get(current_ + k); + return get(_current + k); } constexpr token previous() const noexcept { - return get(current_ - 1); + return get(_current - 1); } - constexpr bool advanceIfMatch(token& token, token_type type) noexcept { - if (get(current_).type != type) { + constexpr bool advance_if_match(token& token, token_type type) noexcept { + if (get(_current).type != type) { return false; } @@ -321,9 +302,9 @@ namespace plg { return true; } - constexpr bool advanceIfMatch(token_type type) noexcept { + constexpr bool advance_if_match(token_type type) noexcept { token token; - return advanceIfMatch(token, type); + return advance_if_match(token, type); } constexpr bool consume(token_type type) noexcept { @@ -335,20 +316,20 @@ namespace plg { } private: - std::size_t current_ = 0; - vector tokens_; + std::size_t _current = 0; + vector _tokens; constexpr token get(std::size_t i) const noexcept { - return tokens_[i]; + return _tokens[i]; } }; class lexer { public: - explicit constexpr lexer(std::string_view text) noexcept : text_{text}, current_pos_{0} {} + explicit constexpr lexer(std::string_view text) noexcept : _text{text}, _current_pos{0} {} constexpr from_chars_result scan_tokens(token_stream& token_stream) noexcept { - from_chars_result result{ text_.data(), std::errc{} }; + from_chars_result result{ _text.data(), std::errc{} }; while (!is_eol()) { result = scan_token(token_stream); @@ -357,14 +338,14 @@ namespace plg { } } - token_stream.push({ token_type::eol, {}, text_.data() + text_.size() }); + token_stream.push({ token_type::eol, {}, _text.data() + _text.size() }); return result; } private: - std::string_view text_; - std::size_t current_pos_; + std::string_view _text; + std::size_t _current_pos; constexpr from_chars_result scan_token(token_stream& stream) noexcept { const char c = advance(); @@ -383,16 +364,16 @@ namespace plg { add_token(stream, token_type::plus); break; case '|': - if (advanceIfMatch('|')) { + if (advance_if_match('|')) { add_token(stream, token_type::logical_or); break; } return failure(get_prev_symbol()); case '<': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::less_or_equal : range_operator::less); + add_token(stream, token_type::range_operator, advance_if_match('=') ? range_operator::less_or_equal : range_operator::less); break; case '>': - add_token(stream, token_type::range_operator, advanceIfMatch('=') ? range_operator::greater_or_equal : range_operator::greater); + add_token(stream, token_type::range_operator, advance_if_match('=') ? range_operator::greater_or_equal : range_operator::greater); break; case '=': add_token(stream, token_type::range_operator, range_operator::equal); @@ -417,51 +398,51 @@ namespace plg { stream.push({ type, value, lexeme}); } - constexpr char advance() noexcept { - char c = text_[current_pos_]; - current_pos_ += 1; + constexpr char advance() noexcept { + char c = _text[_current_pos]; + _current_pos += 1; return c; } - constexpr bool advanceIfMatch(char c) noexcept { + constexpr bool advance_if_match(char c) noexcept { if (is_eol()) { return false; } - if (text_[current_pos_] != c) { + if (_text[_current_pos] != c) { return false; } - current_pos_ += 1; + _current_pos += 1; return true; } constexpr const char* get_prev_symbol() const noexcept { - return text_.data() + current_pos_ - 1; + return _text.data() + _current_pos - 1; } - constexpr bool is_eol() const noexcept { return current_pos_ >= text_.size(); } + constexpr bool is_eol() const noexcept { return _current_pos >= _text.size(); } }; class prerelease_comparator { public: template [[nodiscard]] constexpr int compare(const version& lhs, const version& rhs) const noexcept { - if (lhs.prerelease_identifiers.empty() != rhs.prerelease_identifiers.empty()) { - return static_cast(rhs.prerelease_identifiers.size()) - static_cast(lhs.prerelease_identifiers.size()); + if (lhs._prerelease_identifiers.empty() != rhs._prerelease_identifiers.empty()) { + return static_cast(rhs._prerelease_identifiers.size()) - static_cast(lhs._prerelease_identifiers.size()); } - const std::size_t count = std::min(lhs.prerelease_identifiers.size(), rhs.prerelease_identifiers.size()); + const std::size_t count = std::min(lhs._prerelease_identifiers.size(), rhs._prerelease_identifiers.size()); for (std::size_t i = 0; i < count; ++i) { - const int compare_result = compare_identifier(lhs.prerelease_identifiers[i], rhs.prerelease_identifiers[i]); + const int compare_result = compare_identifier(lhs._prerelease_identifiers[i], rhs._prerelease_identifiers[i]); if (compare_result != 0) { return compare_result; } } - return static_cast(lhs.prerelease_identifiers.size()) - static_cast(rhs.prerelease_identifiers.size()); + return static_cast(lhs._prerelease_identifiers.size()) - static_cast(rhs._prerelease_identifiers.size()); } private: @@ -478,45 +459,45 @@ namespace plg { class version_parser { public: - constexpr explicit version_parser(token_stream& stream) : stream_{stream} { + constexpr explicit version_parser(token_stream& stream) : _stream{stream} { } template constexpr from_chars_result parse(version& out) noexcept { out.clear(); - from_chars_result result = parse_number(out.major_); + from_chars_result result = parse_number(out._major); if (!result) { return result; } - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); + if (!_stream.consume(token_type::dot)) { + return failure(_stream.previous().lexeme); } - result = parse_number(out.minor_); + result = parse_number(out._minor); if (!result) { return result; } - if (!stream_.consume(token_type::dot)) { - return failure(stream_.previous().lexeme); + if (!_stream.consume(token_type::dot)) { + return failure(_stream.previous().lexeme); } - result = parse_number(out.patch_); + result = parse_number(out._patch); if (!result) { return result; } - if (stream_.advanceIfMatch(token_type::hyphen)) { - result = parse_prerelease_tag(out.prerelease_tag_, out.prerelease_identifiers); + if (_stream.advance_if_match(token_type::hyphen)) { + result = parse_prerelease_tag(out._prerelease_tag, out._prerelease_identifiers); if (!result) { return result; } } - if (stream_.advanceIfMatch(token_type::plus)) { - result = parse_build_metadata(out.build_metadata_); + if (_stream.advance_if_match(token_type::plus)) { + result = parse_build_metadata(out._build_metadata); if (!result) { return result; } @@ -527,11 +508,11 @@ namespace plg { private: - token_stream& stream_; + token_stream& _stream; template constexpr from_chars_result parse_number(Int& out) { - token token = stream_.advance(); + token token = _stream.advance(); if (!is_digit(token)) { return failure(token.lexeme); @@ -542,16 +523,16 @@ namespace plg { if (first_digit == 0) { out = static_cast(result); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } - while (stream_.advanceIfMatch(token, token_type::digit)) { + while (_stream.advance_if_match(token, token_type::digit)) { result = result * 10 + std::get(token.value); } if (detail::number_in_range(result)) { out = static_cast(result); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } return failure(token.lexeme, std::errc::result_out_of_range); @@ -573,10 +554,10 @@ namespace plg { result.append(identifier); out_identifiers.push_back(make_prerelease_identifier(identifier)); - } while (stream_.advanceIfMatch(token_type::dot)); + } while (_stream.advance_if_match(token_type::dot)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr from_chars_result parse_build_metadata(string& out) { @@ -593,15 +574,15 @@ namespace plg { } result.append(identifier); - } while (stream_.advanceIfMatch(token_type::dot)); + } while (_stream.advance_if_match(token_type::dot)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr from_chars_result parse_prerelease_identifier(string& out) { string result; - token token = stream_.advance(); + token token = _stream.advance(); do { switch (token.type) { @@ -615,7 +596,7 @@ namespace plg { { const auto digit = std::get(token.value); - // numerical prerelease identifier doesn't allow leading zero + // numerical prerelease identifier doesn't allow leading zero // 1.2.3-1.alpha is valid, // 1.2.3-01b is valid as well, but // 1.2.3-01.alpha is not valid @@ -632,10 +613,10 @@ namespace plg { default: return failure(token.lexeme); } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + } while (_stream.advance_if_match(token, token_type::hyphen) || _stream.advance_if_match(token, token_type::letter) || _stream.advance_if_match(token, token_type::digit)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr detail::prerelease_identifier make_prerelease_identifier(const string& identifier) { @@ -651,7 +632,7 @@ namespace plg { constexpr from_chars_result parse_build_identifier(string& out) { string result; - token token = stream_.advance(); + token token = _stream.advance(); do { switch (token.type) { @@ -670,10 +651,10 @@ namespace plg { default: return failure(token.lexeme); } - } while (stream_.advanceIfMatch(token, token_type::hyphen) || stream_.advanceIfMatch(token, token_type::letter) || stream_.advanceIfMatch(token, token_type::digit)); + } while (_stream.advance_if_match(token, token_type::hyphen) || _stream.advance_if_match(token, token_type::letter) || _stream.advance_if_match(token, token_type::digit)); out = result; - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr bool is_leading_zero(int digit) noexcept { @@ -686,7 +667,7 @@ namespace plg { int digits = 0; while (true) { - const token token = stream_.peek(k); + const token token = _stream.peek(k); if (!is_alphanumeric(token)) { break; @@ -766,7 +747,7 @@ namespace plg { return success(token_stream.previous().lexeme); } - } // namespace semver::detail + } // namespace detail template [[nodiscard]] constexpr bool operator==(const version& lhs, const version& rhs) noexcept { @@ -798,17 +779,15 @@ namespace plg { return detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease) <= 0; } -#if __cpp_impl_three_way_comparison >= 201907L template [[nodiscard]] constexpr std::strong_ordering operator<=>(const version& lhs, const version& rhs) { int compare = detail::compare_parsed(lhs, rhs, version_compare_option::include_prerelease); if (compare == 0) - return std::strong_ordering::equal; - if (compare > 0) - return std::strong_ordering::greater; - return std::strong_ordering::less; + return std::strong_ordering::equal; + if (compare > 0) + return std::strong_ordering::greater; + return std::strong_ordering::less; } -#endif template constexpr from_chars_result parse(std::string_view str, version& output) { @@ -824,44 +803,44 @@ namespace plg { template class range_comparator { public: - constexpr range_comparator(const version& v, range_operator op) noexcept : v_(v), op_(op) {} + constexpr range_comparator(const version& v, range_operator op) noexcept : _v(v), _op(op) {} constexpr bool contains(const version& other) const noexcept { - switch (op_) { + switch (_op) { case range_operator::less: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) < 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) < 0; case range_operator::less_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) <= 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) <= 0; case range_operator::greater: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) > 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) > 0; case range_operator::greater_or_equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) >= 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) >= 0; case range_operator::equal: - return detail::compare_parsed(other, v_, version_compare_option::include_prerelease) == 0; + return detail::compare_parsed(other, _v, version_compare_option::include_prerelease) == 0; } return false; } - constexpr const version& get_version() const noexcept { return v_; } + constexpr const version& get_version() const noexcept { return _v; } - constexpr range_operator get_operator() const noexcept { return op_; } + constexpr range_operator get_operator() const noexcept { return _op; } constexpr string to_string() const { string result; - switch (op_) { + switch (_op) { case range_operator::less: result += "<"; break; case range_operator::less_or_equal: result += "<="; break; case range_operator::greater: result += ">"; break; case range_operator::greater_or_equal: result += ">="; break; case range_operator::equal: result += "="; break; } - result += v_.to_string(); + result += _v.to_string(); return result; } private: - version v_; - range_operator op_; + version _v; + range_operator _op; }; class range_parser; @@ -878,40 +857,40 @@ namespace plg { } } - return std::all_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + return std::all_of(_ranges_comparators.begin(), _ranges_comparators.end(), [&](const auto& ranges_comparator) { return ranges_comparator.contains(v); }); } constexpr auto begin() const noexcept { - return ranges_comparators_.begin(); + return _ranges_comparators.begin(); } constexpr auto end() const noexcept { - return ranges_comparators_.end(); + return _ranges_comparators.end(); } constexpr std::size_t size() const noexcept { - return ranges_comparators_.size(); + return _ranges_comparators.size(); } constexpr bool empty() const noexcept { - return ranges_comparators_.empty(); + return _ranges_comparators.empty(); } constexpr string to_string() const { - return join(ranges_comparators_, " "); + return join(_ranges_comparators, " "); } private: - vector> ranges_comparators_; + vector> _ranges_comparators; constexpr bool match_at_least_one_comparator_with_prerelease(const version& v) const noexcept { if (v.prerelease_tag().empty()) { return true; } - return std::any_of(ranges_comparators_.begin(), ranges_comparators_.end(), [&](const auto& ranges_comparator) { + return std::any_of(_ranges_comparators.begin(), _ranges_comparators.end(), [&](const auto& ranges_comparator) { const bool has_prerelease = !ranges_comparator.get_version().prerelease_tag().empty(); const bool equal_without_prerelease = detail::compare_parsed(v, ranges_comparator.get_version(), version_compare_option::exclude_prerelease) == 0; return has_prerelease && equal_without_prerelease; @@ -926,39 +905,39 @@ namespace plg { friend class detail::range_parser; constexpr bool contains(const version& v, version_compare_option option = version_compare_option::exclude_prerelease) const noexcept { - return std::any_of(ranges_.begin(), ranges_.end(), [&](const auto& range) { + return std::any_of(_ranges.begin(), _ranges.end(), [&](const auto& range) { return range.contains(v, option); }); } constexpr auto begin() const noexcept { - return ranges_.begin(); + return _ranges.begin(); } constexpr auto end() const noexcept { - return ranges_.end(); + return _ranges.end(); } constexpr std::size_t size() const noexcept { - return ranges_.size(); + return _ranges.size(); } constexpr bool empty() const noexcept { - return ranges_.empty(); + return _ranges.empty(); } constexpr string to_string() const { - return join(ranges_, " "); + return join(_ranges, " "); } private: - vector> ranges_; + vector> _ranges; }; namespace detail { class range_parser { public: - constexpr explicit range_parser(token_stream stream) noexcept : stream_(std::move(stream)) {} + constexpr explicit range_parser(token_stream stream) noexcept : _stream(std::move(stream)) {} template constexpr from_chars_result parse(range_set& out) noexcept { @@ -974,59 +953,59 @@ namespace plg { ranges.push_back(range); skip_whitespaces(); - } while (stream_.advanceIfMatch(token_type::logical_or)); + } while (_stream.advance_if_match(token_type::logical_or)); - out.ranges_ = std::move(ranges); + out._ranges = std::move(ranges); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } - + private: - token_stream stream_; + token_stream _stream; template constexpr from_chars_result parse_range(detail::range& out) noexcept { do { skip_whitespaces(); - if (const auto res = parse_range_comparator(out.ranges_comparators_); !res) { + if (const auto res = parse_range_comparator(out._ranges_comparators); !res) { return res; } skip_whitespaces(); - } while (stream_.check(token_type::range_operator) || stream_.check(token_type::digit)); - - return success(stream_.peek().lexeme); + } while (_stream.check(token_type::range_operator) || _stream.check(token_type::digit)); + + return success(_stream.peek().lexeme); } template constexpr from_chars_result parse_range_comparator(vector>& out) noexcept { range_operator op = range_operator::equal; token token; - if (stream_.advanceIfMatch(token, token_type::range_operator)) { + if (_stream.advance_if_match(token, token_type::range_operator)) { op = std::get(token.value); } skip_whitespaces(); version ver; - version_parser parser{ stream_ }; + version_parser parser{ _stream }; if (const auto res = parser.parse(ver); !res) { return res; } out.emplace_back(ver, op); - return success(stream_.peek().lexeme); + return success(_stream.peek().lexeme); } constexpr void skip_whitespaces() noexcept { - while (stream_.advanceIfMatch(token_type::space)) { + while (_stream.advance_if_match(token_type::space)) { ; } } }; - } // namespace semver::detail + } // namespace detail template @@ -1039,7 +1018,7 @@ namespace plg { return detail::range_parser{ std::move(token_stream) }.parse(out); } -} // namespace semver +} // namespace plg #ifndef PLUGIFY_VECTOR_NO_STD_HASH // hash support From 91c49ebffcd42bdb7a329314b39535d28294e22c Mon Sep 17 00:00:00 2001 From: qubka Date: Sat, 27 Sep 2025 13:44:24 +0100 Subject: [PATCH 09/10] fix: add mac build --- .github/workflows/cmake-multiple-platform.yml | 36 ++++++++++++++--- conda/build.sh | 16 ++++++-- conda/meta.yaml.example | 39 ++++++++++++++----- 3 files changed, 72 insertions(+), 19 deletions(-) diff --git a/.github/workflows/cmake-multiple-platform.yml b/.github/workflows/cmake-multiple-platform.yml index 891f436..7526e0a 100644 --- a/.github/workflows/cmake-multiple-platform.yml +++ b/.github/workflows/cmake-multiple-platform.yml @@ -64,6 +64,11 @@ jobs: arch: x86_64 container: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest setup_env: gcc14 + - os: macos-latest + platform: osx-arm64 + arch: arm64 + container: null + setup_env: clang runs-on: ${{ matrix.os }} container: ${{ matrix.container }} steps: @@ -88,8 +93,18 @@ jobs: ln -sf /usr/bin/gcc-14 /usr/bin/gcc && ln -sf /usr/bin/g++-14 /usr/bin/g++ # for ACT add nodejs + # macOS-specific setup + - name: Setup macOS build environment + if: matrix.setup_env == 'clang' + shell: bash -el {0} + run: | + # Install ninja via homebrew if not present + brew list ninja &>/dev/null || brew install ninja + # Ensure we're using the ARM64 architecture + echo "CMAKE_OSX_ARCHITECTURES=arm64" >> $GITHUB_ENV + - name: Setup CMake - if: matrix.setup_env == 'msvc' + if: matrix.setup_env == 'msvc' || matrix.setup_env == 'clang' uses: lukka/get-cmake@latest - name: Cache build dependencies @@ -107,7 +122,11 @@ jobs: - name: Configure shell: bash -el {0} run: | - cmake -S . -B build -G "Ninja" -DCPPLM_VERSION="${{ needs.setup.outputs.tag_name }}" + CMAKE_ARGS="" + if [[ "${{ matrix.setup_env }}" == "clang" ]]; then + CMAKE_ARGS="-DCMAKE_OSX_ARCHITECTURES=arm64" + fi + cmake -S . -B build -G "Ninja" -DCPPLM_VERSION="${{ needs.setup.outputs.tag_name }}" $CMAKE_ARGS - name: Build shell: bash -el {0} @@ -138,6 +157,8 @@ jobs: platform: win-64 - os: ubuntu-latest platform: linux-64 + - os: macos-latest + platform: osx-arm64 runs-on: ${{ matrix.os }} outputs: url: ${{ steps.release.outputs.url }} @@ -178,8 +199,8 @@ jobs: version="${version#v}" # Remove leading 'v' sed "s/REPLACE_VERSION/$version/g" "conda/meta.yaml.example" > "conda/meta.yaml" - # Ensure build.sh is executable on Linux - if [[ "$RUNNER_OS" == "Linux" ]]; then + # Ensure build.sh is executable on Unix systems + if [[ "$RUNNER_OS" == "Linux" ]] || [[ "$RUNNER_OS" == "macOS" ]]; then chmod +x "conda/build.sh" fi @@ -259,7 +280,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mkdir -p build/repo/{linux-64,win-64,noarch} + mkdir -p build/repo/{linux-64,win-64,osx-arm64,noarch} gh api /repos/${{ github.repository }}/releases?per_page=10 \ | jq -r '.[] | .assets[] | .browser_download_url' \ | grep -E "(\.tar\.bz2|\.conda)$" > urls.txt @@ -267,10 +288,12 @@ jobs: # separate by platform grep linux-64 urls.txt > linux.txt || true grep win-64 urls.txt > win.txt || true - grep -v -E "(linux-64|win-64)" urls.txt > noarch.txt || true + grep osx-arm64 urls.txt > osx.txt || true + grep -v -E "(linux-64|win-64|osx-arm64)" urls.txt > noarch.txt || true [ -s linux.txt ] && aria2c -x4 -s4 -j4 -i linux.txt -d build/repo/linux-64/ --continue [ -s win.txt ] && aria2c -x4 -s4 -j4 -i win.txt -d build/repo/win-64/ --continue + [ -s osx.txt ] && aria2c -x4 -s4 -j4 -i osx.txt -d build/repo/osx-arm64/ --continue [ -s noarch.txt ]&& aria2c -x4 -s4 -j4 -i noarch.txt -d build/repo/noarch/ --continue - name: Download conda packages @@ -347,6 +370,7 @@ jobs: diff --git a/conda/build.sh b/conda/build.sh index 7741d14..050a7eb 100644 --- a/conda/build.sh +++ b/conda/build.sh @@ -1,18 +1,28 @@ #!/bin/bash -# build.sh - For Linux builds +# build.sh - For Unix builds set -ex +# Detect the platform and set the appropriate library extension +if [[ "$OSTYPE" == "darwin"* ]]; then + LIB_EXT="dylib" +elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + LIB_EXT="so" +else + echo "Unsupported platform: $OSTYPE" + exit 1 +fi + # Create the target directories mkdir -p $PREFIX/bin mkdir -p $PREFIX # Copy the shared library and module file -cp bin/libplugify-module-cpp.so $PREFIX/bin/ +cp bin/libplugify-module-cpp.$LIB_EXT $PREFIX/bin/ cp plugify-module-cpp.pmodule $PREFIX/ # Set proper permissions -chmod 755 $PREFIX/bin/libplugify-module-cpp.so +chmod 755 $PREFIX/bin/libplugify-module-cpp.$LIB_EXT chmod 644 $PREFIX/plugify-module-cpp.pmodule # Create activation scripts for proper library path diff --git a/conda/meta.yaml.example b/conda/meta.yaml.example index ab9da91..0a86e4f 100644 --- a/conda/meta.yaml.example +++ b/conda/meta.yaml.example @@ -12,23 +12,42 @@ build: number: 0 string: "{{ target_platform | replace('-', '_') }}" missing_dso_whitelist: - - "*/ld-linux*.so.*" # [linux] - - "*/libc.so.*" # [linux] - - "*/libm.so.*" # [linux] - - "*/libdl.so.*" # [linux] - - "*/libpthread.so.*" # [linux] - - "*/librt.so.*" # [linux] - - "*/libplugify.so*" # [linux] - - "*/plugify.dll" # [win] + # Linux system libraries + - "*/ld-linux*.so.*" # [linux] + - "*/libc.so.*" # [linux] + - "*/libm.so.*" # [linux] + - "*/libdl.so.*" # [linux] + - "*/libpthread.so.*" # [linux] + - "*/librt.so.*" # [linux] + - "*/libplugify.so*" # [linux] + # macOS system libraries and frameworks + - "/usr/lib/libc++.1.dylib" # [osx] + - "/usr/lib/libSystem.B.dylib" # [osx] + - "/usr/lib/libc++abi.dylib" # [osx] + - "/usr/lib/libutil.dylib" # [osx] + - "/System/Library/Frameworks/*" # [osx] + - "*/libplugify.dylib" # [osx] + - "*/libplugify.*.dylib" # [osx] + - "@rpath/libplugify.dylib" # [osx] + - "@loader_path/libplugify.dylib" # [osx] + # Windows libraries + - "*/plugify.dll" # [win] requirements: run: - - __glibc >=2.17 # [linux64] + - __glibc >=2.17 # [linux64] + - __osx >=11.0 # [osx and arm64] test: commands: + # Linux tests - test -f $PREFIX/bin/libplugify-module-cpp.so # [linux] - test -f $PREFIX/plugify-module-cpp.pmodule # [linux] + # macOS tests + - test -f $PREFIX/bin/libplugify-module-cpp.dylib # [osx] + - test -f $PREFIX/plugify-module-cpp.pmodule # [osx] + - otool -L $PREFIX/bin/libplugify-module-cpp.dylib # [osx] + # Windows tests - if not exist %PREFIX%\\bin\\plugify-module-cpp.dll exit 1 # [win] - if not exist %PREFIX%\\plugify-module-cpp.pmodule exit 1 # [win] @@ -46,4 +65,4 @@ about: extra: recipe-maintainers: - - {{ environ.get('GITHUB_ACTOR', 'your-username') }} + - {{ environ.get('GITHUB_ACTOR', 'your-username') }} \ No newline at end of file From 79ebafb47e21d73a931d36dba4fe1f4e2f0ad953 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 27 Sep 2025 12:44:39 +0000 Subject: [PATCH 10/10] chore(main): release 2.1.0 --- .github/release-please-manifest.json | 2 +- CHANGELOG.md | 17 +++++++++++++++++ version.txt | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/release-please-manifest.json b/.github/release-please-manifest.json index c7734e9..969d3db 100644 --- a/.github/release-please-manifest.json +++ b/.github/release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.0.18" + ".": "2.1.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 77ad19a..3f60c7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [2.1.0](https://github.com/untrustedmodders/plugify-module-cpp/compare/v2.0.18...v2.1.0) (2025-09-27) + + +### Features + +* update for a new plugify ([ef75a18](https://github.com/untrustedmodders/plugify-module-cpp/commit/ef75a180f2c6015b7660acf40a07e9decd91fbce)) + + +### Bug Fixes + +* add mac build ([91c49eb](https://github.com/untrustedmodders/plugify-module-cpp/commit/91c49ebffcd42bdb7a329314b39535d28294e22c)) +* replace static by reinterpret cast ([3e3dbbc](https://github.com/untrustedmodders/plugify-module-cpp/commit/3e3dbbc62f8fb12b499d47ea19dae43702e9f137)) +* update clang format ([eb1a580](https://github.com/untrustedmodders/plugify-module-cpp/commit/eb1a5801d94a94431fda88783f5b125a3bbb52e5)) +* update deps ([dd3746f](https://github.com/untrustedmodders/plugify-module-cpp/commit/dd3746fce37aae3baf8c56bf614d4cb6240507d9)) +* update plugify ([adde663](https://github.com/untrustedmodders/plugify-module-cpp/commit/adde6637aa24f43e6ee3644be413e7a105c9530d)) +* update string hasher ([23fce3e](https://github.com/untrustedmodders/plugify-module-cpp/commit/23fce3eb3793e967bf225334219f30ac36cfa7e4)) + ## [2.0.18](https://github.com/untrustedmodders/plugify-module-cpp/compare/v2.0.17...v2.0.18) (2025-09-10) diff --git a/version.txt b/version.txt index c945ef1..7ec1d6d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.18 +2.1.0