├── .clang-format ├── .clang-tidy ├── .clangd ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── build.yml │ └── release.yml ├── LICENSE ├── README.md ├── manifest.json ├── scripts └── after_build.lua ├── src ├── MemoryOperators.cpp ├── Plugin.cpp ├── Plugin.h └── nonstd │ └── expected.hpp └── xmake.lua /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | AccessModifierOffset: -4 3 | AlignAfterOpenBracket: BlockIndent 4 | AlignArrayOfStructures: Left 5 | AlignConsecutiveDeclarations: 6 | Enabled: true 7 | AcrossEmptyLines: false 8 | AcrossComments: false 9 | AlignConsecutiveAssignments: 10 | Enabled: true 11 | AcrossEmptyLines: false 12 | AcrossComments: false 13 | AlignCompound: true 14 | PadOperators: true 15 | AlignConsecutiveMacros: 16 | Enabled: true 17 | AcrossEmptyLines: false 18 | AcrossComments: false 19 | AllowAllParametersOfDeclarationOnNextLine: false 20 | AllowAllArgumentsOnNextLine: false 21 | AlignOperands: AlignAfterOperator 22 | AlignConsecutiveBitFields: 23 | Enabled: true 24 | AcrossEmptyLines: false 25 | AcrossComments: false 26 | AllowShortLambdasOnASingleLine: All 27 | AllowShortBlocksOnASingleLine: Empty 28 | AllowShortIfStatementsOnASingleLine: AllIfsAndElse 29 | AllowShortLoopsOnASingleLine: true 30 | AlwaysBreakAfterDefinitionReturnType: None 31 | AlwaysBreakTemplateDeclarations: 'Yes' 32 | BinPackArguments: false 33 | BinPackParameters: false 34 | BreakBeforeBraces: Custom 35 | BreakBeforeBinaryOperators: NonAssignment 36 | ColumnLimit: 120 37 | CommentPragmas: '^ IWYU pragma:' 38 | ConstructorInitializerIndentWidth: 0 39 | IndentWidth: 4 40 | Language: Cpp 41 | MaxEmptyLinesToKeep: 2 42 | PackConstructorInitializers: CurrentLine 43 | PointerAlignment: Left 44 | TabWidth: 4 45 | UseTab: Never 46 | SortIncludes: CaseSensitive 47 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | # Generated from CLion Inspection settings 2 | --- 3 | Checks: '-*, 4 | bugprone-argument-comment, 5 | bugprone-assert-side-effect, 6 | bugprone-bad-signal-to-kill-thread, 7 | bugprone-branch-clone, 8 | bugprone-copy-constructor-init, 9 | bugprone-dangling-handle, 10 | bugprone-dynamic-static-initializers, 11 | bugprone-fold-init-type, 12 | bugprone-forward-declaration-namespace, 13 | bugprone-forwarding-reference-overload, 14 | bugprone-inaccurate-erase, 15 | bugprone-incorrect-roundings, 16 | bugprone-integer-division, 17 | bugprone-lambda-function-name, 18 | bugprone-macro-parentheses, 19 | bugprone-macro-repeated-side-effects, 20 | bugprone-misplaced-operator-in-strlen-in-alloc, 21 | bugprone-misplaced-pointer-arithmetic-in-alloc, 22 | bugprone-misplaced-widening-cast, 23 | bugprone-move-forwarding-reference, 24 | bugprone-multiple-statement-macro, 25 | bugprone-no-escape, 26 | bugprone-not-null-terminated-result, 27 | bugprone-parent-virtual-call, 28 | bugprone-posix-return, 29 | bugprone-reserved-identifier, 30 | bugprone-sizeof-container, 31 | bugprone-sizeof-expression, 32 | bugprone-spuriously-wake-up-functions, 33 | bugprone-string-constructor, 34 | bugprone-string-integer-assignment, 35 | bugprone-string-literal-with-embedded-nul, 36 | bugprone-suspicious-enum-usage, 37 | bugprone-suspicious-include, 38 | bugprone-suspicious-memory-comparison, 39 | bugprone-suspicious-memset-usage, 40 | bugprone-suspicious-missing-comma, 41 | bugprone-suspicious-semicolon, 42 | bugprone-suspicious-string-compare, 43 | bugprone-swapped-arguments, 44 | bugprone-terminating-continue, 45 | bugprone-throw-keyword-missing, 46 | bugprone-too-small-loop-variable, 47 | bugprone-undefined-memory-manipulation, 48 | bugprone-undelegated-constructor, 49 | bugprone-unhandled-self-assignment, 50 | bugprone-unused-raii, 51 | bugprone-unused-return-value, 52 | bugprone-use-after-move, 53 | bugprone-virtual-near-miss, 54 | cert-dcl21-cpp, 55 | cert-dcl58-cpp, 56 | cert-err34-c, 57 | cert-err52-cpp, 58 | cert-err60-cpp, 59 | cert-flp30-c, 60 | cert-msc50-cpp, 61 | cert-msc51-cpp, 62 | cert-str34-c, 63 | cppcoreguidelines-interfaces-global-init, 64 | cppcoreguidelines-narrowing-conversions, 65 | cppcoreguidelines-pro-type-member-init, 66 | cppcoreguidelines-slicing, 67 | google-default-arguments, 68 | google-explicit-constructor, 69 | google-runtime-operator, 70 | hicpp-exception-baseclass, 71 | hicpp-multiway-paths-covered, 72 | misc-misplaced-const, 73 | misc-new-delete-overloads, 74 | misc-non-copyable-objects, 75 | misc-throw-by-value-catch-by-reference, 76 | misc-unconventional-assign-operator, 77 | misc-uniqueptr-reset-release, 78 | modernize-avoid-bind, 79 | modernize-concat-nested-namespaces, 80 | modernize-deprecated-headers, 81 | modernize-deprecated-ios-base-aliases, 82 | modernize-loop-convert, 83 | modernize-make-shared, 84 | modernize-make-unique, 85 | modernize-pass-by-value, 86 | modernize-raw-string-literal, 87 | modernize-redundant-void-arg, 88 | modernize-replace-auto-ptr, 89 | modernize-replace-disallow-copy-and-assign-macro, 90 | modernize-replace-random-shuffle, 91 | modernize-return-braced-init-list, 92 | modernize-shrink-to-fit, 93 | modernize-unary-static-assert, 94 | modernize-use-auto, 95 | modernize-use-bool-literals, 96 | modernize-use-emplace, 97 | modernize-use-equals-default, 98 | modernize-use-equals-delete, 99 | modernize-use-nodiscard, 100 | modernize-use-noexcept, 101 | modernize-use-nullptr, 102 | modernize-use-override, 103 | modernize-use-transparent-functors, 104 | modernize-use-uncaught-exceptions, 105 | mpi-buffer-deref, 106 | mpi-type-mismatch, 107 | openmp-use-default-none, 108 | performance-faster-string-find, 109 | performance-for-range-copy, 110 | performance-implicit-conversion-in-loop, 111 | performance-inefficient-algorithm, 112 | performance-inefficient-string-concatenation, 113 | performance-inefficient-vector-operation, 114 | performance-move-const-arg, 115 | performance-move-constructor-init, 116 | performance-no-automatic-move, 117 | performance-noexcept-move-constructor, 118 | performance-trivially-destructible, 119 | performance-type-promotion-in-math-fn, 120 | performance-unnecessary-copy-initialization, 121 | performance-unnecessary-value-param, 122 | portability-simd-intrinsics, 123 | readability-avoid-const-params-in-decls, 124 | readability-const-return-type, 125 | readability-container-size-empty, 126 | readability-convert-member-functions-to-static, 127 | readability-delete-null-pointer, 128 | readability-deleted-default, 129 | readability-inconsistent-declaration-parameter-name, 130 | readability-make-member-function-const, 131 | readability-misleading-indentation, 132 | readability-misplaced-array-index, 133 | readability-non-const-parameter, 134 | readability-redundant-control-flow, 135 | readability-redundant-declaration, 136 | readability-redundant-function-ptr-dereference, 137 | readability-redundant-smartptr-get, 138 | readability-redundant-string-cstr, 139 | readability-redundant-string-init, 140 | readability-simplify-subscript-expr, 141 | readability-static-accessed-through-instance, 142 | readability-static-definition-in-anonymous-namespace, 143 | readability-string-compare, 144 | readability-uniqueptr-delete-release, 145 | readability-use-anyofallof' 146 | -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | Diagnostics: 2 | Suppress: 3 | - "-Wmicrosoft-enum-forward-reference" 4 | - "-Wc++11-narrowing" 5 | - "-Wc++2b-extensions" 6 | - "-Wmicrosoft-cast" 7 | CompileFlags: 8 | Add: 9 | - "-ferror-limit=0" 10 | - "-D__FUNCTION__=\"dummy\"" 11 | - "-Yumc/_HeaderOutputPredefine.h" 12 | - "-FImc/_HeaderOutputPredefine.h" # clangd bug can't find pch file 13 | Remove: 14 | - "/Yu_HeaderOutputPredefine.h" 15 | - "/FI_HeaderOutputPredefine.h" 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a report to help us improve 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Describe the bug 9 | description: A clear and concise description of what the bug is. 10 | validations: 11 | required: true 12 | 13 | - type: textarea 14 | attributes: 15 | label: To Reproduce 16 | description: Steps to reproduce the behavior. 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | attributes: 22 | label: Expected behavior 23 | description: A clear and concise description of what you expected to happen. 24 | validations: 25 | required: true 26 | 27 | - type: textarea 28 | attributes: 29 | label: Screenshots 30 | description: If applicable, add screenshots to help explain your problem. 31 | 32 | - type: input 33 | attributes: 34 | label: Platform 35 | description: The platform you are using. (e.g. Windows 10) 36 | 37 | - type: input 38 | attributes: 39 | label: BDS Version 40 | description: The version of BDS you are using. (e.g. 1.20.32.1) 41 | 42 | - type: input 43 | attributes: 44 | label: LeviLamina Version 45 | description: The version of LeviLamina you are using. (e.g. 1.0.0) 46 | 47 | - type: input 48 | attributes: 49 | label: Version 50 | description: The version of the plugin you are using. (e.g. 1.0.0) 51 | 52 | - type: textarea 53 | attributes: 54 | label: Additional context 55 | description: Add any other context about the problem here. 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project 3 | title: "[Feature]: " 4 | labels: ["enhancement"] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Is your feature request related to a problem? Please describe. 9 | description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 10 | validations: 11 | required: true 12 | 13 | - type: textarea 14 | attributes: 15 | label: Describe the solution you'd like 16 | description: A clear and concise description of what you want to happen. 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | attributes: 22 | label: Describe alternatives you've considered 23 | description: A clear and concise description of any alternative solutions or features you've considered. 24 | 25 | - type: textarea 26 | attributes: 27 | label: Additional context 28 | description: Add any other context or screenshots about the feature request here. 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## What does this PR do? 2 | 3 | 4 | 5 | ## Which issues does this PR resolve? 6 | 7 | 8 | 9 | ## Checklist before merging 10 | 11 | Thank you for your contribution to the repository. 12 | Before submitting this PR, please make sure: 13 | 14 | - [ ] Your code builds clean without any errors or warnings 15 | - [ ] Your code follows [LeviLamina C++ Style Guide](https://github.com/LiteLDev/LeviLamina/wiki/CPP-Style-Guide) 16 | - [ ] You have tested all functions 17 | - [ ] You have not used code without license 18 | - [ ] You have added statement for third-party code 19 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | push: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build: 8 | runs-on: windows-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | 12 | - uses: xmake-io/github-action-setup-xmake@v1 13 | 14 | - run: | 15 | xmake repo -u 16 | 17 | - run: | 18 | xmake f -a x64 -m release -p windows -v -y 19 | 20 | - run: | 21 | xmake -w -y 22 | 23 | - uses: actions/upload-artifact@v3 24 | with: 25 | name: DataExtractor-Windows-X64-${{ github.sha }} 26 | path: | 27 | build/windows/x64/release/DataExtractor.dll 28 | build/windows/x64/release/DataExtractor.pdb 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | release: 3 | types: 4 | - published 5 | 6 | jobs: 7 | build: 8 | runs-on: windows-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | 12 | - uses: xmake-io/github-action-setup-xmake@v1 13 | 14 | - run: | 15 | xmake repo -u 16 | 17 | - run: | 18 | xmake f -a x64 -m release -p windows -v -y 19 | 20 | - run: | 21 | xmake -w -y 22 | 23 | - uses: actions/upload-artifact@v3 24 | with: 25 | name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }} 26 | path: | 27 | bin/ 28 | 29 | upload-to-release: 30 | needs: 31 | - build 32 | permissions: 33 | contents: write 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v4 37 | 38 | - uses: actions/download-artifact@v3 39 | with: 40 | name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }} 41 | path: release/ 42 | 43 | - run: | 44 | cp LICENSE README.md release/ 45 | 46 | - name: Archive release 47 | run: | 48 | cd release 49 | zip -r ../${{ github.event.repository.name }}-windows-x64.zip * 50 | cd .. 51 | 52 | - uses: softprops/action-gh-release@v1 53 | with: 54 | append_body: true 55 | files: | 56 | ${{ github.event.repository.name }}-windows-x64.zip 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AllayMC/DataExtractor/6c6c35408b19063fe542ca8fcfded17f11184bed/LICENSE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DataExtractor 2 | 3 | This is a BDS mod which allows generating useful data used in AllayMC Project from BDS server. 4 | 5 | ## How to use? 6 | 1. Install windows version BedrockServer. see [here](https://www.minecraft.net/en-us/download/server/bedrock). 7 | 2. Set the property `block-network-ids-are-hashes` in file `server.properties` to `false`. 8 | 3. Install latest levilamina loader. For how to install it, please see [here](https://github.com/LiteLDev/LeviLamina?tab=readme-ov-file#install) 9 | 4. Download the latest release and put ```DataExtractor.dll``` and ```manifest.json``` it into `plugin/DataExtractor` folder (you may need to create it if it doesn't exist). 10 | 5. Run `bedrock_server_mod.exe`, type `/ext` in the chat, the output files will create in `data/*`. 11 | 12 | ## I want to build it myself! 13 | See [here](https://levilamina.liteldev.com/tutorials/create_your_first_plugin) for how to build levilamina plugin 14 | 15 | ## Special thanks 16 | 17 | Thanks to [LeviLamina](https://github.com/LiteLDev/LeviLamina) for their great work! -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DataExtractor", 3 | "entry": "DataExtractor.dll", 4 | "type": "native" 5 | } -------------------------------------------------------------------------------- /scripts/after_build.lua: -------------------------------------------------------------------------------- 1 | function beautify_json(value, indent) 2 | import("core.base.json") 3 | local json_text = "" 4 | local stack = {} 5 | 6 | local function escape_str(s) 7 | return string.gsub(s, '[%c\\"]', function(c) 8 | local replacements = {['\b'] = '\\b', ['\f'] = '\\f', ['\n'] = '\\n', ['\r'] = '\\r', ['\t'] = '\\t', ['"'] = '\\"', ['\\'] = '\\\\'} 9 | return replacements[c] or string.format('\\u%04x', c:byte()) 10 | end) 11 | end 12 | 13 | local function is_null(v) 14 | return v == json.null 15 | end 16 | 17 | local function is_empty_table(t) 18 | if type(t) ~= 'table' then return false end 19 | for _ in pairs(t) do 20 | return false 21 | end 22 | return true 23 | end 24 | 25 | local function is_array(t) 26 | return type(t) == 'table' and json.is_marked_as_array(t) or #t > 0 27 | end 28 | 29 | local function serialize(val, level) 30 | local spaces = string.rep(" ", level * indent) 31 | 32 | if type(val) == "table" and not stack[val] then 33 | if is_empty_table(val) then 34 | json_text = json_text .. (is_array(val) and "[]" or "{}") 35 | return 36 | end 37 | 38 | stack[val] = true 39 | local isArray = is_array(val) 40 | json_text = json_text .. (isArray and "[\n" or "{\n") 41 | 42 | local keys = isArray and {} or {} 43 | for k in pairs(val) do 44 | table.insert(keys, k) 45 | end 46 | if not isArray then 47 | table.sort(keys) 48 | end 49 | 50 | for _, k in ipairs(keys) do 51 | local v = val[k] 52 | json_text = json_text .. spaces .. (isArray and "" or '"' .. escape_str(tostring(k)) .. '": ') 53 | serialize(v, level + 1) 54 | json_text = json_text .. ",\n" 55 | end 56 | 57 | json_text = string.sub(json_text, 1, -3) .. "\n" .. string.rep(" ", (level - 1) * indent) .. (isArray and "]" or "}") 58 | stack[val] = nil 59 | elseif type(val) == "string" then 60 | json_text = json_text .. '"' .. escape_str(val) .. '"' 61 | elseif type(val) == "number" then 62 | if val % 1 == 0 then 63 | json_text = json_text .. tostring(math.floor(val)) 64 | else 65 | json_text = json_text .. tostring(val) 66 | end 67 | elseif type(val) == "boolean" then 68 | json_text = json_text .. tostring(val) 69 | elseif is_null(val) then 70 | json_text = json_text .. "null" 71 | else 72 | error("Invalid value type: " .. type(val)) 73 | end 74 | end 75 | serialize(value, 1) 76 | return json_text 77 | end 78 | 79 | function string_formatter(str, variables) 80 | return str:gsub("%${(.-)}", function(var) 81 | return variables[var] or "${" .. var .. "}" 82 | end) 83 | end 84 | 85 | function pack_plugin(target,plugin_define) 86 | import("lib.detect.find_file") 87 | 88 | local manifest_path = find_file("manifest.json", os.projectdir()) 89 | if manifest_path then 90 | local manifest = io.readfile(manifest_path) 91 | local bindir = path.join(os.projectdir(), "bin") 92 | local outputdir = path.join(bindir, plugin_define.pluginName) 93 | local targetfile = path.join(outputdir, plugin_define.pluginFile) 94 | local pdbfile = path.join(outputdir, path.basename(plugin_define.pluginFile) .. ".pdb") 95 | local manifestfile = path.join(outputdir, "manifest.json") 96 | local oritargetfile = target:targetfile() 97 | local oripdbfile = path.join(path.directory(oritargetfile), path.basename(oritargetfile) .. ".pdb") 98 | 99 | os.mkdir(outputdir) 100 | os.cp(oritargetfile, targetfile) 101 | if os.isfile(oripdbfile) then 102 | os.cp(oripdbfile, pdbfile) 103 | end 104 | 105 | formattedmanifest = string_formatter(manifest, plugin_define) 106 | io.writefile(manifestfile,formattedmanifest) 107 | cprint("${bright green}[Plugin Packer]: ${reset}plugin already generated to " .. outputdir) 108 | else 109 | cprint("${bright yellow}warn: ${reset}not found manifest.json in root dir!") 110 | end 111 | end 112 | 113 | 114 | return { 115 | pack_plugin = pack_plugin, 116 | beautify_json = beautify_json, 117 | string_formatter = string_formatter 118 | } 119 | -------------------------------------------------------------------------------- /src/MemoryOperators.cpp: -------------------------------------------------------------------------------- 1 | // This file will make your plugin use LeviLamina's memory operators by default. 2 | // This improves the memory management of your plugin and is recommended to use. 3 | 4 | #define LL_MEMORY_OPERATORS 5 | 6 | #include "ll/api/memory/MemoryOperators.h" // IWYU pragma: keep -------------------------------------------------------------------------------- /src/Plugin.cpp: -------------------------------------------------------------------------------- 1 | // Basic 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | // Plugin 8 | #include 9 | 10 | // Compress 11 | #include 12 | 13 | // Json 14 | #include 15 | 16 | // LL 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "ll/api/plugin/RegisterHelper.h" 22 | #include 23 | #include 24 | 25 | // MC 26 | #include 27 | // Item 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include "mc/world/item/components/ComponentItem.h" 38 | // Block 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | // Level 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | // Color 52 | #include 53 | #include 54 | // Math 55 | #include 56 | #include 57 | // Command 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | // NBT 64 | #include 65 | #include 66 | // Network 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | 74 | namespace plugin { 75 | 76 | static std::unique_ptr instance; 77 | 78 | bool folderExists(const std::string& folderName) { 79 | struct stat info{}; 80 | if (stat(folderName.c_str(), &info) != 0) { 81 | return false; 82 | } 83 | return info.st_mode & S_IFDIR; 84 | } 85 | 86 | void createFolder(const ll::Logger &logger, const std::string &folderName) { 87 | if (const int result = _mkdir(folderName.c_str()); result != 0) { 88 | logger.error("Failed to create folder."); 89 | } else { 90 | logger.info("Folder " + std::string(folderName) + " created successfully."); 91 | } 92 | } 93 | 94 | bool gzip_compress(const std::string &original_str, std::string &str) { 95 | z_stream d_stream = {nullptr}; 96 | if (Z_OK != deflateInit2(&d_stream, Z_BEST_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 9, Z_DEFAULT_STRATEGY)) { 97 | return false; 98 | } 99 | const unsigned long len = compressBound(original_str.size()); 100 | auto *buf = static_cast(malloc(len)); 101 | if (!buf) { 102 | return false; 103 | } 104 | d_stream.next_in = (unsigned char *) original_str.c_str(); 105 | d_stream.avail_in = original_str.size(); 106 | d_stream.next_out = buf; 107 | d_stream.avail_out = len; 108 | deflate(&d_stream, Z_SYNC_FLUSH); 109 | deflateEnd(&d_stream); 110 | str.assign(reinterpret_cast(buf), d_stream.total_out); 111 | free(buf); 112 | return true; 113 | } 114 | 115 | void writeNBT(const std::string &fileName, const CompoundTag &tag) { 116 | std::string compressed; 117 | gzip_compress(tag.toBinaryNbt(false), compressed); 118 | auto out = std::ofstream(fileName, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc); 119 | out << compressed; 120 | out.close(); 121 | } 122 | 123 | template 124 | void writeNlohmannJSON(const std::string &fileName, JSON_TYPE &json) { 125 | auto out = std::ofstream(fileName, std::ofstream::out | std::ofstream::trunc); 126 | out << json.dump(4); 127 | out.close(); 128 | } 129 | 130 | void writeJSON(const std::string &fileName, const Json::Value &json) { 131 | auto out = std::ofstream(fileName, std::ofstream::out | std::ofstream::trunc); 132 | out << json.toStyledString(); 133 | out.close(); 134 | } 135 | 136 | std::string aabbToStr(const AABB &aabb) { 137 | std::stringstream aabbStr; 138 | aabbStr << aabb.min.x << "," << aabb.min.y << "," << aabb.min.z << "," << aabb.max.x << "," << aabb.max.y << "," 139 | << aabb.max.z; 140 | return aabbStr.str(); 141 | } 142 | 143 | ll::Logger hookLogger("DataExtractor-Hook"); 144 | 145 | //Recipe packet 146 | LL_AUTO_TYPE_INSTANCE_HOOK( 147 | CraftingDataPacketHook, 148 | ll::memory::HookPriority::Normal, 149 | CraftingDataPacket, 150 | "?write@CraftingDataPacket@@UEBAXAEAVBinaryStream@@@Z", 151 | void, 152 | BinaryStream& stream 153 | ) { 154 | origin(stream); 155 | const std::string &data = stream.getAndReleaseData(); 156 | const std::string datacopy = data; 157 | stream.writeString(data, nullptr, nullptr); 158 | auto out = std::ofstream("data/crafting_data_packet.bin", 159 | std::ofstream::out | std::ofstream::binary | std::ofstream::trunc); 160 | out << datacopy; 161 | out.close(); 162 | hookLogger.info("Create crafting_data_packet.bin success!"); 163 | } 164 | 165 | //Biome definition packet 166 | //A way to get biome_definitions from network 167 | //LL_AUTO_TYPE_INSTANCE_HOOK( 168 | // BiomeDefinitionListPacketHook, 169 | // ll::memory::HookPriority::Normal, 170 | // BiomeDefinitionListPacket, 171 | // "?write@BiomeDefinitionListPacket@@UEBAXAEAVBinaryStream@@@Z", 172 | // void, 173 | // BinaryStream& stream 174 | //) { 175 | // origin(stream); 176 | // writeNBT("biome_definitions.nbt", this->mBiomeData); 177 | // hookLogger.info("Create biome_definitions.nbt success!"); 178 | //} 179 | 180 | //Cmd packet 181 | LL_AUTO_TYPE_INSTANCE_HOOK( 182 | AvailableCommandsPacketHook, 183 | ll::memory::HookPriority::Normal, 184 | AvailableCommandsPacket, 185 | "?write@AvailableCommandsPacket@@UEBAXAEAVBinaryStream@@@Z", 186 | void, 187 | BinaryStream& stream 188 | ) { 189 | origin(stream); 190 | const std::string &data = stream.getAndReleaseData(); 191 | const std::string datacopy = data; 192 | stream.writeString(data, nullptr, nullptr); 193 | auto out = std::ofstream("data/available_commands_packet.bin", 194 | std::ofstream::out | std::ofstream::binary | std::ofstream::trunc); 195 | out << datacopy; 196 | out.close(); 197 | hookLogger.info("Create available_commands_packet.bin success!"); 198 | } 199 | 200 | void dumpCreativeItemData(const ll::Logger &logger) { 201 | logger.info("Dumping creative items..."); 202 | 203 | auto global = CompoundTag(); 204 | unsigned int index = 0; 205 | CreativeItemRegistry::forEachCreativeItemInstance([&logger, &index, &global](const ItemInstance &itemInstance) { 206 | if (itemInstance.getName().empty()) { 207 | logger.warn( 208 | "Failed to extract creative item - " + itemInstance.getName() + ", index: " + std::to_string(index) 209 | ); 210 | return true; 211 | } 212 | logger.info("Dumping creative item - " + itemInstance.getName() + ", index: " + std::to_string(index)); 213 | auto obj = CompoundTag(); 214 | obj.putInt64("index", index); 215 | obj.putString("name", itemInstance.getItem()->getFullItemName()); 216 | obj.putInt("damage", itemInstance.getAuxValue()); 217 | if (itemInstance.isBlock()) { 218 | obj.putInt("blockStateHash", itemInstance.getBlock()->computeRawSerializationIdHashForNetwork()); 219 | } 220 | if (const auto nbt = itemInstance.save(); nbt->contains("tag")) { 221 | obj.put("tag", nbt->getCompound("tag")->copy()); 222 | } 223 | global.put(std::to_string(index), obj.copy()); 224 | index++; 225 | return true; 226 | }); 227 | writeNBT("data/creative_items.nbt", global); 228 | logger.info(R"(Creative items data is saved to "data/creative_items.nbt")"); 229 | } 230 | 231 | AABB ZERO_AABB = AABB(Vec3(0, 0, 0), Vec3(0, 0, 0)); 232 | 233 | void dumpBlock(ListTag &dest, const Block& block, const ll::Logger &logger) { 234 | auto nbt = CompoundTag(); 235 | try { 236 | auto sid = block.getSerializationId().clone(); 237 | auto& name = sid->getString("name"); 238 | logger.info("Dumping block state - " + name + ":" + std::to_string(block.getRuntimeId())); 239 | nbt.putString("name", name); 240 | nbt.putString("descriptionId", block.getDescriptionId()); 241 | nbt.putString("blockEntityName", std::string(magic_enum::enum_name(block.getBlockEntityType()))); 242 | nbt.putCompound("states", sid->getCompound("states")->clone()); 243 | nbt.putFloat("thickness", block.getThickness()); 244 | nbt.putFloat("friction", block.getFriction()); 245 | nbt.putFloat("hardness", block.getDestroySpeed()); 246 | nbt.putFloat("explosionResistance", block.getExplosionResistance()); 247 | nbt.putInt("version", sid->getInt("version")); 248 | nbt.putInt("runtimeId", block.getRuntimeId()); 249 | if (name != "minecraft:unknown") 250 | nbt.putInt("blockStateHash", block.computeRawSerializationIdHashForNetwork()); 251 | else 252 | nbt.putInt("blockStateHash", -2); 253 | nbt.putInt("burnChance", block.getFlameOdds()); 254 | nbt.putInt("burnAbility", block.getBurnOdds()); 255 | nbt.putInt("lightDampening", block.getLight().value); 256 | nbt.putInt("lightEmission", block.getLightEmission().value); 257 | mce::Color color = block.getMapColor( 258 | ll::service::getLevel()->getDimension(DimensionType(0))->getBlockSourceFromMainChunkSource(), 259 | BlockPos(0, 10, 0) 260 | ); 261 | auto colornbt = CompoundTag(); 262 | colornbt.putInt("r", static_cast(color.r * 255)); 263 | colornbt.putInt("g", static_cast(color.g * 255)); 264 | colornbt.putInt("b", static_cast(color.b * 255)); 265 | colornbt.putInt("a", static_cast(color.a * 255)); 266 | colornbt.putString("hexString", color.toHexString()); 267 | nbt.putCompound("color", colornbt); 268 | auto tmp = AABB(0, 0, 0, 0, 0, 0); 269 | block.getCollisionShapeForCamera( 270 | tmp, 271 | *reinterpret_cast(&ll::service::getLevel() 272 | ->getDimension(DimensionType(0)) 273 | ->getBlockSourceFromMainChunkSource()), 274 | BlockPos(0, 0, 0) 275 | ); 276 | nbt.putString("aabbVisual", aabbToStr(tmp)); 277 | auto tmp2 = AABB(0, 0, 0, 0, 0, 0); 278 | optional_ref nullRef{}; 279 | block.getCollisionShape( 280 | tmp2, 281 | *reinterpret_cast(&ll::service::getLevel() 282 | ->getDimension(DimensionType(0)) 283 | ->getBlockSourceFromMainChunkSource()), 284 | BlockPos(0, 0, 0), 285 | nullRef 286 | ); 287 | nbt.putString("aabbCollision", aabbToStr(tmp2)); 288 | nbt.putBoolean("hasCollision", tmp2 != ZERO_AABB); 289 | nbt.putBoolean("hasBlockEntity", block.getBlockEntityType() != BlockActorType::Undefined); 290 | nbt.putBoolean("isBounceBlock", block.isBounceBlock()); 291 | nbt.putBoolean("isButtonBlock", block.isButtonBlock()); 292 | nbt.putBoolean("isCropBlock", block.isCropBlock()); 293 | nbt.putBoolean("isDoorBlock", block.isDoorBlock()); 294 | nbt.putBoolean("isFenceBlock", block.isFenceBlock()); 295 | nbt.putBoolean("isFenceGateBlock", block.isFenceGateBlock()); 296 | nbt.putBoolean("isThinFenceBlock", block.isThinFenceBlock()); 297 | nbt.putBoolean("isFallingBlock", block.isFallingBlock()); 298 | nbt.putBoolean("isStemBlock", block.isStemBlock()); 299 | nbt.putBoolean("isSlabBlock", block.isSlabBlock()); 300 | nbt.putBoolean("isLavaFlammable", block.isLavaFlammable()); 301 | nbt.putBoolean("isUnbreakable", block.isUnbreakable()); 302 | nbt.putBoolean("isPowerSource", block.isSignalSource()); 303 | // nbt->putBoolean("breaksFallingBlocks", block->breaksFallingBlocks(BaseGameVersion())); 304 | nbt.putBoolean("isWaterBlocking", block.isWaterBlocking()); 305 | nbt.putBoolean("isMotionBlockingBlock", block.isMotionBlockingBlock()); 306 | nbt.putBoolean("hasComparatorSignal", block.hasComparatorSignal()); 307 | nbt.putBoolean("pushesUpFallingBlocks", block.pushesUpFallingBlocks()); 308 | // nbt->putBoolean("waterSpreadCausesSpawn", block->waterSpreadCausesSpawn()); 309 | nbt.putBoolean("canContainLiquid", block.getLegacyBlock().canContainLiquid()); 310 | // nbt->putBoolean("canBeBrokenFromFalling", block.canBeBrokenFromFalling()); 311 | nbt.putBoolean("isContainerBlock", block.isContainerBlock()); 312 | nbt.putBoolean("canHarvestWithHand", block.canDropWithAnyTool()); 313 | } catch (std::exception &e) { 314 | logger.error("Exception caught : " + std::string(e.what())); 315 | } 316 | 317 | dest.add(nbt); 318 | } 319 | 320 | unsigned int blockStateCounter = 0; 321 | 322 | void dumpBlockData(const ll::Logger &logger) { 323 | logger.info("Dumping block states' attributes..."); 324 | const auto &palette = ll::service::getLevel()->getBlockPalette(); 325 | int airCount = 0; 326 | auto array = nlohmann::json::array(); 327 | 328 | auto tag = CompoundTag(); 329 | auto list = ListTag(); 330 | blockStateCounter = 0; 331 | while (true) { 332 | const auto &block = palette.getBlock(blockStateCounter); 333 | if (block.getName().getString() == "minecraft:air") { 334 | airCount++; 335 | if (airCount == 2) { 336 | blockStateCounter--; 337 | break; 338 | } 339 | } 340 | dumpBlock(list, block, logger); 341 | blockStateCounter++; 342 | } 343 | tag.put("block", list.copyList()); 344 | // logger.info("Successfully extract " + std::to_string(blockStateCounter) + " block states' attributes!"); 345 | writeNBT("data/block_attributes.nbt", tag); 346 | logger.info(R"(Block attribute data is saved to "data/block_attributes.nbt")"); 347 | } 348 | 349 | void dumpItem(ListTag &dest, const Item &item, const ll::Logger &logger) { 350 | auto nbt = CompoundTag(); 351 | logger.info("Dumping item - " + item.getFullItemName()); 352 | nbt.putShort("id", item.getId()); 353 | try { 354 | if (!item.getLegacyBlock().expired() && item.getLegacyBlock().get() != nullptr) 355 | nbt.putString( 356 | "blockId", 357 | item.getLegacyBlock()->getNamespace() + ":" + item.getLegacyBlock()->getRawNameId() 358 | ); 359 | } catch (std::exception &e) { 360 | logger.warn("Exception occur when trying to get block for item " + item.getFullItemName()); 361 | } 362 | nbt.putBoolean("isComponentBased", item.isComponentBased()); 363 | nbt.putString("name", item.getFullItemName()); 364 | nbt.putShort("maxDamage", item.getMaxDamage()); 365 | nbt.putBoolean("isBlockPlanterItem", item.isBlockPlanterItem()); 366 | nbt.putBoolean("isDamageable", item.isDamageable()); 367 | nbt.putBoolean("isDye", item.isDye()); 368 | nbt.putString("itemColorName", ItemColorUtil::getName(item.getItemColor())); 369 | nbt.putInt("itemColorRGB", ItemColorUtil::getRGBColor(item.getItemColor())); 370 | nbt.putBoolean("isFertilizer", item.isFertilizer()); 371 | nbt.putBoolean("isThrowable", item.isThrowable()); 372 | nbt.putBoolean("isUseable", item.isUseable()); 373 | nbt.putBoolean("isElytra", item.isElytra()); 374 | nbt.putBoolean("canBeDepleted", item.canBeDepleted()); 375 | nbt.putBoolean("canDestroyInCreative", item.canDestroyInCreative()); 376 | nbt.putBoolean("canUseOnSimTick", item.canUseOnSimTick()); 377 | nbt.putBoolean("canBeCharged", item.canBeCharged()); 378 | nbt.putString("creativeGroup", item.getCreativeGroup()); 379 | nbt.putInt("creativeCategory", static_cast(item.getCreativeCategory())); 380 | nbt.putInt("armorValue", item.getArmorValue()); 381 | nbt.putInt("attackDamage", item.getAttackDamage()); 382 | nbt.putInt("toughnessValue", item.getToughnessValue()); 383 | nbt.putFloat("viewDamping", item.getViewDamping()); 384 | nbt.putInt("cooldownTime", item.getCooldownTime()); 385 | nbt.putString("cooldownType", item.getCooldownType().getString()); 386 | nbt.putInt("maxStackSize", item.getMaxStackSize(item.buildDescriptor(0, nullptr))); 387 | CompoundTag descriptionId; 388 | std::set uniqueStr; 389 | for (int i = 0; i <= 256; ++i) { 390 | try { 391 | if (item.isValidAuxValue(i)) { 392 | if (const auto itemStack = ItemStack(item, 1, i); !uniqueStr.contains(itemStack.getDescriptionId())) { 393 | uniqueStr.insert(itemStack.getDescriptionId()); 394 | descriptionId.putString(std::to_string(i), itemStack.getDescriptionId()); 395 | } 396 | } 397 | } catch (...) {} 398 | } 399 | nbt.putCompound("descriptionId", descriptionId); 400 | dest.add(nbt); 401 | } 402 | 403 | void dumpItemData(const ll::Logger &logger) { 404 | auto tag = CompoundTag(); 405 | auto list = ListTag(); 406 | short counter = 0; 407 | for (const auto &item: ItemRegistryManager::getItemRegistry().getNameToItemMap() | std::views::values) { 408 | dumpItem(list, *item, logger); 409 | counter++; 410 | } 411 | tag.put("item", list); 412 | logger.info("Dump " + std::to_string(counter) + " item data successfully!"); 413 | writeNBT("data/item_data.nbt", tag); 414 | logger.info(R"(Items' data have is to "data/item_data.nbt")"); 415 | } 416 | 417 | void dumpPalette(const ll::Logger &logger) { 418 | logger.info("Dumping block palette..."); 419 | 420 | const auto &palette = ll::service::getLevel()->getBlockPalette(); 421 | 422 | auto global = CompoundTag(); 423 | auto blocks = ListTag(); 424 | for (int i = 0; i <= blockStateCounter; ++i) { 425 | // Do not use CompoundTag::clone() here, use CompoundTag's constructor instead! 426 | blocks.add(CompoundTag(palette.getBlock(i).getSerializationId())); 427 | } 428 | global.put("blocks", blocks); 429 | writeNBT("data/block_palette.nbt", global); 430 | logger.info(R"(Block palette table is saved to "data/block_palette.nbt"))"); 431 | } 432 | 433 | static const MaterialType materialTypes[] = { 434 | MaterialType::Air,MaterialType::Dirt,MaterialType::Wood,MaterialType::Stone, 435 | MaterialType::Metal,MaterialType::Water,MaterialType::Lava,MaterialType::Leaves, 436 | MaterialType::Plant,MaterialType::SolidPlant,MaterialType::Sponge,MaterialType::Cloth, 437 | MaterialType::Bed,MaterialType::Fire,MaterialType::Sand,MaterialType::Decoration, 438 | MaterialType::Glass,MaterialType::Explosive,MaterialType::Ice,MaterialType::PackedIce, 439 | MaterialType::TopSnow,MaterialType::Snow,MaterialType::PowderSnow,MaterialType::Amethyst, 440 | MaterialType::Cactus,MaterialType::Clay,MaterialType::Vegetable,MaterialType::Portal, 441 | MaterialType::Cake,MaterialType::Web,MaterialType::RedstoneWire,MaterialType::Carpet, 442 | MaterialType::BuildableGlass,MaterialType::Slime,MaterialType::Piston,MaterialType::Allow, 443 | MaterialType::Deny,MaterialType::Netherwart,MaterialType::StoneDecoration,MaterialType::Bubble, 444 | MaterialType::Egg,MaterialType::SoftEgg,MaterialType::Barrier,MaterialType::Coral, 445 | MaterialType::DecorationSolid,MaterialType::Dripstone,MaterialType::ReinforcedStone,MaterialType::Sculk, 446 | MaterialType::SculkVein,MaterialType::ClientRequestPlaceholder,MaterialType::StructureVoid,MaterialType::Root, 447 | MaterialType::SurfaceTypeTotal,MaterialType::Any 448 | }; 449 | 450 | MaterialType findMaterialType(const Material & material) { 451 | for (MaterialType type : materialTypes) { 452 | if (material.isType(type)) { 453 | return type; 454 | } 455 | } 456 | return MaterialType::Any; 457 | } 458 | 459 | void dumpMaterialData(const ll::Logger &logger) { 460 | logger.info("Dumping material data..."); 461 | 462 | CompoundTag global = CompoundTag(); 463 | BlockTypeRegistry::forEachBlock([&global](const BlockLegacy& blockLegacy) { 464 | auto data = CompoundTag(); 465 | auto & material = blockLegacy.getMaterial(); 466 | data.putString("materialType", std::string(magic_enum::enum_name(findMaterialType(material)))); 467 | data.putBoolean("isSolid", material.isSolid()); 468 | data.putBoolean("isSolidBlocking", material.isSolidBlocking()); 469 | data.putBoolean("canBeMovingBlock", material.getBlocksMotion()); 470 | data.putBoolean("canHavePrecipitation", material.getBlocksPrecipitation()); 471 | data.putFloat("translucency", material.getTranslucency()); 472 | data.putBoolean("isAlwaysDestroyable", material.isAlwaysDestroyable()); 473 | data.putBoolean("isLiquid", material.isLiquid()); 474 | data.putBoolean("isSuperHot", material.isSuperHot()); 475 | 476 | global.put(blockLegacy.getTypeName(), data); 477 | return true; 478 | }); 479 | writeNBT("data/block_material_data.nbt", global); 480 | } 481 | 482 | void dumpBlockCorrectToolSpecial(const ll::Logger &logger) { 483 | logger.info("Dumping correct tool special..."); 484 | 485 | CompoundTag global = CompoundTag(); 486 | BlockTypeRegistry::forEachBlock([&global](const BlockLegacy& blockLegacy) { 487 | auto correctItemList = ListTag(); 488 | auto & block = blockLegacy.getDefaultState(); 489 | for (const auto &item: ItemRegistryManager::getItemRegistry().getNameToItemMap() | std::views::values) { 490 | auto itemStack = ItemStack(*item, 1, 0); 491 | if (itemStack.canDestroySpecial(block)) { 492 | correctItemList.add(StringTag(item->getFullItemName())); 493 | } 494 | } 495 | if (correctItemList.size() != 0) { 496 | global.put(blockLegacy.getTypeName(), correctItemList); 497 | } 498 | return true; 499 | }); 500 | writeNBT("data/block_correct_tool_special.nbt", global); 501 | } 502 | 503 | bool compareCmdSymbolByIndex(const CommandRegistry::Symbol &s1, const CommandRegistry::Symbol &s2) { 504 | return s1.toIndex() < s2.toIndex(); 505 | } 506 | 507 | bool compareCmdSymbolByValue(const CommandRegistry::Symbol &s1, const CommandRegistry::Symbol &s2) { 508 | return s1.value() < s2.value(); 509 | } 510 | 511 | template 512 | void dumpCmdSymbol(const ll::Logger &logger, const CommandRegistry ®istry, JSON_TYPE &json, const CommandRegistry::Symbol &symbol) { 513 | const std::string name = registry.symbolToString(symbol); 514 | logger.info("Dumping command arg type - " + name); 515 | auto obj = std::map(); 516 | obj["description"] = registry.describe(symbol); 517 | obj["index"] = std::to_string(symbol.toIndex()); 518 | obj["value"] = std::to_string(symbol.value()); 519 | json[name] = obj; 520 | } 521 | 522 | template 523 | void dumpCmdSymbol(const ll::Logger &logger, const CommandRegistry ®istry, JSON_TYPE &json, const CommandRegistry::Symbol &symbol, const std::string &key) { 524 | const std::string name = registry.symbolToString(symbol); 525 | logger.info("Dumping command arg type - " + name); 526 | auto obj = std::map(); 527 | obj["name"] = name; 528 | obj["description"] = registry.describe(symbol); 529 | obj["index"] = std::to_string(symbol.toIndex()); 530 | obj["value"] = std::to_string(symbol.value()); 531 | json[key] = obj; 532 | } 533 | 534 | void dumpCommandNameSymbol(const ll::Logger &logger) { 535 | const auto ®istry = ll::service::getMinecraft()->getCommands().getRegistry(); 536 | auto symbols_sortby_index = std::vector(); 537 | auto symbols_sortby_value = std::vector(); 538 | for (auto &symbol: registry.mCommandSymbols) { 539 | if (!registry.isValid(symbol)) { 540 | continue; 541 | } 542 | if (auto name = registry.symbolToString(symbol); name == "ll" || name == "ext") { 543 | continue; 544 | } 545 | symbols_sortby_index.push_back(symbol); 546 | symbols_sortby_value.push_back(symbol); 547 | } 548 | // Sort symbol by index 549 | std::ranges::sort(symbols_sortby_index, compareCmdSymbolByIndex); 550 | std::ranges::sort(symbols_sortby_value, compareCmdSymbolByValue); 551 | nlohmann::ordered_json global1; 552 | for (auto &symbol : symbols_sortby_index) { 553 | dumpCmdSymbol(logger, registry, global1, symbol); 554 | } 555 | writeNlohmannJSON("data/command_name_symbol_i.json", global1); 556 | nlohmann::ordered_json global2; 557 | for (auto &symbol : symbols_sortby_value) { 558 | dumpCmdSymbol(logger, registry, global2, symbol); 559 | } 560 | writeNlohmannJSON("data/command_name_symbol_v.json", global2); 561 | logger.info("Command name symbol is saved to \"data/command_name_symbol_(i/v).json\""); 562 | } 563 | 564 | void dumpCommonCommandArgData(const ll::Logger &logger) { 565 | const auto ®istry = ll::service::getMinecraft()->getCommands().getRegistry(); 566 | nlohmann::ordered_json global; 567 | for (int i = 0; i < 1000; i++) { 568 | if (const int symbol = i | 0x100000; registry.isValid(symbol)) { 569 | dumpCmdSymbol(logger, registry, global, symbol); 570 | } 571 | } 572 | writeNlohmannJSON("data/command_arg_types_common_i.json", global); 573 | logger.info("Common command arg type is saved to \"data/command_arg_types_common_i.json\""); 574 | } 575 | 576 | void dumpFullCommandArgData(const ll::Logger &logger) { 577 | auto ®istry = ll::service::getMinecraft()->getCommands().getRegistry(); 578 | auto symbols_sortby_index = std::vector(); 579 | auto symbols_sortby_value = std::vector(); 580 | registry.forEachNonTerminal([®istry, &symbols_sortby_index, &symbols_sortby_value](const CommandRegistry::Symbol &symbol) { 581 | if (!registry.isValid(symbol)) { 582 | return; 583 | } 584 | symbols_sortby_index.push_back(symbol); 585 | symbols_sortby_value.push_back(symbol); 586 | }); 587 | // Sort symbol by index 588 | std::ranges::sort(symbols_sortby_index, compareCmdSymbolByIndex); 589 | nlohmann::ordered_json global1; 590 | for (auto &symbol : symbols_sortby_index) { 591 | dumpCmdSymbol(logger, registry, global1, symbol); 592 | } 593 | writeNlohmannJSON("data/command_arg_types_full_i.json", global1); 594 | nlohmann::ordered_json global2; 595 | for (auto &symbol : symbols_sortby_value) { 596 | dumpCmdSymbol(logger, registry, global2, symbol); 597 | } 598 | writeNlohmannJSON("data/command_arg_types_full_v.json", global2); 599 | logger.info("Full command arg type data is saved to \"data/command_arg_types_full_(i/v).json\""); 600 | } 601 | 602 | void dumpCommandmConstrainedValues(const ll::Logger &logger) { 603 | auto ®istry = ll::service::getMinecraft()->getCommands().getRegistry(); 604 | auto array = nlohmann::json::array(); 605 | for (auto &[mValue, mEnum, mConstraints] : registry.mConstrainedValues) { 606 | auto obj = nlohmann::json::object(); 607 | dumpCmdSymbol(logger, registry, obj, mValue, "value"); 608 | dumpCmdSymbol(logger, registry, obj, mEnum, "enum"); 609 | obj["constraints"] = mConstraints; 610 | array.push_back(obj); 611 | } 612 | writeNlohmannJSON("data/command_constrained_values.json", array); 613 | logger.info("Command constrained values data is saved to \"data/command_constrained_values.json\""); 614 | } 615 | 616 | int getBiomeId(const ll::Logger& logger, const Biome& biome) { 617 | try { 618 | return ll::memory::dAccess(&biome, 0x80); 619 | } catch (...) { 620 | logger.error("Failed in getBiomeId()! Please check if the memory offset is right!"); 621 | } 622 | } 623 | 624 | std::string getBiomeName(const ll::Logger& logger, const Biome& biome) { 625 | try { 626 | return ll::memory::dAccess(&biome, 0x08).getString(); 627 | } catch (...) { 628 | logger.error("Failed in getBiomeName()! Please check if the memory offset is right!"); 629 | } 630 | } 631 | 632 | void dumpBiomeData(const ll::Logger &logger) { 633 | BiomeRegistry ®istry = ll::service::getLevel()->getBiomeRegistry(); 634 | auto biomeInfoMap = nlohmann::json::object(); 635 | auto biomes = CompoundTag(); 636 | TagRegistry, IDType > &tagReg = registry.getTagRegistry(); 637 | registry.forEachBiome([&biomes, &logger, &tagReg, &biomeInfoMap](Biome const &biome) { 638 | auto name = getBiomeName(logger, biome); 639 | int id = getBiomeId(logger, biome); 640 | logger.info("Dumping biome data - " + name); 641 | auto tag = CompoundTag(); 642 | biome.writePacketData(tag, tagReg); 643 | biomes.put(name, tag); 644 | auto obj = nlohmann::json::object(); 645 | obj["id"] = id; 646 | obj["type"] = std::string(magic_enum::enum_name(biome.getBiomeType())); 647 | biomeInfoMap[name] = obj; 648 | }); 649 | writeNBT("data/biome_definitions.nbt", biomes); 650 | writeNlohmannJSON("data/biome_id_and_type.json", biomeInfoMap); 651 | logger.info( 652 | R"(Biome definitions is saved to "data/biome_definitions.nbt" and "data/biome_id_and_type.json")" 653 | ); 654 | } 655 | 656 | struct PropertyType { 657 | std::string serializationName; 658 | std::string valueType; 659 | std::set values; 660 | std::string blockName; 661 | 662 | bool operator==(const PropertyType &other) const { 663 | return serializationName == other.serializationName && valueType == other.valueType 664 | && values.size() == other.values.size(); 665 | } 666 | }; 667 | 668 | void dumpPropertyTypeData(const ll::Logger &logger) { 669 | logger.info("Dumping property type data..."); 670 | 671 | std::map > > blockToBlockStateData; 672 | 673 | auto &palette = ll::service::getLevel()->getBlockPalette(); 674 | for (int i = 0; i <= blockStateCounter; ++i) { 675 | const Block &block = palette.getBlock(i); 676 | auto name = block.getLegacyBlock().getRawNameId(); 677 | if (!blockToBlockStateData.contains(name)) { 678 | blockToBlockStateData[name] = std::vector >(); 679 | } 680 | auto &blockStates = blockToBlockStateData[name]; 681 | if (auto nbt = block.getSerializationId().clone(); nbt->contains("states") && !nbt->getCompound("states")->isEmpty()) { 682 | blockStates.push_back(nbt->getCompound("states")->clone()); 683 | } 684 | } 685 | 686 | std::map > blockToPropertyTypeMap; 687 | 688 | for (auto &entry: blockToBlockStateData) { 689 | auto &states = entry.second; 690 | std::map propertyTypeMap; 691 | 692 | for (auto &state: states) { 693 | for (auto &valueEntry: state->rawView()) { 694 | if (!propertyTypeMap.contains(valueEntry.first)) { 695 | PropertyType p; 696 | p.serializationName = valueEntry.first; 697 | p.blockName = entry.first; 698 | propertyTypeMap[p.serializationName] = p; 699 | } 700 | auto &propertyType = propertyTypeMap[valueEntry.first]; 701 | switch (valueEntry.second.getId()) { 702 | case Tag::Type::Byte: 703 | if (propertyType.valueType.empty()) { 704 | propertyType.valueType = "BOOLEAN"; 705 | } 706 | propertyType.values.insert(state->getBoolean(valueEntry.first) ? "true" : "false"); 707 | break; 708 | case Tag::Type::Int: 709 | if (propertyType.valueType.empty()) { 710 | propertyType.valueType = "INTEGER"; 711 | } 712 | propertyType.values.insert(std::to_string(state->getInt(valueEntry.first))); 713 | break; 714 | case Tag::Type::String: 715 | if (propertyType.valueType.empty()) { 716 | propertyType.valueType = "ENUM"; 717 | } 718 | propertyType.values.insert(state->getString(valueEntry.first)); 719 | break; 720 | default: 721 | if (propertyType.valueType.empty()) { 722 | propertyType.valueType = "UNKNOWN"; 723 | } 724 | logger.warn("Unknown tag type when dumping property type data: " + valueEntry.first); 725 | break; 726 | } 727 | } 728 | } 729 | blockToPropertyTypeMap[entry.first] = propertyTypeMap; 730 | } 731 | 732 | std::set differentSizePropertyTypes; 733 | std::map > specialBlockTypes; 734 | std::map tmpLookUp; 735 | 736 | for (auto &entry: blockToPropertyTypeMap) { 737 | for (auto &entryInside: entry.second) { 738 | auto &propertyName = entryInside.first; 739 | auto &propertyType = entryInside.second; 740 | if (!tmpLookUp.contains(propertyName)) { 741 | tmpLookUp[propertyName] = propertyType; 742 | } else if (tmpLookUp[propertyName] != propertyType && !differentSizePropertyTypes. 743 | contains(propertyName)) { 744 | logger.warn("Property type \"" + propertyName + "\" has different size in different blocks!"); 745 | differentSizePropertyTypes.insert(propertyName); 746 | auto fullBlockName = "minecraft:" + entry.first; 747 | if (!specialBlockTypes.contains(fullBlockName)) { 748 | specialBlockTypes[fullBlockName] = std::map(); 749 | } 750 | } 751 | } 752 | } 753 | 754 | std::map globalPropertyTypeMap; 755 | 756 | for (auto &entry: blockToPropertyTypeMap) { 757 | for (auto &entryInside: entry.second) { 758 | auto &propertyName = entryInside.first; 759 | auto &propertyType = entryInside.second; 760 | auto keyName = std::string(propertyName); 761 | std::string::size_type pos = 0; 762 | while ((pos = keyName.find(':', pos)) != std::string::npos) { 763 | keyName.replace(pos, 1, "_"); 764 | pos++; 765 | } 766 | if (!differentSizePropertyTypes.contains(propertyName)) { 767 | globalPropertyTypeMap[keyName] = propertyType; 768 | } else { 769 | auto newKey = keyName + "_" + std::to_string(propertyType.values.size()); 770 | auto fullBlockName = "minecraft:" + entry.first; 771 | specialBlockTypes[fullBlockName][keyName] = newKey; 772 | globalPropertyTypeMap[newKey] = propertyType; 773 | } 774 | } 775 | } 776 | 777 | auto globalJson = nlohmann::json::object(); 778 | auto propertyTypes = nlohmann::json::object(); 779 | 780 | for (auto &propertyTypeEntry: globalPropertyTypeMap) { 781 | if (propertyTypeEntry.second.serializationName.empty()) { 782 | continue; 783 | } 784 | auto obj = nlohmann::json::object(); 785 | 786 | obj["serializationName"] = propertyTypeEntry.second.serializationName; 787 | obj["valueType"] = propertyTypeEntry.second.valueType; 788 | if (propertyTypeEntry.second.valueType == "INTEGER") { 789 | std::vector values; 790 | for (auto &value: propertyTypeEntry.second.values) { 791 | values.push_back(stoi(value)); 792 | } 793 | std::ranges::sort(values); 794 | obj["values"] = values; 795 | } else if (propertyTypeEntry.second.valueType == "BOOLEAN") { 796 | std::vector values{false, true}; 797 | obj["values"] = values; 798 | } else { 799 | obj["values"] = propertyTypeEntry.second.values; 800 | } 801 | 802 | propertyTypes[propertyTypeEntry.first] = obj; 803 | } 804 | globalJson["propertyTypes"] = propertyTypes; 805 | globalJson["differentSizePropertyTypes"] = differentSizePropertyTypes; 806 | globalJson["specialBlockTypes"] = specialBlockTypes; 807 | writeNlohmannJSON("data/block_property_types.json", globalJson); 808 | logger.info("Block property type data is saved to \"data/block_property_types.json\""); 809 | } 810 | 811 | void dumpItemTags(const ll::Logger &logger) { 812 | logger.info("Dumping item tags..."); 813 | nlohmann::json res = nlohmann::json::object(); 814 | #define DUMP(TAG) \ 815 | do { \ 816 | auto items = ItemRegistryManager::getItemRegistry().lookupByTag(VanillaItemTags::##TAG); \ 817 | auto arr = nlohmann::json::array(); \ 818 | for (auto item : items) { \ 819 | arr.push_back(item->getFullItemName()); \ 820 | } \ 821 | res[VanillaItemTags::##TAG.getString()] = arr; \ 822 | logger.info(VanillaItemTags::##TAG.getString()); \ 823 | } while (false) 824 | DUMP(Armor); 825 | DUMP(Arrows); 826 | DUMP(Banners); 827 | DUMP(Boat); 828 | DUMP(Boats); 829 | DUMP(BookshelfBooks); 830 | DUMP(ChainmailTier); 831 | DUMP(ChestBoat); 832 | DUMP(Coals); 833 | DUMP(Cooked); 834 | DUMP(CrimsonStems); 835 | DUMP(DecoratedPotSherds); 836 | DUMP(DiamondTier); 837 | DUMP(Digger); 838 | DUMP(Door); 839 | DUMP(Fishes); 840 | DUMP(Food); 841 | DUMP(GoldenTier); 842 | DUMP(HangingActor); 843 | DUMP(HangingSign); 844 | DUMP(Hatchet); 845 | DUMP(Hoe); 846 | DUMP(HorseArmor); 847 | DUMP(IronTier); 848 | DUMP(LeatherTier); 849 | DUMP(LecternBooks); 850 | DUMP(Logs); 851 | DUMP(LogsThatBurn); 852 | DUMP(MangroveLogs); 853 | DUMP(Meat); 854 | DUMP(Minecart); 855 | DUMP(MusicDiscs); 856 | DUMP(NetheriteTier); 857 | DUMP(Pickaxe); 858 | DUMP(PiglinLoved); 859 | DUMP(PiglinRepellents); 860 | DUMP(Planks); 861 | DUMP(Sand); 862 | DUMP(Shovel); 863 | DUMP(Sign); 864 | DUMP(SoulFireBaseBlocks); 865 | DUMP(SpawnEgg); 866 | DUMP(StoneBricks); 867 | DUMP(StoneCraftingMaterials); 868 | DUMP(StoneTier); 869 | DUMP(StoneToolMaterials); 870 | DUMP(Sword); 871 | DUMP(Tool); 872 | DUMP(TransformMaterials); 873 | DUMP(TransformTemplates); 874 | DUMP(TransformableItems); 875 | DUMP(Trident); 876 | DUMP(TrimMaterials); 877 | DUMP(TrimTemplates); 878 | DUMP(TrimmableArmors); 879 | DUMP(VibrationDamper); 880 | DUMP(WarpedStems); 881 | DUMP(WoodenSlabs); 882 | DUMP(WoodenTier); 883 | DUMP(Wool); 884 | #undef DUMP 885 | writeNlohmannJSON("data/item_tags.json", res); 886 | } 887 | 888 | void dumpBlockTags(const ll::Logger &logger) { 889 | logger.info("Dumping block tags..."); 890 | nlohmann::json res = nlohmann::json::object(); 891 | #define DUMP(TAG) \ 892 | do { \ 893 | auto arr = nlohmann::json::array(); \ 894 | BlockTypeRegistry::forEachBlock([&arr](const BlockLegacy& b) { \ 895 | if (b.hasTag(VanillaBlockTags::##TAG)) { \ 896 | arr.push_back(b.getTypeName()); \ 897 | } \ 898 | return true; \ 899 | }); \ 900 | res[VanillaBlockTags::##TAG.getString()] = arr; \ 901 | logger.info(VanillaBlockTags::##TAG.getString()); \ 902 | } while (false) 903 | DUMP(Acacia); 904 | DUMP(Birch); 905 | DUMP(Crop); 906 | DUMP(DarkOak); 907 | DUMP(DiamondDiggable); 908 | DUMP(Dirt); 909 | DUMP(FertilizeArea); 910 | DUMP(GoldDiggable); 911 | DUMP(Grass); 912 | DUMP(Gravel); 913 | DUMP(IronDiggable); 914 | DUMP(Jungle); 915 | DUMP(Log); 916 | DUMP(Metal); 917 | DUMP(MobSpawner); 918 | DUMP(NotFeatureReplaceable); 919 | DUMP(Oak); 920 | DUMP(Plant); 921 | DUMP(Pumpkin); 922 | DUMP(Rail); 923 | DUMP(Sand); 924 | DUMP(Snow); 925 | DUMP(Spruce); 926 | DUMP(Stone); 927 | DUMP(StoneDiggable); 928 | DUMP(TextSign); 929 | DUMP(Trapdoors); 930 | DUMP(Water); 931 | DUMP(Wood); 932 | DUMP(WoodDiggable); 933 | #undef DUMP 934 | writeNlohmannJSON("data/block_tags.json", res); 935 | } 936 | 937 | void ext(const ll::Logger &logger) { 938 | if (!folderExists("data")) { 939 | createFolder(logger, "data"); 940 | } 941 | dumpBlockCorrectToolSpecial(logger); 942 | dumpCommandNameSymbol(logger); 943 | dumpCommonCommandArgData(logger); 944 | dumpFullCommandArgData(logger); 945 | dumpCommandmConstrainedValues(logger); 946 | dumpBiomeData(logger); 947 | dumpCreativeItemData(logger); 948 | dumpBlockData(logger); 949 | dumpMaterialData(logger); 950 | dumpPalette(logger); 951 | dumpPropertyTypeData(logger); 952 | dumpBlockTags(logger); 953 | dumpItemTags(logger); 954 | dumpItemData(logger); 955 | } 956 | 957 | // // Use this if command not works 958 | // LL_AUTO_TYPE_INSTANCE_HOOK( 959 | // TextPacketHandleHook, 960 | // ll::memory::HookPriority::Normal, 961 | // ServerNetworkHandler, 962 | // "?handle@ServerNetworkHandler@@UEAAXAEBVNetworkIdentifier@@AEBVTextPacket@@@Z", 963 | // void, 964 | // class NetworkIdentifier const& source, 965 | // class TextPacket const& packet 966 | // ) { 967 | // origin(source, packet); 968 | // if (packet.mMessage == "ext") { 969 | // ext(Plugin::getInstance().getSelf().getLogger()); 970 | // } 971 | // } 972 | 973 | // // Another way if command not works. No need to join the server 974 | LL_AUTO_TYPE_INSTANCE_HOOK( 975 | HelpCommandHook, 976 | ll::memory::HookPriority::Normal, 977 | HelpCommand, 978 | "?execute@HelpCommand@@UEBAXAEBVCommandOrigin@@AEAVCommandOutput@@@Z", 979 | void, 980 | class CommandOrigin const& o, 981 | class CommandOutput& output 982 | ) { 983 | origin(o, output); 984 | ext(instance->getSelf().getLogger()); 985 | } 986 | 987 | Plugin& Plugin::getInstance() { return *instance; } 988 | 989 | bool Plugin::load() { 990 | getSelf().getLogger().info("Loading..."); 991 | return true; 992 | } 993 | 994 | bool Plugin::enable() { 995 | auto& logger = getSelf().getLogger(); 996 | logger.info("Enabling..."); 997 | 998 | // TODO: It seems not works, replaced with TextPacket hook. Need to fix it in the future 999 | // auto& cmd = ll::command::CommandRegistrar::getInstance().getOrCreateCommand( 1000 | // "ext", 1001 | // "extract data", 1002 | // CommandPermissionLevel::GameDirectors, 1003 | // CommandFlagValue::None 1004 | // ); 1005 | // cmd.overload().execute<[&](CommandOrigin const&, CommandOutput& output) { 1006 | // ext(logger); 1007 | // output.success("Success!"); 1008 | // }>(); 1009 | 1010 | return true; 1011 | } 1012 | 1013 | bool Plugin::disable() { 1014 | getSelf().getLogger().info("Disabling..."); 1015 | return true; 1016 | } 1017 | } // namespace plugin 1018 | 1019 | LL_REGISTER_PLUGIN(plugin::Plugin, plugin::instance); -------------------------------------------------------------------------------- /src/Plugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ll/api/plugin/NativePlugin.h" 4 | 5 | namespace plugin { 6 | 7 | class Plugin { 8 | 9 | public: 10 | static Plugin& getInstance(); 11 | 12 | Plugin(ll::plugin::NativePlugin& self) : mSelf(self) {} 13 | 14 | [[nodiscard]] ll::plugin::NativePlugin& getSelf() const { return mSelf; } 15 | 16 | /// @return True if the plugin is loaded successfully. 17 | bool load(); 18 | 19 | /// @return True if the plugin is enabled successfully. 20 | bool enable(); 21 | 22 | /// @return True if the plugin is disabled successfully. 23 | bool disable(); 24 | 25 | // TODO: Implement this method if you need to unload the plugin. 26 | // /// @return True if the plugin is unloaded successfully. 27 | // bool unload(); 28 | 29 | private: 30 | ll::plugin::NativePlugin& mSelf; 31 | }; 32 | 33 | } // namespace my_plugin -------------------------------------------------------------------------------- /src/nonstd/expected.hpp: -------------------------------------------------------------------------------- 1 | // This version targets C++11 and later. 2 | // 3 | // Copyright (C) 2016-2020 Martin Moene. 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | // 8 | // expected lite is based on: 9 | // A proposal to add a utility class to represent expected monad 10 | // by Vicente J. Botet Escriba and Pierre Talbot. http:://wg21.link/p0323 11 | 12 | #ifndef NONSTD_EXPECTED_LITE_HPP 13 | #define NONSTD_EXPECTED_LITE_HPP 14 | 15 | #define expected_lite_MAJOR 0 16 | #define expected_lite_MINOR 6 17 | #define expected_lite_PATCH 3 18 | 19 | #define expected_lite_VERSION expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH) 20 | 21 | #define expected_STRINGIFY( x ) expected_STRINGIFY_( x ) 22 | #define expected_STRINGIFY_( x ) #x 23 | 24 | // expected-lite configuration: 25 | 26 | #define nsel_EXPECTED_DEFAULT 0 27 | #define nsel_EXPECTED_NONSTD 1 28 | #define nsel_EXPECTED_STD 2 29 | 30 | // tweak header support: 31 | 32 | #ifdef __has_include 33 | # if __has_include() 34 | # include 35 | # endif 36 | #define expected_HAVE_TWEAK_HEADER 1 37 | #else 38 | #define expected_HAVE_TWEAK_HEADER 0 39 | //# pragma message("expected.hpp: Note: Tweak header not supported.") 40 | #endif 41 | 42 | // expected selection and configuration: 43 | 44 | #if !defined( nsel_CONFIG_SELECT_EXPECTED ) 45 | # define nsel_CONFIG_SELECT_EXPECTED ( nsel_HAVE_STD_EXPECTED ? nsel_EXPECTED_STD : nsel_EXPECTED_NONSTD ) 46 | #endif 47 | 48 | // Proposal revisions: 49 | // 50 | // DXXXXR0: -- 51 | // N4015 : -2 (2014-05-26) 52 | // N4109 : -1 (2014-06-29) 53 | // P0323R0: 0 (2016-05-28) 54 | // P0323R1: 1 (2016-10-12) 55 | // -------: 56 | // P0323R2: 2 (2017-06-15) 57 | // P0323R3: 3 (2017-10-15) 58 | // P0323R4: 4 (2017-11-26) 59 | // P0323R5: 5 (2018-02-08) 60 | // P0323R6: 6 (2018-04-02) 61 | // P0323R7: 7 (2018-06-22) * 62 | // 63 | // expected-lite uses 2 and higher 64 | 65 | #ifndef nsel_P0323R 66 | # define nsel_P0323R 7 67 | #endif 68 | 69 | // Monadic operations proposal revisions: 70 | // 71 | // P2505R0: 0 (2021-12-12) 72 | // P2505R1: 1 (2022-02-10) 73 | // P2505R2: 2 (2022-04-15) 74 | // P2505R3: 3 (2022-06-05) 75 | // P2505R4: 4 (2022-06-15) 76 | // P2505R5: 5 (2022-09-20) * 77 | // 78 | // expected-lite uses 5 79 | 80 | #ifndef nsel_P2505R 81 | # define nsel_P2505R 5 82 | #endif 83 | 84 | // Control presence of C++ exception handling (try and auto discover): 85 | 86 | #ifndef nsel_CONFIG_NO_EXCEPTIONS 87 | # if defined(_MSC_VER) 88 | # include // for _HAS_EXCEPTIONS 89 | # endif 90 | # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) 91 | # define nsel_CONFIG_NO_EXCEPTIONS 0 92 | # else 93 | # define nsel_CONFIG_NO_EXCEPTIONS 1 94 | # endif 95 | #endif 96 | 97 | // at default use SEH with MSVC for no C++ exceptions 98 | 99 | #ifndef nsel_CONFIG_NO_EXCEPTIONS_SEH 100 | # define nsel_CONFIG_NO_EXCEPTIONS_SEH ( nsel_CONFIG_NO_EXCEPTIONS && _MSC_VER ) 101 | #endif 102 | 103 | // C++ language version detection (C++23 is speculative): 104 | // Note: VC14.0/1900 (VS2015) lacks too much from C++14. 105 | 106 | #ifndef nsel_CPLUSPLUS 107 | # if defined(_MSVC_LANG ) && !defined(__clang__) 108 | # define nsel_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) 109 | # else 110 | # define nsel_CPLUSPLUS __cplusplus 111 | # endif 112 | #endif 113 | 114 | #define nsel_CPP98_OR_GREATER ( nsel_CPLUSPLUS >= 199711L ) 115 | #define nsel_CPP11_OR_GREATER ( nsel_CPLUSPLUS >= 201103L ) 116 | #define nsel_CPP14_OR_GREATER ( nsel_CPLUSPLUS >= 201402L ) 117 | #define nsel_CPP17_OR_GREATER ( nsel_CPLUSPLUS >= 201703L ) 118 | #define nsel_CPP20_OR_GREATER ( nsel_CPLUSPLUS >= 202002L ) 119 | #define nsel_CPP23_OR_GREATER ( nsel_CPLUSPLUS >= 202300L ) 120 | 121 | // Use C++23 std::expected if available and requested: 122 | 123 | #if nsel_CPP23_OR_GREATER && defined(__has_include ) 124 | # if __has_include( ) 125 | # define nsel_HAVE_STD_EXPECTED 1 126 | # else 127 | # define nsel_HAVE_STD_EXPECTED 0 128 | # endif 129 | #else 130 | # define nsel_HAVE_STD_EXPECTED 0 131 | #endif 132 | 133 | #define nsel_USES_STD_EXPECTED ( (nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_STD) || ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_DEFAULT) && nsel_HAVE_STD_EXPECTED) ) 134 | 135 | // 136 | // in_place: code duplicated in any-lite, expected-lite, expected-lite, value-ptr-lite, variant-lite: 137 | // 138 | 139 | #ifndef nonstd_lite_HAVE_IN_PLACE_TYPES 140 | #define nonstd_lite_HAVE_IN_PLACE_TYPES 1 141 | 142 | // C++17 std::in_place in : 143 | 144 | #if nsel_CPP17_OR_GREATER 145 | 146 | #include 147 | 148 | namespace nonstd { 149 | 150 | using std::in_place; 151 | using std::in_place_type; 152 | using std::in_place_index; 153 | using std::in_place_t; 154 | using std::in_place_type_t; 155 | using std::in_place_index_t; 156 | 157 | #define nonstd_lite_in_place_t( T) std::in_place_t 158 | #define nonstd_lite_in_place_type_t( T) std::in_place_type_t 159 | #define nonstd_lite_in_place_index_t(K) std::in_place_index_t 160 | 161 | #define nonstd_lite_in_place( T) std::in_place_t{} 162 | #define nonstd_lite_in_place_type( T) std::in_place_type_t{} 163 | #define nonstd_lite_in_place_index(K) std::in_place_index_t{} 164 | 165 | } // namespace nonstd 166 | 167 | #else // nsel_CPP17_OR_GREATER 168 | 169 | #include 170 | 171 | namespace nonstd { 172 | namespace detail { 173 | 174 | template< class T > 175 | struct in_place_type_tag {}; 176 | 177 | template< std::size_t K > 178 | struct in_place_index_tag {}; 179 | 180 | } // namespace detail 181 | 182 | struct in_place_t {}; 183 | 184 | template< class T > 185 | inline in_place_t in_place( detail::in_place_type_tag = detail::in_place_type_tag() ) 186 | { 187 | return in_place_t(); 188 | } 189 | 190 | template< std::size_t K > 191 | inline in_place_t in_place( detail::in_place_index_tag = detail::in_place_index_tag() ) 192 | { 193 | return in_place_t(); 194 | } 195 | 196 | template< class T > 197 | inline in_place_t in_place_type( detail::in_place_type_tag = detail::in_place_type_tag() ) 198 | { 199 | return in_place_t(); 200 | } 201 | 202 | template< std::size_t K > 203 | inline in_place_t in_place_index( detail::in_place_index_tag = detail::in_place_index_tag() ) 204 | { 205 | return in_place_t(); 206 | } 207 | 208 | // mimic templated typedef: 209 | 210 | #define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) 211 | #define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) 212 | #define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) 213 | 214 | #define nonstd_lite_in_place( T) nonstd::in_place_type 215 | #define nonstd_lite_in_place_type( T) nonstd::in_place_type 216 | #define nonstd_lite_in_place_index(K) nonstd::in_place_index 217 | 218 | } // namespace nonstd 219 | 220 | #endif // nsel_CPP17_OR_GREATER 221 | #endif // nonstd_lite_HAVE_IN_PLACE_TYPES 222 | 223 | // 224 | // Using std::expected: 225 | // 226 | 227 | #if nsel_USES_STD_EXPECTED 228 | 229 | #include 230 | 231 | namespace nonstd { 232 | 233 | using std::expected; 234 | // ... 235 | } 236 | 237 | #else // nsel_USES_STD_EXPECTED 238 | 239 | #include 240 | #include 241 | #include 242 | #include 243 | #include 244 | #include 245 | #include 246 | #include 247 | #include 248 | 249 | // additional includes: 250 | 251 | #if nsel_CONFIG_NO_EXCEPTIONS 252 | # if nsel_CONFIG_NO_EXCEPTIONS_SEH 253 | # include // for ExceptionCodes 254 | # else 255 | // already included: 256 | # endif 257 | #else 258 | # include 259 | #endif 260 | 261 | // C++ feature usage: 262 | 263 | #if nsel_CPP11_OR_GREATER 264 | # define nsel_constexpr constexpr 265 | #else 266 | # define nsel_constexpr /*constexpr*/ 267 | #endif 268 | 269 | #if nsel_CPP14_OR_GREATER 270 | # define nsel_constexpr14 constexpr 271 | #else 272 | # define nsel_constexpr14 /*constexpr*/ 273 | #endif 274 | 275 | #if nsel_CPP17_OR_GREATER 276 | # define nsel_inline17 inline 277 | #else 278 | # define nsel_inline17 /*inline*/ 279 | #endif 280 | 281 | // Compiler versions: 282 | // 283 | // MSVC++ 6.0 _MSC_VER == 1200 nsel_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) 284 | // MSVC++ 7.0 _MSC_VER == 1300 nsel_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) 285 | // MSVC++ 7.1 _MSC_VER == 1310 nsel_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) 286 | // MSVC++ 8.0 _MSC_VER == 1400 nsel_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) 287 | // MSVC++ 9.0 _MSC_VER == 1500 nsel_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) 288 | // MSVC++ 10.0 _MSC_VER == 1600 nsel_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) 289 | // MSVC++ 11.0 _MSC_VER == 1700 nsel_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) 290 | // MSVC++ 12.0 _MSC_VER == 1800 nsel_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) 291 | // MSVC++ 14.0 _MSC_VER == 1900 nsel_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) 292 | // MSVC++ 14.1 _MSC_VER >= 1910 nsel_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) 293 | // MSVC++ 14.2 _MSC_VER >= 1920 nsel_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) 294 | 295 | #if defined(_MSC_VER) && !defined(__clang__) 296 | # define nsel_COMPILER_MSVC_VER (_MSC_VER ) 297 | # define nsel_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) ) 298 | #else 299 | # define nsel_COMPILER_MSVC_VER 0 300 | # define nsel_COMPILER_MSVC_VERSION 0 301 | #endif 302 | 303 | #define nsel_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) 304 | 305 | #if defined(__clang__) 306 | # define nsel_COMPILER_CLANG_VERSION nsel_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) 307 | #else 308 | # define nsel_COMPILER_CLANG_VERSION 0 309 | #endif 310 | 311 | #if defined(__GNUC__) && !defined(__clang__) 312 | # define nsel_COMPILER_GNUC_VERSION nsel_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) 313 | #else 314 | # define nsel_COMPILER_GNUC_VERSION 0 315 | #endif 316 | 317 | // half-open range [lo..hi): 318 | //#define nsel_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) 319 | 320 | // Method enabling 321 | 322 | #define nsel_REQUIRES_0(...) \ 323 | template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > 324 | 325 | #define nsel_REQUIRES_T(...) \ 326 | , typename std::enable_if< (__VA_ARGS__), int >::type = 0 327 | 328 | #define nsel_REQUIRES_R(R, ...) \ 329 | typename std::enable_if< (__VA_ARGS__), R>::type 330 | 331 | #define nsel_REQUIRES_A(...) \ 332 | , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr 333 | 334 | // Presence of language and library features: 335 | 336 | #ifdef _HAS_CPP0X 337 | # define nsel_HAS_CPP0X _HAS_CPP0X 338 | #else 339 | # define nsel_HAS_CPP0X 0 340 | #endif 341 | 342 | //#define nsel_CPP11_140 (nsel_CPP11_OR_GREATER || nsel_COMPILER_MSVC_VER >= 1900) 343 | 344 | // Clang, GNUC, MSVC warning suppression macros: 345 | 346 | #ifdef __clang__ 347 | # pragma clang diagnostic push 348 | #elif defined __GNUC__ 349 | # pragma GCC diagnostic push 350 | #endif // __clang__ 351 | 352 | #if nsel_COMPILER_MSVC_VERSION >= 140 353 | # pragma warning( push ) 354 | # define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(disable: codes) ) 355 | #else 356 | # define nsel_DISABLE_MSVC_WARNINGS(codes) 357 | #endif 358 | 359 | #ifdef __clang__ 360 | # define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") 361 | #elif defined __GNUC__ 362 | # define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") 363 | #elif nsel_COMPILER_MSVC_VERSION >= 140 364 | # define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) ) 365 | #else 366 | # define nsel_RESTORE_WARNINGS() 367 | #endif 368 | 369 | // Suppress the following MSVC (GSL) warnings: 370 | // - C26409: Avoid calling new and delete explicitly, use std::make_unique instead (r.11) 371 | 372 | nsel_DISABLE_MSVC_WARNINGS( 26409 ) 373 | 374 | // 375 | // expected: 376 | // 377 | 378 | namespace nonstd { namespace expected_lite { 379 | 380 | // type traits C++17: 381 | 382 | namespace std17 { 383 | 384 | #if nsel_CPP17_OR_GREATER 385 | 386 | using std::conjunction; 387 | using std::is_swappable; 388 | using std::is_nothrow_swappable; 389 | 390 | #else // nsel_CPP17_OR_GREATER 391 | 392 | namespace detail { 393 | 394 | using std::swap; 395 | 396 | struct is_swappable 397 | { 398 | template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > 399 | static std::true_type test( int /* unused */); 400 | 401 | template< typename > 402 | static std::false_type test(...); 403 | }; 404 | 405 | struct is_nothrow_swappable 406 | { 407 | // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): 408 | 409 | template< typename T > 410 | static constexpr bool satisfies() 411 | { 412 | return noexcept( swap( std::declval(), std::declval() ) ); 413 | } 414 | 415 | template< typename T > 416 | static auto test( int ) -> std::integral_constant()>{} 417 | 418 | template< typename > 419 | static auto test(...) -> std::false_type; 420 | }; 421 | } // namespace detail 422 | 423 | // is [nothrow] swappable: 424 | 425 | template< typename T > 426 | struct is_swappable : decltype( detail::is_swappable::test(0) ){}; 427 | 428 | template< typename T > 429 | struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; 430 | 431 | // conjunction: 432 | 433 | template< typename... > struct conjunction : std::true_type{}; 434 | template< typename B1 > struct conjunction : B1{}; 435 | 436 | template< typename B1, typename... Bn > 437 | struct conjunction : std::conditional, B1>::type{}; 438 | 439 | #endif // nsel_CPP17_OR_GREATER 440 | 441 | } // namespace std17 442 | 443 | // type traits C++20: 444 | 445 | namespace std20 { 446 | 447 | #if defined(__cpp_lib_remove_cvref) 448 | 449 | using std::remove_cvref; 450 | 451 | #else 452 | 453 | template< typename T > 454 | struct remove_cvref 455 | { 456 | typedef typename std::remove_cv< typename std::remove_reference::type >::type type; 457 | }; 458 | 459 | #endif 460 | 461 | } // namespace std20 462 | 463 | // forward declaration: 464 | 465 | template< typename T, typename E > 466 | class expected; 467 | 468 | namespace detail { 469 | 470 | #if nsel_P2505R >= 3 471 | template< typename T > 472 | struct is_expected : std::false_type {}; 473 | 474 | template< typename T, typename E > 475 | struct is_expected< expected< T, E > > : std::true_type {}; 476 | #endif // nsel_P2505R >= 3 477 | 478 | /// discriminated union to hold value or 'error'. 479 | 480 | template< typename T, typename E > 481 | class storage_t_noncopy_nonmove_impl 482 | { 483 | template< typename, typename > friend class nonstd::expected_lite::expected; 484 | 485 | public: 486 | using value_type = T; 487 | using error_type = E; 488 | 489 | // no-op construction 490 | storage_t_noncopy_nonmove_impl() {} 491 | ~storage_t_noncopy_nonmove_impl() {} 492 | 493 | explicit storage_t_noncopy_nonmove_impl( bool has_value ) 494 | : m_has_value( has_value ) 495 | {} 496 | 497 | void construct_value() 498 | { 499 | new( &m_value ) value_type(); 500 | } 501 | 502 | // void construct_value( value_type const & e ) 503 | // { 504 | // new( &m_value ) value_type( e ); 505 | // } 506 | 507 | // void construct_value( value_type && e ) 508 | // { 509 | // new( &m_value ) value_type( std::move( e ) ); 510 | // } 511 | 512 | template< class... Args > 513 | void emplace_value( Args&&... args ) 514 | { 515 | new( &m_value ) value_type( std::forward(args)...); 516 | } 517 | 518 | template< class U, class... Args > 519 | void emplace_value( std::initializer_list il, Args&&... args ) 520 | { 521 | new( &m_value ) value_type( il, std::forward(args)... ); 522 | } 523 | 524 | void destruct_value() 525 | { 526 | m_value.~value_type(); 527 | } 528 | 529 | // void construct_error( error_type const & e ) 530 | // { 531 | // // new( &m_error ) error_type( e ); 532 | // } 533 | 534 | // void construct_error( error_type && e ) 535 | // { 536 | // // new( &m_error ) error_type( std::move( e ) ); 537 | // } 538 | 539 | template< class... Args > 540 | void emplace_error( Args&&... args ) 541 | { 542 | new( &m_error ) error_type( std::forward(args)...); 543 | } 544 | 545 | template< class U, class... Args > 546 | void emplace_error( std::initializer_list il, Args&&... args ) 547 | { 548 | new( &m_error ) error_type( il, std::forward(args)... ); 549 | } 550 | 551 | void destruct_error() 552 | { 553 | m_error.~error_type(); 554 | } 555 | 556 | constexpr value_type const & value() const & 557 | { 558 | return m_value; 559 | } 560 | 561 | value_type & value() & 562 | { 563 | return m_value; 564 | } 565 | 566 | constexpr value_type const && value() const && 567 | { 568 | return std::move( m_value ); 569 | } 570 | 571 | nsel_constexpr14 value_type && value() && 572 | { 573 | return std::move( m_value ); 574 | } 575 | 576 | value_type const * value_ptr() const 577 | { 578 | return &m_value; 579 | } 580 | 581 | value_type * value_ptr() 582 | { 583 | return &m_value; 584 | } 585 | 586 | error_type const & error() const & 587 | { 588 | return m_error; 589 | } 590 | 591 | error_type & error() & 592 | { 593 | return m_error; 594 | } 595 | 596 | constexpr error_type const && error() const && 597 | { 598 | return std::move( m_error ); 599 | } 600 | 601 | nsel_constexpr14 error_type && error() && 602 | { 603 | return std::move( m_error ); 604 | } 605 | 606 | bool has_value() const 607 | { 608 | return m_has_value; 609 | } 610 | 611 | void set_has_value( bool v ) 612 | { 613 | m_has_value = v; 614 | } 615 | 616 | private: 617 | union 618 | { 619 | value_type m_value; 620 | error_type m_error; 621 | }; 622 | 623 | bool m_has_value = false; 624 | }; 625 | 626 | template< typename T, typename E > 627 | class storage_t_impl 628 | { 629 | template< typename, typename > friend class nonstd::expected_lite::expected; 630 | 631 | public: 632 | using value_type = T; 633 | using error_type = E; 634 | 635 | // no-op construction 636 | storage_t_impl() {} 637 | ~storage_t_impl() {} 638 | 639 | explicit storage_t_impl( bool has_value ) 640 | : m_has_value( has_value ) 641 | {} 642 | 643 | void construct_value() 644 | { 645 | new( &m_value ) value_type(); 646 | } 647 | 648 | void construct_value( value_type const & e ) 649 | { 650 | new( &m_value ) value_type( e ); 651 | } 652 | 653 | void construct_value( value_type && e ) 654 | { 655 | new( &m_value ) value_type( std::move( e ) ); 656 | } 657 | 658 | template< class... Args > 659 | void emplace_value( Args&&... args ) 660 | { 661 | new( &m_value ) value_type( std::forward(args)...); 662 | } 663 | 664 | template< class U, class... Args > 665 | void emplace_value( std::initializer_list il, Args&&... args ) 666 | { 667 | new( &m_value ) value_type( il, std::forward(args)... ); 668 | } 669 | 670 | void destruct_value() 671 | { 672 | m_value.~value_type(); 673 | } 674 | 675 | void construct_error( error_type const & e ) 676 | { 677 | new( &m_error ) error_type( e ); 678 | } 679 | 680 | void construct_error( error_type && e ) 681 | { 682 | new( &m_error ) error_type( std::move( e ) ); 683 | } 684 | 685 | template< class... Args > 686 | void emplace_error( Args&&... args ) 687 | { 688 | new( &m_error ) error_type( std::forward(args)...); 689 | } 690 | 691 | template< class U, class... Args > 692 | void emplace_error( std::initializer_list il, Args&&... args ) 693 | { 694 | new( &m_error ) error_type( il, std::forward(args)... ); 695 | } 696 | 697 | void destruct_error() 698 | { 699 | m_error.~error_type(); 700 | } 701 | 702 | constexpr value_type const & value() const & 703 | { 704 | return m_value; 705 | } 706 | 707 | value_type & value() & 708 | { 709 | return m_value; 710 | } 711 | 712 | constexpr value_type const && value() const && 713 | { 714 | return std::move( m_value ); 715 | } 716 | 717 | nsel_constexpr14 value_type && value() && 718 | { 719 | return std::move( m_value ); 720 | } 721 | 722 | value_type const * value_ptr() const 723 | { 724 | return &m_value; 725 | } 726 | 727 | value_type * value_ptr() 728 | { 729 | return &m_value; 730 | } 731 | 732 | error_type const & error() const & 733 | { 734 | return m_error; 735 | } 736 | 737 | error_type & error() & 738 | { 739 | return m_error; 740 | } 741 | 742 | constexpr error_type const && error() const && 743 | { 744 | return std::move( m_error ); 745 | } 746 | 747 | nsel_constexpr14 error_type && error() && 748 | { 749 | return std::move( m_error ); 750 | } 751 | 752 | bool has_value() const 753 | { 754 | return m_has_value; 755 | } 756 | 757 | void set_has_value( bool v ) 758 | { 759 | m_has_value = v; 760 | } 761 | 762 | private: 763 | union 764 | { 765 | value_type m_value; 766 | error_type m_error; 767 | }; 768 | 769 | bool m_has_value = false; 770 | }; 771 | 772 | /// discriminated union to hold only 'error'. 773 | 774 | template< typename E > 775 | struct storage_t_impl 776 | { 777 | template< typename, typename > friend class nonstd::expected_lite::expected; 778 | 779 | public: 780 | using value_type = void; 781 | using error_type = E; 782 | 783 | // no-op construction 784 | storage_t_impl() {} 785 | ~storage_t_impl() {} 786 | 787 | explicit storage_t_impl( bool has_value ) 788 | : m_has_value( has_value ) 789 | {} 790 | 791 | void construct_error( error_type const & e ) 792 | { 793 | new( &m_error ) error_type( e ); 794 | } 795 | 796 | void construct_error( error_type && e ) 797 | { 798 | new( &m_error ) error_type( std::move( e ) ); 799 | } 800 | 801 | template< class... Args > 802 | void emplace_error( Args&&... args ) 803 | { 804 | new( &m_error ) error_type( std::forward(args)...); 805 | } 806 | 807 | template< class U, class... Args > 808 | void emplace_error( std::initializer_list il, Args&&... args ) 809 | { 810 | new( &m_error ) error_type( il, std::forward(args)... ); 811 | } 812 | 813 | void destruct_error() 814 | { 815 | m_error.~error_type(); 816 | } 817 | 818 | error_type const & error() const & 819 | { 820 | return m_error; 821 | } 822 | 823 | error_type & error() & 824 | { 825 | return m_error; 826 | } 827 | 828 | constexpr error_type const && error() const && 829 | { 830 | return std::move( m_error ); 831 | } 832 | 833 | nsel_constexpr14 error_type && error() && 834 | { 835 | return std::move( m_error ); 836 | } 837 | 838 | bool has_value() const 839 | { 840 | return m_has_value; 841 | } 842 | 843 | void set_has_value( bool v ) 844 | { 845 | m_has_value = v; 846 | } 847 | 848 | private: 849 | union 850 | { 851 | char m_dummy; 852 | error_type m_error; 853 | }; 854 | 855 | bool m_has_value = false; 856 | }; 857 | 858 | template< typename T, typename E, bool isConstructable, bool isMoveable > 859 | class storage_t 860 | { 861 | public: 862 | }; 863 | 864 | template< typename T, typename E > 865 | class storage_t : public storage_t_noncopy_nonmove_impl 866 | { 867 | public: 868 | storage_t() = default; 869 | ~storage_t() = default; 870 | 871 | explicit storage_t( bool has_value ) 872 | : storage_t_noncopy_nonmove_impl( has_value ) 873 | {} 874 | 875 | storage_t( storage_t const & other ) = delete; 876 | storage_t( storage_t && other ) = delete; 877 | 878 | }; 879 | 880 | template< typename T, typename E > 881 | class storage_t : public storage_t_impl 882 | { 883 | public: 884 | storage_t() = default; 885 | ~storage_t() = default; 886 | 887 | explicit storage_t( bool has_value ) 888 | : storage_t_impl( has_value ) 889 | {} 890 | 891 | storage_t( storage_t const & other ) 892 | : storage_t_impl( other.has_value() ) 893 | { 894 | if ( this->has_value() ) this->construct_value( other.value() ); 895 | else this->construct_error( other.error() ); 896 | } 897 | 898 | storage_t(storage_t && other ) 899 | : storage_t_impl( other.has_value() ) 900 | { 901 | if ( this->has_value() ) this->construct_value( std::move( other.value() ) ); 902 | else this->construct_error( std::move( other.error() ) ); 903 | } 904 | }; 905 | 906 | template< typename E > 907 | class storage_t : public storage_t_impl 908 | { 909 | public: 910 | storage_t() = default; 911 | ~storage_t() = default; 912 | 913 | explicit storage_t( bool has_value ) 914 | : storage_t_impl( has_value ) 915 | {} 916 | 917 | storage_t( storage_t const & other ) 918 | : storage_t_impl( other.has_value() ) 919 | { 920 | if ( this->has_value() ) ; 921 | else this->construct_error( other.error() ); 922 | } 923 | 924 | storage_t(storage_t && other ) 925 | : storage_t_impl( other.has_value() ) 926 | { 927 | if ( this->has_value() ) ; 928 | else this->construct_error( std::move( other.error() ) ); 929 | } 930 | }; 931 | 932 | template< typename T, typename E > 933 | class storage_t : public storage_t_impl 934 | { 935 | public: 936 | storage_t() = default; 937 | ~storage_t() = default; 938 | 939 | explicit storage_t( bool has_value ) 940 | : storage_t_impl( has_value ) 941 | {} 942 | 943 | storage_t( storage_t const & other ) 944 | : storage_t_impl(other.has_value()) 945 | { 946 | if ( this->has_value() ) this->construct_value( other.value() ); 947 | else this->construct_error( other.error() ); 948 | } 949 | 950 | storage_t( storage_t && other ) = delete; 951 | }; 952 | 953 | template< typename E > 954 | class storage_t : public storage_t_impl 955 | { 956 | public: 957 | storage_t() = default; 958 | ~storage_t() = default; 959 | 960 | explicit storage_t( bool has_value ) 961 | : storage_t_impl( has_value ) 962 | {} 963 | 964 | storage_t( storage_t const & other ) 965 | : storage_t_impl(other.has_value()) 966 | { 967 | if ( this->has_value() ) ; 968 | else this->construct_error( other.error() ); 969 | } 970 | 971 | storage_t( storage_t && other ) = delete; 972 | }; 973 | 974 | template< typename T, typename E > 975 | class storage_t : public storage_t_impl 976 | { 977 | public: 978 | storage_t() = default; 979 | ~storage_t() = default; 980 | 981 | explicit storage_t( bool has_value ) 982 | : storage_t_impl( has_value ) 983 | {} 984 | 985 | storage_t( storage_t const & other ) = delete; 986 | 987 | storage_t( storage_t && other ) 988 | : storage_t_impl( other.has_value() ) 989 | { 990 | if ( this->has_value() ) this->construct_value( std::move( other.value() ) ); 991 | else this->construct_error( std::move( other.error() ) ); 992 | } 993 | }; 994 | 995 | template< typename E > 996 | class storage_t : public storage_t_impl 997 | { 998 | public: 999 | storage_t() = default; 1000 | ~storage_t() = default; 1001 | 1002 | explicit storage_t( bool has_value ) 1003 | : storage_t_impl( has_value ) 1004 | {} 1005 | 1006 | storage_t( storage_t const & other ) = delete; 1007 | 1008 | storage_t( storage_t && other ) 1009 | : storage_t_impl( other.has_value() ) 1010 | { 1011 | if ( this->has_value() ) ; 1012 | else this->construct_error( std::move( other.error() ) ); 1013 | } 1014 | }; 1015 | 1016 | #if nsel_P2505R >= 3 1017 | // C++11 invoke implementation 1018 | template< typename > 1019 | struct is_reference_wrapper : std::false_type {}; 1020 | template< typename T > 1021 | struct is_reference_wrapper< std::reference_wrapper< T > > : std::true_type {}; 1022 | 1023 | template< typename FnT, typename ClassT, typename ObjectT, typename... Args 1024 | nsel_REQUIRES_T( 1025 | std::is_function::value 1026 | && ( std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value 1027 | || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value ) 1028 | ) 1029 | > 1030 | nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) 1031 | noexcept( noexcept( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ) ) ) 1032 | -> decltype( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )...) ) 1033 | { 1034 | return (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ); 1035 | } 1036 | 1037 | template< typename FnT, typename ClassT, typename ObjectT, typename... Args 1038 | nsel_REQUIRES_T( 1039 | std::is_function::value 1040 | && is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value 1041 | ) 1042 | > 1043 | nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) 1044 | noexcept( noexcept( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) ) 1045 | -> decltype( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) 1046 | { 1047 | return (obj.get().*memfnptr)( std::forward< Args >( args ) ... ); 1048 | } 1049 | 1050 | template< typename FnT, typename ClassT, typename ObjectT, typename... Args 1051 | nsel_REQUIRES_T( 1052 | std::is_function::value 1053 | && !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value 1054 | && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value 1055 | && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value 1056 | ) 1057 | > 1058 | nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) 1059 | noexcept( noexcept( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) ) 1060 | -> decltype( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) 1061 | { 1062 | return ((*std::forward(obj)).*memfnptr)( std::forward< Args >( args ) ... ); 1063 | } 1064 | 1065 | template< typename MemberT, typename ClassT, typename ObjectT 1066 | nsel_REQUIRES_T( 1067 | std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value 1068 | || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value 1069 | ) 1070 | > 1071 | nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) 1072 | noexcept( noexcept( std::forward< ObjectT >( obj ).*memobjptr ) ) 1073 | -> decltype( std::forward< ObjectT >( obj ).*memobjptr ) 1074 | { 1075 | return std::forward< ObjectT >( obj ).*memobjptr; 1076 | } 1077 | 1078 | template< typename MemberT, typename ClassT, typename ObjectT 1079 | nsel_REQUIRES_T( 1080 | is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value 1081 | ) 1082 | > 1083 | nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) 1084 | noexcept( noexcept( obj.get().*memobjptr ) ) 1085 | -> decltype( obj.get().*memobjptr ) 1086 | { 1087 | return obj.get().*memobjptr; 1088 | } 1089 | 1090 | template< typename MemberT, typename ClassT, typename ObjectT 1091 | nsel_REQUIRES_T( 1092 | !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value 1093 | && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value 1094 | && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value 1095 | ) 1096 | > 1097 | nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) 1098 | noexcept( noexcept( (*std::forward< ObjectT >( obj )).*memobjptr ) ) 1099 | -> decltype( (*std::forward< ObjectT >( obj )).*memobjptr ) 1100 | { 1101 | return (*std::forward< ObjectT >( obj )).*memobjptr; 1102 | } 1103 | 1104 | template< typename F, typename... Args 1105 | nsel_REQUIRES_T( 1106 | std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value 1107 | ) 1108 | > 1109 | nsel_constexpr auto invoke( F && f, Args && ... args ) 1110 | noexcept( noexcept( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) ) 1111 | -> decltype( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) 1112 | { 1113 | return invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ); 1114 | } 1115 | 1116 | template< typename F, typename... Args 1117 | nsel_REQUIRES_T( 1118 | std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value 1119 | ) 1120 | > 1121 | nsel_constexpr auto invoke( F && f, Args && ... args ) 1122 | noexcept( noexcept( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) ) 1123 | -> decltype( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) 1124 | { 1125 | return invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ); 1126 | } 1127 | 1128 | template< typename F, typename... Args 1129 | nsel_REQUIRES_T( 1130 | !std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value 1131 | && !std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value 1132 | ) 1133 | > 1134 | nsel_constexpr auto invoke( F && f, Args && ... args ) 1135 | noexcept( noexcept( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) ) 1136 | -> decltype( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) 1137 | { 1138 | return std::forward< F >( f )( std::forward< Args >( args ) ... ); 1139 | } 1140 | 1141 | template< typename F, typename ... Args > 1142 | using invoke_result_nocvref_t = typename std20::remove_cvref< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type; 1143 | 1144 | #if nsel_P2505R >= 5 1145 | template< typename F, typename ... Args > 1146 | using transform_invoke_result_t = typename std::remove_cv< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type; 1147 | #else 1148 | template< typename F, typename ... Args > 1149 | using transform_invoke_result_t = invoke_result_nocvref_t 1150 | #endif // nsel_P2505R >= 5 1151 | 1152 | template< typename T > 1153 | struct valid_expected_value_type : std::integral_constant< bool, std::is_destructible< T >::value && !std::is_reference< T >::value && !std::is_array< T >::value > {}; 1154 | 1155 | #endif // nsel_P2505R >= 3 1156 | } // namespace detail 1157 | 1158 | /// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also use aliased type unexpected. 1159 | 1160 | #if nsel_P0323R <= 2 1161 | template< typename E = std::exception_ptr > 1162 | class unexpected_type 1163 | #else 1164 | template< typename E > 1165 | class unexpected_type 1166 | #endif // nsel_P0323R 1167 | { 1168 | public: 1169 | using error_type = E; 1170 | 1171 | // x.x.5.2.1 Constructors 1172 | 1173 | // unexpected_type() = delete; 1174 | 1175 | constexpr unexpected_type( unexpected_type const & ) = default; 1176 | constexpr unexpected_type( unexpected_type && ) = default; 1177 | 1178 | template< typename... Args 1179 | nsel_REQUIRES_T( 1180 | std::is_constructible::value 1181 | ) 1182 | > 1183 | constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), Args &&... args ) 1184 | : m_error( std::forward( args )...) 1185 | {} 1186 | 1187 | template< typename U, typename... Args 1188 | nsel_REQUIRES_T( 1189 | std::is_constructible, Args&&...>::value 1190 | ) 1191 | > 1192 | constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), std::initializer_list il, Args &&... args ) 1193 | : m_error( il, std::forward( args )...) 1194 | {} 1195 | 1196 | template< typename E2 1197 | nsel_REQUIRES_T( 1198 | std::is_constructible::value 1199 | && !std::is_same< typename std20::remove_cvref::type, nonstd_lite_in_place_t(E2) >::value 1200 | && !std::is_same< typename std20::remove_cvref::type, unexpected_type >::value 1201 | ) 1202 | > 1203 | constexpr explicit unexpected_type( E2 && error ) 1204 | : m_error( std::forward( error ) ) 1205 | {} 1206 | 1207 | template< typename E2 1208 | nsel_REQUIRES_T( 1209 | std::is_constructible< E, E2>::value 1210 | && !std::is_constructible & >::value 1211 | && !std::is_constructible >::value 1212 | && !std::is_constructible const & >::value 1213 | && !std::is_constructible const >::value 1214 | && !std::is_convertible< unexpected_type &, E>::value 1215 | && !std::is_convertible< unexpected_type , E>::value 1216 | && !std::is_convertible< unexpected_type const &, E>::value 1217 | && !std::is_convertible< unexpected_type const , E>::value 1218 | && !std::is_convertible< E2 const &, E>::value /*=> explicit */ 1219 | ) 1220 | > 1221 | constexpr explicit unexpected_type( unexpected_type const & error ) 1222 | : m_error( E{ error.value() } ) 1223 | {} 1224 | 1225 | template< typename E2 1226 | nsel_REQUIRES_T( 1227 | std::is_constructible< E, E2>::value 1228 | && !std::is_constructible & >::value 1229 | && !std::is_constructible >::value 1230 | && !std::is_constructible const & >::value 1231 | && !std::is_constructible const >::value 1232 | && !std::is_convertible< unexpected_type &, E>::value 1233 | && !std::is_convertible< unexpected_type , E>::value 1234 | && !std::is_convertible< unexpected_type const &, E>::value 1235 | && !std::is_convertible< unexpected_type const , E>::value 1236 | && std::is_convertible< E2 const &, E>::value /*=> explicit */ 1237 | ) 1238 | > 1239 | constexpr /*non-explicit*/ unexpected_type( unexpected_type const & error ) 1240 | : m_error( error.value() ) 1241 | {} 1242 | 1243 | template< typename E2 1244 | nsel_REQUIRES_T( 1245 | std::is_constructible< E, E2>::value 1246 | && !std::is_constructible & >::value 1247 | && !std::is_constructible >::value 1248 | && !std::is_constructible const & >::value 1249 | && !std::is_constructible const >::value 1250 | && !std::is_convertible< unexpected_type &, E>::value 1251 | && !std::is_convertible< unexpected_type , E>::value 1252 | && !std::is_convertible< unexpected_type const &, E>::value 1253 | && !std::is_convertible< unexpected_type const , E>::value 1254 | && !std::is_convertible< E2 const &, E>::value /*=> explicit */ 1255 | ) 1256 | > 1257 | constexpr explicit unexpected_type( unexpected_type && error ) 1258 | : m_error( E{ std::move( error.value() ) } ) 1259 | {} 1260 | 1261 | template< typename E2 1262 | nsel_REQUIRES_T( 1263 | std::is_constructible< E, E2>::value 1264 | && !std::is_constructible & >::value 1265 | && !std::is_constructible >::value 1266 | && !std::is_constructible const & >::value 1267 | && !std::is_constructible const >::value 1268 | && !std::is_convertible< unexpected_type &, E>::value 1269 | && !std::is_convertible< unexpected_type , E>::value 1270 | && !std::is_convertible< unexpected_type const &, E>::value 1271 | && !std::is_convertible< unexpected_type const , E>::value 1272 | && std::is_convertible< E2 const &, E>::value /*=> non-explicit */ 1273 | ) 1274 | > 1275 | constexpr /*non-explicit*/ unexpected_type( unexpected_type && error ) 1276 | : m_error( std::move( error.value() ) ) 1277 | {} 1278 | 1279 | // x.x.5.2.2 Assignment 1280 | 1281 | nsel_constexpr14 unexpected_type& operator=( unexpected_type const & ) = default; 1282 | nsel_constexpr14 unexpected_type& operator=( unexpected_type && ) = default; 1283 | 1284 | template< typename E2 = E > 1285 | nsel_constexpr14 unexpected_type & operator=( unexpected_type const & other ) 1286 | { 1287 | unexpected_type{ other.value() }.swap( *this ); 1288 | return *this; 1289 | } 1290 | 1291 | template< typename E2 = E > 1292 | nsel_constexpr14 unexpected_type & operator=( unexpected_type && other ) 1293 | { 1294 | unexpected_type{ std::move( other.value() ) }.swap( *this ); 1295 | return *this; 1296 | } 1297 | 1298 | // x.x.5.2.3 Observers 1299 | 1300 | nsel_constexpr14 E & value() & noexcept 1301 | { 1302 | return m_error; 1303 | } 1304 | 1305 | constexpr E const & value() const & noexcept 1306 | { 1307 | return m_error; 1308 | } 1309 | 1310 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 1311 | 1312 | nsel_constexpr14 E && value() && noexcept 1313 | { 1314 | return std::move( m_error ); 1315 | } 1316 | 1317 | constexpr E const && value() const && noexcept 1318 | { 1319 | return std::move( m_error ); 1320 | } 1321 | 1322 | #endif 1323 | 1324 | // x.x.5.2.4 Swap 1325 | 1326 | template< typename U=E > 1327 | nsel_REQUIRES_R( void, 1328 | std17::is_swappable::value 1329 | ) 1330 | swap( unexpected_type & other ) noexcept ( 1331 | std17::is_nothrow_swappable::value 1332 | ) 1333 | { 1334 | using std::swap; 1335 | swap( m_error, other.m_error ); 1336 | } 1337 | 1338 | // TODO: ??? unexpected_type: in-class friend operator==, != 1339 | 1340 | private: 1341 | error_type m_error; 1342 | }; 1343 | 1344 | #if nsel_CPP17_OR_GREATER 1345 | 1346 | /// template deduction guide: 1347 | 1348 | template< typename E > 1349 | unexpected_type( E ) -> unexpected_type< E >; 1350 | 1351 | #endif 1352 | 1353 | /// class unexpected_type, std::exception_ptr specialization (P0323R2) 1354 | 1355 | #if !nsel_CONFIG_NO_EXCEPTIONS 1356 | #if nsel_P0323R <= 2 1357 | 1358 | // TODO: Should expected be specialized for particular E types such as exception_ptr and how? 1359 | // See p0323r7 2.1. Ergonomics, http://wg21.link/p0323 1360 | template<> 1361 | class unexpected_type< std::exception_ptr > 1362 | { 1363 | public: 1364 | using error_type = std::exception_ptr; 1365 | 1366 | unexpected_type() = delete; 1367 | 1368 | ~unexpected_type(){} 1369 | 1370 | explicit unexpected_type( std::exception_ptr const & error ) 1371 | : m_error( error ) 1372 | {} 1373 | 1374 | explicit unexpected_type(std::exception_ptr && error ) 1375 | : m_error( std::move( error ) ) 1376 | {} 1377 | 1378 | template< typename E > 1379 | explicit unexpected_type( E error ) 1380 | : m_error( std::make_exception_ptr( error ) ) 1381 | {} 1382 | 1383 | std::exception_ptr const & value() const 1384 | { 1385 | return m_error; 1386 | } 1387 | 1388 | std::exception_ptr & value() 1389 | { 1390 | return m_error; 1391 | } 1392 | 1393 | private: 1394 | std::exception_ptr m_error; 1395 | }; 1396 | 1397 | #endif // nsel_P0323R 1398 | #endif // !nsel_CONFIG_NO_EXCEPTIONS 1399 | 1400 | /// x.x.4, Unexpected equality operators 1401 | 1402 | template< typename E1, typename E2 > 1403 | constexpr bool operator==( unexpected_type const & x, unexpected_type const & y ) 1404 | { 1405 | return x.value() == y.value(); 1406 | } 1407 | 1408 | template< typename E1, typename E2 > 1409 | constexpr bool operator!=( unexpected_type const & x, unexpected_type const & y ) 1410 | { 1411 | return ! ( x == y ); 1412 | } 1413 | 1414 | #if nsel_P0323R <= 2 1415 | 1416 | template< typename E > 1417 | constexpr bool operator<( unexpected_type const & x, unexpected_type const & y ) 1418 | { 1419 | return x.value() < y.value(); 1420 | } 1421 | 1422 | template< typename E > 1423 | constexpr bool operator>( unexpected_type const & x, unexpected_type const & y ) 1424 | { 1425 | return ( y < x ); 1426 | } 1427 | 1428 | template< typename E > 1429 | constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) 1430 | { 1431 | return ! ( y < x ); 1432 | } 1433 | 1434 | template< typename E > 1435 | constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) 1436 | { 1437 | return ! ( x < y ); 1438 | } 1439 | 1440 | #endif // nsel_P0323R 1441 | 1442 | /// x.x.5 Specialized algorithms 1443 | 1444 | template< typename E 1445 | nsel_REQUIRES_T( 1446 | std17::is_swappable::value 1447 | ) 1448 | > 1449 | void swap( unexpected_type & x, unexpected_type & y) noexcept ( noexcept ( x.swap(y) ) ) 1450 | { 1451 | x.swap( y ); 1452 | } 1453 | 1454 | #if nsel_P0323R <= 2 1455 | 1456 | // unexpected: relational operators for std::exception_ptr: 1457 | 1458 | inline constexpr bool operator<( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) 1459 | { 1460 | return false; 1461 | } 1462 | 1463 | inline constexpr bool operator>( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) 1464 | { 1465 | return false; 1466 | } 1467 | 1468 | inline constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) 1469 | { 1470 | return ( x == y ); 1471 | } 1472 | 1473 | inline constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) 1474 | { 1475 | return ( x == y ); 1476 | } 1477 | 1478 | #endif // nsel_P0323R 1479 | 1480 | // unexpected: traits 1481 | 1482 | #if nsel_P0323R <= 3 1483 | 1484 | template< typename E> 1485 | struct is_unexpected : std::false_type {}; 1486 | 1487 | template< typename E> 1488 | struct is_unexpected< unexpected_type > : std::true_type {}; 1489 | 1490 | #endif // nsel_P0323R 1491 | 1492 | // unexpected: factory 1493 | 1494 | // keep make_unexpected() removed in p0323r2 for pre-C++17: 1495 | 1496 | template< typename E> 1497 | nsel_constexpr14 auto 1498 | make_unexpected( E && value ) -> unexpected_type< typename std::decay::type > 1499 | { 1500 | return unexpected_type< typename std::decay::type >( std::forward(value) ); 1501 | } 1502 | 1503 | #if nsel_P0323R <= 3 1504 | 1505 | /*nsel_constexpr14*/ auto inline 1506 | make_unexpected_from_current_exception() -> unexpected_type< std::exception_ptr > 1507 | { 1508 | return unexpected_type< std::exception_ptr >( std::current_exception() ); 1509 | } 1510 | 1511 | #endif // nsel_P0323R 1512 | 1513 | /// x.x.6, x.x.7 expected access error 1514 | 1515 | template< typename E > 1516 | class bad_expected_access; 1517 | 1518 | /// x.x.7 bad_expected_access: expected access error 1519 | 1520 | template <> 1521 | class bad_expected_access< void > : public std::exception 1522 | { 1523 | public: 1524 | explicit bad_expected_access() 1525 | : std::exception() 1526 | {} 1527 | }; 1528 | 1529 | /// x.x.6 bad_expected_access: expected access error 1530 | 1531 | #if !nsel_CONFIG_NO_EXCEPTIONS 1532 | 1533 | template< typename E > 1534 | class bad_expected_access : public bad_expected_access< void > 1535 | { 1536 | public: 1537 | using error_type = E; 1538 | 1539 | explicit bad_expected_access( error_type error ) 1540 | : m_error( error ) 1541 | {} 1542 | 1543 | virtual char const * what() const noexcept override 1544 | { 1545 | return "bad_expected_access"; 1546 | } 1547 | 1548 | nsel_constexpr14 error_type & error() & 1549 | { 1550 | return m_error; 1551 | } 1552 | 1553 | constexpr error_type const & error() const & 1554 | { 1555 | return m_error; 1556 | } 1557 | 1558 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 1559 | 1560 | nsel_constexpr14 error_type && error() && 1561 | { 1562 | return std::move( m_error ); 1563 | } 1564 | 1565 | constexpr error_type const && error() const && 1566 | { 1567 | return std::move( m_error ); 1568 | } 1569 | 1570 | #endif 1571 | 1572 | private: 1573 | error_type m_error; 1574 | }; 1575 | 1576 | #endif // nsel_CONFIG_NO_EXCEPTIONS 1577 | 1578 | /// x.x.8 unexpect tag, in_place_unexpected tag: construct an error 1579 | 1580 | struct unexpect_t{}; 1581 | using in_place_unexpected_t = unexpect_t; 1582 | 1583 | nsel_inline17 constexpr unexpect_t unexpect{}; 1584 | nsel_inline17 constexpr unexpect_t in_place_unexpected{}; 1585 | 1586 | /// class error_traits 1587 | 1588 | #if nsel_CONFIG_NO_EXCEPTIONS 1589 | 1590 | namespace detail { 1591 | inline bool text( char const * /*text*/ ) { return true; } 1592 | } 1593 | 1594 | template< typename Error > 1595 | struct error_traits 1596 | { 1597 | static void rethrow( Error const & /*e*/ ) 1598 | { 1599 | #if nsel_CONFIG_NO_EXCEPTIONS_SEH 1600 | RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); 1601 | #else 1602 | assert( false && detail::text("throw bad_expected_access{ e };") ); 1603 | #endif 1604 | } 1605 | }; 1606 | 1607 | template<> 1608 | struct error_traits< std::exception_ptr > 1609 | { 1610 | static void rethrow( std::exception_ptr const & /*e*/ ) 1611 | { 1612 | #if nsel_CONFIG_NO_EXCEPTIONS_SEH 1613 | RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); 1614 | #else 1615 | assert( false && detail::text("throw bad_expected_access{ e };") ); 1616 | #endif 1617 | } 1618 | }; 1619 | 1620 | template<> 1621 | struct error_traits< std::error_code > 1622 | { 1623 | static void rethrow( std::error_code const & /*e*/ ) 1624 | { 1625 | #if nsel_CONFIG_NO_EXCEPTIONS_SEH 1626 | RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL ); 1627 | #else 1628 | assert( false && detail::text("throw std::system_error( e );") ); 1629 | #endif 1630 | } 1631 | }; 1632 | 1633 | #else // nsel_CONFIG_NO_EXCEPTIONS 1634 | 1635 | template< typename Error > 1636 | struct error_traits 1637 | { 1638 | static void rethrow( Error const & e ) 1639 | { 1640 | throw bad_expected_access{ e }; 1641 | } 1642 | }; 1643 | 1644 | template<> 1645 | struct error_traits< std::exception_ptr > 1646 | { 1647 | static void rethrow( std::exception_ptr const & e ) 1648 | { 1649 | std::rethrow_exception( e ); 1650 | } 1651 | }; 1652 | 1653 | template<> 1654 | struct error_traits< std::error_code > 1655 | { 1656 | static void rethrow( std::error_code const & e ) 1657 | { 1658 | throw std::system_error( e ); 1659 | } 1660 | }; 1661 | 1662 | #endif // nsel_CONFIG_NO_EXCEPTIONS 1663 | 1664 | #if nsel_P2505R >= 3 1665 | namespace detail { 1666 | 1667 | // from https://en.cppreference.com/w/cpp/utility/expected/unexpected: 1668 | // "the type of the unexpected value. The type must not be an array type, a non-object type, a specialization of std::unexpected, or a cv-qualified type." 1669 | template< typename T > 1670 | struct valid_unexpected_type : std::integral_constant< bool, 1671 | std::is_same< T, typename std20::remove_cvref< T >::type >::value 1672 | && std::is_object< T >::value 1673 | && !std::is_array< T >::value 1674 | > {}; 1675 | 1676 | template< typename T > 1677 | struct valid_unexpected_type< unexpected_type< T > > : std::false_type {}; 1678 | 1679 | } // namespace detail 1680 | #endif // nsel_P2505R >= 3 1681 | 1682 | } // namespace expected_lite 1683 | 1684 | // provide nonstd::unexpected_type: 1685 | 1686 | using expected_lite::unexpected_type; 1687 | 1688 | namespace expected_lite { 1689 | 1690 | /// class expected 1691 | 1692 | #if nsel_P0323R <= 2 1693 | template< typename T, typename E = std::exception_ptr > 1694 | class expected 1695 | #else 1696 | template< typename T, typename E > 1697 | class expected 1698 | #endif // nsel_P0323R 1699 | { 1700 | private: 1701 | template< typename, typename > friend class expected; 1702 | 1703 | public: 1704 | using value_type = T; 1705 | using error_type = E; 1706 | using unexpected_type = nonstd::unexpected_type; 1707 | 1708 | template< typename U > 1709 | struct rebind 1710 | { 1711 | using type = expected; 1712 | }; 1713 | 1714 | // x.x.4.1 constructors 1715 | 1716 | nsel_REQUIRES_0( 1717 | std::is_default_constructible::value 1718 | ) 1719 | nsel_constexpr14 expected() 1720 | : contained( true ) 1721 | { 1722 | contained.construct_value(); 1723 | } 1724 | 1725 | nsel_constexpr14 expected( expected const & ) = default; 1726 | nsel_constexpr14 expected( expected && ) = default; 1727 | 1728 | template< typename U, typename G 1729 | nsel_REQUIRES_T( 1730 | std::is_constructible< T, U const &>::value 1731 | && std::is_constructible::value 1732 | && !std::is_constructible & >::value 1733 | && !std::is_constructible && >::value 1734 | && !std::is_constructible const & >::value 1735 | && !std::is_constructible const && >::value 1736 | && !std::is_convertible< expected & , T>::value 1737 | && !std::is_convertible< expected &&, T>::value 1738 | && !std::is_convertible< expected const & , T>::value 1739 | && !std::is_convertible< expected const &&, T>::value 1740 | && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ 1741 | ) 1742 | > 1743 | nsel_constexpr14 explicit expected( expected const & other ) 1744 | : contained( other.has_value() ) 1745 | { 1746 | if ( has_value() ) contained.construct_value( T{ other.contained.value() } ); 1747 | else contained.construct_error( E{ other.contained.error() } ); 1748 | } 1749 | 1750 | template< typename U, typename G 1751 | nsel_REQUIRES_T( 1752 | std::is_constructible< T, U const &>::value 1753 | && std::is_constructible::value 1754 | && !std::is_constructible & >::value 1755 | && !std::is_constructible && >::value 1756 | && !std::is_constructible const & >::value 1757 | && !std::is_constructible const && >::value 1758 | && !std::is_convertible< expected & , T>::value 1759 | && !std::is_convertible< expected &&, T>::value 1760 | && !std::is_convertible< expected const &, T>::value 1761 | && !std::is_convertible< expected const &&, T>::value 1762 | && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> non-explicit */ 1763 | ) 1764 | > 1765 | nsel_constexpr14 /*non-explicit*/ expected( expected const & other ) 1766 | : contained( other.has_value() ) 1767 | { 1768 | if ( has_value() ) contained.construct_value( other.contained.value() ); 1769 | else contained.construct_error( other.contained.error() ); 1770 | } 1771 | 1772 | template< typename U, typename G 1773 | nsel_REQUIRES_T( 1774 | std::is_constructible< T, U>::value 1775 | && std::is_constructible::value 1776 | && !std::is_constructible & >::value 1777 | && !std::is_constructible && >::value 1778 | && !std::is_constructible const & >::value 1779 | && !std::is_constructible const && >::value 1780 | && !std::is_convertible< expected & , T>::value 1781 | && !std::is_convertible< expected &&, T>::value 1782 | && !std::is_convertible< expected const & , T>::value 1783 | && !std::is_convertible< expected const &&, T>::value 1784 | && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ 1785 | ) 1786 | > 1787 | nsel_constexpr14 explicit expected( expected && other ) 1788 | : contained( other.has_value() ) 1789 | { 1790 | if ( has_value() ) contained.construct_value( T{ std::move( other.contained.value() ) } ); 1791 | else contained.construct_error( E{ std::move( other.contained.error() ) } ); 1792 | } 1793 | 1794 | template< typename U, typename G 1795 | nsel_REQUIRES_T( 1796 | std::is_constructible< T, U>::value 1797 | && std::is_constructible::value 1798 | && !std::is_constructible & >::value 1799 | && !std::is_constructible && >::value 1800 | && !std::is_constructible const & >::value 1801 | && !std::is_constructible const && >::value 1802 | && !std::is_convertible< expected & , T>::value 1803 | && !std::is_convertible< expected &&, T>::value 1804 | && !std::is_convertible< expected const & , T>::value 1805 | && !std::is_convertible< expected const &&, T>::value 1806 | && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> non-explicit */ 1807 | ) 1808 | > 1809 | nsel_constexpr14 /*non-explicit*/ expected( expected && other ) 1810 | : contained( other.has_value() ) 1811 | { 1812 | if ( has_value() ) contained.construct_value( std::move( other.contained.value() ) ); 1813 | else contained.construct_error( std::move( other.contained.error() ) ); 1814 | } 1815 | 1816 | template< typename U = T 1817 | nsel_REQUIRES_T( 1818 | std::is_copy_constructible::value 1819 | ) 1820 | > 1821 | nsel_constexpr14 expected( value_type const & value ) 1822 | : contained( true ) 1823 | { 1824 | contained.construct_value( value ); 1825 | } 1826 | 1827 | template< typename U = T 1828 | nsel_REQUIRES_T( 1829 | std::is_constructible::value 1830 | && !std::is_same::type, nonstd_lite_in_place_t(U)>::value 1831 | && !std::is_same< expected , typename std20::remove_cvref::type>::value 1832 | && !std::is_same, typename std20::remove_cvref::type>::value 1833 | && !std::is_convertible::value /*=> explicit */ 1834 | ) 1835 | > 1836 | nsel_constexpr14 explicit expected( U && value ) noexcept 1837 | ( 1838 | std::is_nothrow_move_constructible::value && 1839 | std::is_nothrow_move_constructible::value 1840 | ) 1841 | : contained( true ) 1842 | { 1843 | contained.construct_value( T{ std::forward( value ) } ); 1844 | } 1845 | 1846 | template< typename U = T 1847 | nsel_REQUIRES_T( 1848 | std::is_constructible::value 1849 | && !std::is_same::type, nonstd_lite_in_place_t(U)>::value 1850 | && !std::is_same< expected , typename std20::remove_cvref::type>::value 1851 | && !std::is_same, typename std20::remove_cvref::type>::value 1852 | && std::is_convertible::value /*=> non-explicit */ 1853 | ) 1854 | > 1855 | nsel_constexpr14 /*non-explicit*/ expected( U && value ) noexcept 1856 | ( 1857 | std::is_nothrow_move_constructible::value && 1858 | std::is_nothrow_move_constructible::value 1859 | ) 1860 | : contained( true ) 1861 | { 1862 | contained.construct_value( std::forward( value ) ); 1863 | } 1864 | 1865 | // construct error: 1866 | 1867 | template< typename G = E 1868 | nsel_REQUIRES_T( 1869 | std::is_constructible::value 1870 | && !std::is_convertible< G const &, E>::value /*=> explicit */ 1871 | ) 1872 | > 1873 | nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) 1874 | : contained( false ) 1875 | { 1876 | contained.construct_error( E{ error.value() } ); 1877 | } 1878 | 1879 | template< typename G = E 1880 | nsel_REQUIRES_T( 1881 | std::is_constructible::value 1882 | && std::is_convertible< G const &, E>::value /*=> non-explicit */ 1883 | ) 1884 | > 1885 | nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) 1886 | : contained( false ) 1887 | { 1888 | contained.construct_error( error.value() ); 1889 | } 1890 | 1891 | template< typename G = E 1892 | nsel_REQUIRES_T( 1893 | std::is_constructible::value 1894 | && !std::is_convertible< G&&, E>::value /*=> explicit */ 1895 | ) 1896 | > 1897 | nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) 1898 | : contained( false ) 1899 | { 1900 | contained.construct_error( E{ std::move( error.value() ) } ); 1901 | } 1902 | 1903 | template< typename G = E 1904 | nsel_REQUIRES_T( 1905 | std::is_constructible::value 1906 | && std::is_convertible< G&&, E>::value /*=> non-explicit */ 1907 | ) 1908 | > 1909 | nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) 1910 | : contained( false ) 1911 | { 1912 | contained.construct_error( std::move( error.value() ) ); 1913 | } 1914 | 1915 | // in-place construction, value 1916 | 1917 | template< typename... Args 1918 | nsel_REQUIRES_T( 1919 | std::is_constructible::value 1920 | ) 1921 | > 1922 | nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), Args&&... args ) 1923 | : contained( true ) 1924 | { 1925 | contained.emplace_value( std::forward( args )... ); 1926 | } 1927 | 1928 | template< typename U, typename... Args 1929 | nsel_REQUIRES_T( 1930 | std::is_constructible, Args&&...>::value 1931 | ) 1932 | > 1933 | nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args ) 1934 | : contained( true ) 1935 | { 1936 | contained.emplace_value( il, std::forward( args )... ); 1937 | } 1938 | 1939 | // in-place construction, error 1940 | 1941 | template< typename... Args 1942 | nsel_REQUIRES_T( 1943 | std::is_constructible::value 1944 | ) 1945 | > 1946 | nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) 1947 | : contained( false ) 1948 | { 1949 | contained.emplace_error( std::forward( args )... ); 1950 | } 1951 | 1952 | template< typename U, typename... Args 1953 | nsel_REQUIRES_T( 1954 | std::is_constructible, Args&&...>::value 1955 | ) 1956 | > 1957 | nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) 1958 | : contained( false ) 1959 | { 1960 | contained.emplace_error( il, std::forward( args )... ); 1961 | } 1962 | 1963 | // x.x.4.2 destructor 1964 | 1965 | // TODO: ~expected: triviality 1966 | // Effects: If T is not cv void and is_trivially_destructible_v is false and bool(*this), calls val.~T(). If is_trivially_destructible_v is false and !bool(*this), calls unexpect.~unexpected(). 1967 | // Remarks: If either T is cv void or is_trivially_destructible_v is true, and is_trivially_destructible_v is true, then this destructor shall be a trivial destructor. 1968 | 1969 | ~expected() 1970 | { 1971 | if ( has_value() ) contained.destruct_value(); 1972 | else contained.destruct_error(); 1973 | } 1974 | 1975 | // x.x.4.3 assignment 1976 | 1977 | expected & operator=( expected const & other ) 1978 | { 1979 | expected( other ).swap( *this ); 1980 | return *this; 1981 | } 1982 | 1983 | expected & operator=( expected && other ) noexcept 1984 | ( 1985 | std::is_nothrow_move_constructible< T>::value 1986 | && std::is_nothrow_move_assignable< T>::value 1987 | && std::is_nothrow_move_constructible::value // added for missing 1988 | && std::is_nothrow_move_assignable< E>::value ) // nothrow above 1989 | { 1990 | expected( std::move( other ) ).swap( *this ); 1991 | return *this; 1992 | } 1993 | 1994 | template< typename U 1995 | nsel_REQUIRES_T( 1996 | !std::is_same, typename std20::remove_cvref::type>::value 1997 | && std17::conjunction, std::is_same> >::value 1998 | && std::is_constructible::value 1999 | && std::is_assignable< T&,U>::value 2000 | && std::is_nothrow_move_constructible::value ) 2001 | > 2002 | expected & operator=( U && value ) 2003 | { 2004 | expected( std::forward( value ) ).swap( *this ); 2005 | return *this; 2006 | } 2007 | 2008 | template< typename G = E 2009 | nsel_REQUIRES_T( 2010 | std::is_constructible::value && 2011 | std::is_copy_constructible::value // TODO: std::is_nothrow_copy_constructible 2012 | && std::is_copy_assignable::value 2013 | ) 2014 | > 2015 | expected & operator=( nonstd::unexpected_type const & error ) 2016 | { 2017 | expected( unexpect, error.value() ).swap( *this ); 2018 | return *this; 2019 | } 2020 | 2021 | template< typename G = E 2022 | nsel_REQUIRES_T( 2023 | std::is_constructible::value && 2024 | std::is_move_constructible::value // TODO: std::is_nothrow_move_constructible 2025 | && std::is_move_assignable::value 2026 | ) 2027 | > 2028 | expected & operator=( nonstd::unexpected_type && error ) 2029 | { 2030 | expected( unexpect, std::move( error.value() ) ).swap( *this ); 2031 | return *this; 2032 | } 2033 | 2034 | template< typename... Args 2035 | nsel_REQUIRES_T( 2036 | std::is_nothrow_constructible::value 2037 | ) 2038 | > 2039 | value_type & emplace( Args &&... args ) 2040 | { 2041 | expected( nonstd_lite_in_place(T), std::forward(args)... ).swap( *this ); 2042 | return value(); 2043 | } 2044 | 2045 | template< typename U, typename... Args 2046 | nsel_REQUIRES_T( 2047 | std::is_nothrow_constructible&, Args&&...>::value 2048 | ) 2049 | > 2050 | value_type & emplace( std::initializer_list il, Args &&... args ) 2051 | { 2052 | expected( nonstd_lite_in_place(T), il, std::forward(args)... ).swap( *this ); 2053 | return value(); 2054 | } 2055 | 2056 | // x.x.4.4 swap 2057 | 2058 | template< typename U=T, typename G=E > 2059 | nsel_REQUIRES_R( void, 2060 | std17::is_swappable< U>::value 2061 | && std17::is_swappable::value 2062 | && ( std::is_move_constructible::value || std::is_move_constructible::value ) 2063 | ) 2064 | swap( expected & other ) noexcept 2065 | ( 2066 | std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && 2067 | std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value 2068 | ) 2069 | { 2070 | using std::swap; 2071 | 2072 | if ( bool(*this) && bool(other) ) { swap( contained.value(), other.contained.value() ); } 2073 | else if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); } 2074 | else if ( bool(*this) && ! bool(other) ) { error_type t( std::move( other.error() ) ); 2075 | other.contained.destruct_error(); 2076 | other.contained.construct_value( std::move( contained.value() ) ); 2077 | contained.destruct_value(); 2078 | contained.construct_error( std::move( t ) ); 2079 | bool has_value = contained.has_value(); 2080 | bool other_has_value = other.has_value(); 2081 | other.contained.set_has_value(has_value); 2082 | contained.set_has_value(other_has_value); 2083 | } 2084 | else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); } 2085 | } 2086 | 2087 | // x.x.4.5 observers 2088 | 2089 | constexpr value_type const * operator ->() const 2090 | { 2091 | return assert( has_value() ), contained.value_ptr(); 2092 | } 2093 | 2094 | value_type * operator ->() 2095 | { 2096 | return assert( has_value() ), contained.value_ptr(); 2097 | } 2098 | 2099 | constexpr value_type const & operator *() const & 2100 | { 2101 | return assert( has_value() ), contained.value(); 2102 | } 2103 | 2104 | value_type & operator *() & 2105 | { 2106 | return assert( has_value() ), contained.value(); 2107 | } 2108 | 2109 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2110 | 2111 | constexpr value_type const && operator *() const && 2112 | { 2113 | return std::move( ( assert( has_value() ), contained.value() ) ); 2114 | } 2115 | 2116 | nsel_constexpr14 value_type && operator *() && 2117 | { 2118 | return std::move( ( assert( has_value() ), contained.value() ) ); 2119 | } 2120 | 2121 | #endif 2122 | 2123 | constexpr explicit operator bool() const noexcept 2124 | { 2125 | return has_value(); 2126 | } 2127 | 2128 | constexpr bool has_value() const noexcept 2129 | { 2130 | return contained.has_value(); 2131 | } 2132 | 2133 | constexpr value_type const & value() const & 2134 | { 2135 | return has_value() 2136 | ? ( contained.value() ) 2137 | : ( error_traits::rethrow( contained.error() ), contained.value() ); 2138 | } 2139 | 2140 | value_type & value() & 2141 | { 2142 | return has_value() 2143 | ? ( contained.value() ) 2144 | : ( error_traits::rethrow( contained.error() ), contained.value() ); 2145 | } 2146 | 2147 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2148 | 2149 | constexpr value_type const && value() const && 2150 | { 2151 | return std::move( has_value() 2152 | ? ( contained.value() ) 2153 | : ( error_traits::rethrow( contained.error() ), contained.value() ) ); 2154 | } 2155 | 2156 | nsel_constexpr14 value_type && value() && 2157 | { 2158 | return std::move( has_value() 2159 | ? ( contained.value() ) 2160 | : ( error_traits::rethrow( contained.error() ), contained.value() ) ); 2161 | } 2162 | 2163 | #endif 2164 | 2165 | constexpr error_type const & error() const & 2166 | { 2167 | return assert( ! has_value() ), contained.error(); 2168 | } 2169 | 2170 | error_type & error() & 2171 | { 2172 | return assert( ! has_value() ), contained.error(); 2173 | } 2174 | 2175 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2176 | 2177 | constexpr error_type const && error() const && 2178 | { 2179 | return std::move( ( assert( ! has_value() ), contained.error() ) ); 2180 | } 2181 | 2182 | error_type && error() && 2183 | { 2184 | return std::move( ( assert( ! has_value() ), contained.error() ) ); 2185 | } 2186 | 2187 | #endif 2188 | 2189 | constexpr unexpected_type get_unexpected() const 2190 | { 2191 | return make_unexpected( contained.error() ); 2192 | } 2193 | 2194 | template< typename Ex > 2195 | bool has_exception() const 2196 | { 2197 | using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type; 2198 | return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; 2199 | } 2200 | 2201 | template< typename U 2202 | nsel_REQUIRES_T( 2203 | std::is_copy_constructible< T>::value 2204 | && std::is_convertible::value 2205 | ) 2206 | > 2207 | value_type value_or( U && v ) const & 2208 | { 2209 | return has_value() 2210 | ? contained.value() 2211 | : static_cast( std::forward( v ) ); 2212 | } 2213 | 2214 | template< typename U 2215 | nsel_REQUIRES_T( 2216 | std::is_move_constructible< T>::value 2217 | && std::is_convertible::value 2218 | ) 2219 | > 2220 | value_type value_or( U && v ) && 2221 | { 2222 | return has_value() 2223 | ? std::move( contained.value() ) 2224 | : static_cast( std::forward( v ) ); 2225 | } 2226 | 2227 | #if nsel_P2505R >= 4 2228 | template< typename G = E 2229 | nsel_REQUIRES_T( 2230 | std::is_copy_constructible< E >::value 2231 | && std::is_convertible< G, E >::value 2232 | ) 2233 | > 2234 | nsel_constexpr error_type error_or( G && e ) const & 2235 | { 2236 | return has_value() 2237 | ? static_cast< E >( std::forward< G >( e ) ) 2238 | : contained.error(); 2239 | } 2240 | 2241 | template< typename G = E 2242 | nsel_REQUIRES_T( 2243 | std::is_move_constructible< E >::value 2244 | && std::is_convertible< G, E >::value 2245 | ) 2246 | > 2247 | nsel_constexpr14 error_type error_or( G && e ) && 2248 | { 2249 | return has_value() 2250 | ? static_cast< E >( std::forward< G >( e ) ) 2251 | : std::move( contained.error() ); 2252 | } 2253 | #endif // nsel_P2505R >= 4 2254 | 2255 | #if nsel_P2505R >= 3 2256 | // Monadic operations (P2505) 2257 | template< typename F 2258 | nsel_REQUIRES_T( 2259 | detail::is_expected < detail::invoke_result_nocvref_t< F, value_type & > > ::value 2260 | && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type & >::error_type, error_type >::value 2261 | && std::is_constructible< error_type, error_type & >::value 2262 | ) 2263 | > 2264 | nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type & > and_then( F && f ) & 2265 | { 2266 | return has_value() 2267 | ? detail::invoke_result_nocvref_t< F, value_type & >( detail::invoke( std::forward< F >( f ), value() ) ) 2268 | : detail::invoke_result_nocvref_t< F, value_type & >( unexpect, error() ); 2269 | } 2270 | 2271 | template >::value 2274 | && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value 2275 | && std::is_constructible< error_type, const error_type & >::value 2276 | ) 2277 | > 2278 | nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type & > and_then( F && f ) const & 2279 | { 2280 | return has_value() 2281 | ? detail::invoke_result_nocvref_t< F, const value_type & >( detail::invoke( std::forward< F >( f ), value() ) ) 2282 | : detail::invoke_result_nocvref_t< F, const value_type & >( unexpect, error() ); 2283 | } 2284 | 2285 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2286 | template >::value 2289 | && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type && >::error_type, error_type >::value 2290 | && std::is_constructible< error_type, error_type && >::value 2291 | ) 2292 | > 2293 | nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type && > and_then( F && f ) && 2294 | { 2295 | return has_value() 2296 | ? detail::invoke_result_nocvref_t< F, value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) ) 2297 | : detail::invoke_result_nocvref_t< F, value_type && >( unexpect, std::move( error() ) ); 2298 | } 2299 | 2300 | template >::value 2303 | && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value 2304 | && std::is_constructible< error_type, const error_type && >::value 2305 | ) 2306 | > 2307 | nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type && > and_then( F && f ) const && 2308 | { 2309 | return has_value() 2310 | ? detail::invoke_result_nocvref_t< F, const value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) ) 2311 | : detail::invoke_result_nocvref_t< F, const value_type && >( unexpect, std::move( error() ) ); 2312 | } 2313 | #endif 2314 | 2315 | template >::value 2318 | && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type, value_type >::value 2319 | && std::is_constructible< value_type, value_type & >::value 2320 | ) 2321 | > 2322 | nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) & 2323 | { 2324 | return has_value() 2325 | ? detail::invoke_result_nocvref_t< F, error_type & >( value() ) 2326 | : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); 2327 | } 2328 | 2329 | template >::value 2332 | && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type, value_type >::value 2333 | && std::is_constructible< value_type, const value_type & >::value 2334 | ) 2335 | > 2336 | nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const & 2337 | { 2338 | return has_value() 2339 | ? detail::invoke_result_nocvref_t< F, const error_type & >( value() ) 2340 | : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); 2341 | } 2342 | 2343 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2344 | template >::value 2347 | && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type, value_type >::value 2348 | && std::is_constructible< value_type, value_type && >::value 2349 | ) 2350 | > 2351 | nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) && 2352 | { 2353 | return has_value() 2354 | ? detail::invoke_result_nocvref_t< F, error_type && >( std::move( value() ) ) 2355 | : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); 2356 | } 2357 | 2358 | template >::value 2361 | && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type, value_type >::value 2362 | && std::is_constructible< value_type, const value_type && >::value 2363 | ) 2364 | > 2365 | nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const && 2366 | { 2367 | return has_value() 2368 | ? detail::invoke_result_nocvref_t< F, const error_type && >( std::move( value() ) ) 2369 | : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); 2370 | } 2371 | #endif 2372 | 2373 | template::value 2376 | && !std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value 2377 | && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type & > >::value 2378 | ) 2379 | > 2380 | nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type & >, error_type > transform( F && f ) & 2381 | { 2382 | return has_value() 2383 | ? expected< detail::transform_invoke_result_t< F, value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) ) 2384 | : make_unexpected( error() ); 2385 | } 2386 | 2387 | template::value 2390 | && std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value 2391 | ) 2392 | > 2393 | nsel_constexpr14 expected< void, error_type > transform( F && f ) & 2394 | { 2395 | return has_value() 2396 | ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) 2397 | : make_unexpected( error() ); 2398 | } 2399 | 2400 | template::value 2403 | && !std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value 2404 | && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type & > >::value 2405 | ) 2406 | > 2407 | nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type & >, error_type > transform( F && f ) const & 2408 | { 2409 | return has_value() 2410 | ? expected< detail::transform_invoke_result_t< F, const value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) ) 2411 | : make_unexpected( error() ); 2412 | } 2413 | 2414 | template::value 2417 | && std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value 2418 | ) 2419 | > 2420 | nsel_constexpr expected< void, error_type > transform( F && f ) const & 2421 | { 2422 | return has_value() 2423 | ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) 2424 | : make_unexpected( error() ); 2425 | } 2426 | 2427 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2428 | template::value 2431 | && !std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value 2432 | && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type && > >::value 2433 | ) 2434 | > 2435 | nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type && >, error_type > transform( F && f ) && 2436 | { 2437 | return has_value() 2438 | ? expected< detail::transform_invoke_result_t< F, value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) ) 2439 | : make_unexpected( std::move( error() ) ); 2440 | } 2441 | 2442 | template::value 2445 | && std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value 2446 | ) 2447 | > 2448 | nsel_constexpr14 expected< void, error_type > transform( F && f ) && 2449 | { 2450 | return has_value() 2451 | ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) 2452 | : make_unexpected( std::move( error() ) ); 2453 | } 2454 | 2455 | template::value 2458 | && !std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value 2459 | && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type && > >::value 2460 | ) 2461 | > 2462 | nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type && >, error_type > transform( F && f ) const && 2463 | { 2464 | return has_value() 2465 | ? expected< detail::transform_invoke_result_t< F, const value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) ) 2466 | : make_unexpected( std::move( error() ) ); 2467 | } 2468 | 2469 | template::value 2472 | && std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value 2473 | ) 2474 | > 2475 | nsel_constexpr expected< void, error_type > transform( F && f ) const && 2476 | { 2477 | return has_value() 2478 | ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) 2479 | : make_unexpected( std::move( error() ) ); 2480 | } 2481 | #endif 2482 | 2483 | template >::value 2486 | && std::is_constructible< value_type, value_type & >::value 2487 | ) 2488 | > 2489 | nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) & 2490 | { 2491 | return has_value() 2492 | ? expected< value_type, detail::transform_invoke_result_t< F, error_type & > >( in_place, **this ) 2493 | : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); 2494 | } 2495 | 2496 | template >::value 2499 | && std::is_constructible< value_type, const value_type & >::value 2500 | ) 2501 | > 2502 | nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const & 2503 | { 2504 | return has_value() 2505 | ? expected< value_type, detail::transform_invoke_result_t< F, const error_type & > >( in_place, **this ) 2506 | : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); 2507 | } 2508 | 2509 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2510 | template >::value 2513 | && std::is_constructible< value_type, value_type && >::value 2514 | ) 2515 | > 2516 | nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) && 2517 | { 2518 | return has_value() 2519 | ? expected< value_type, detail::transform_invoke_result_t< F, error_type && > >( in_place, std::move( **this ) ) 2520 | : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); 2521 | } 2522 | 2523 | template >::value 2526 | && std::is_constructible< value_type, const value_type && >::value 2527 | ) 2528 | > 2529 | nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const && 2530 | { 2531 | return has_value() 2532 | ? expected< value_type, detail::transform_invoke_result_t< F, const error_type && > >( in_place, std::move( **this ) ) 2533 | : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); 2534 | } 2535 | #endif 2536 | #endif // nsel_P2505R >= 3 2537 | // unwrap() 2538 | 2539 | // template 2540 | // constexpr expected expected,E>::unwrap() const&; 2541 | 2542 | // template 2543 | // constexpr expected expected::unwrap() const&; 2544 | 2545 | // template 2546 | // expected expected, E>::unwrap() &&; 2547 | 2548 | // template 2549 | // template expected expected::unwrap() &&; 2550 | 2551 | // factories 2552 | 2553 | // template< typename Ex, typename F> 2554 | // expected catch_exception(F&& f); 2555 | 2556 | // template< typename F> 2557 | // expected())),E> map(F&& func) ; 2558 | 2559 | // template< typename F> 2560 | // 'see below' bind(F&& func); 2561 | 2562 | // template< typename F> 2563 | // expected catch_error(F&& f); 2564 | 2565 | // template< typename F> 2566 | // 'see below' then(F&& func); 2567 | 2568 | private: 2569 | detail::storage_t 2570 | < 2571 | T 2572 | ,E 2573 | , std::is_copy_constructible::value && std::is_copy_constructible::value 2574 | , std::is_move_constructible::value && std::is_move_constructible::value 2575 | > 2576 | contained; 2577 | }; 2578 | 2579 | /// class expected, void specialization 2580 | 2581 | template< typename E > 2582 | class expected 2583 | { 2584 | private: 2585 | template< typename, typename > friend class expected; 2586 | 2587 | public: 2588 | using value_type = void; 2589 | using error_type = E; 2590 | using unexpected_type = nonstd::unexpected_type; 2591 | 2592 | // x.x.4.1 constructors 2593 | 2594 | constexpr expected() noexcept 2595 | : contained( true ) 2596 | {} 2597 | 2598 | nsel_constexpr14 expected( expected const & other ) = default; 2599 | nsel_constexpr14 expected( expected && other ) = default; 2600 | 2601 | constexpr explicit expected( nonstd_lite_in_place_t(void) ) 2602 | : contained( true ) 2603 | {} 2604 | 2605 | template< typename G = E 2606 | nsel_REQUIRES_T( 2607 | !std::is_convertible::value /*=> explicit */ 2608 | ) 2609 | > 2610 | nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) 2611 | : contained( false ) 2612 | { 2613 | contained.construct_error( E{ error.value() } ); 2614 | } 2615 | 2616 | template< typename G = E 2617 | nsel_REQUIRES_T( 2618 | std::is_convertible::value /*=> non-explicit */ 2619 | ) 2620 | > 2621 | nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) 2622 | : contained( false ) 2623 | { 2624 | contained.construct_error( error.value() ); 2625 | } 2626 | 2627 | template< typename G = E 2628 | nsel_REQUIRES_T( 2629 | !std::is_convertible::value /*=> explicit */ 2630 | ) 2631 | > 2632 | nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) 2633 | : contained( false ) 2634 | { 2635 | contained.construct_error( E{ std::move( error.value() ) } ); 2636 | } 2637 | 2638 | template< typename G = E 2639 | nsel_REQUIRES_T( 2640 | std::is_convertible::value /*=> non-explicit */ 2641 | ) 2642 | > 2643 | nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) 2644 | : contained( false ) 2645 | { 2646 | contained.construct_error( std::move( error.value() ) ); 2647 | } 2648 | 2649 | template< typename... Args 2650 | nsel_REQUIRES_T( 2651 | std::is_constructible::value 2652 | ) 2653 | > 2654 | nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) 2655 | : contained( false ) 2656 | { 2657 | contained.emplace_error( std::forward( args )... ); 2658 | } 2659 | 2660 | template< typename U, typename... Args 2661 | nsel_REQUIRES_T( 2662 | std::is_constructible, Args&&...>::value 2663 | ) 2664 | > 2665 | nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) 2666 | : contained( false ) 2667 | { 2668 | contained.emplace_error( il, std::forward( args )... ); 2669 | } 2670 | 2671 | // destructor 2672 | 2673 | ~expected() 2674 | { 2675 | if ( ! has_value() ) 2676 | { 2677 | contained.destruct_error(); 2678 | } 2679 | } 2680 | 2681 | // x.x.4.3 assignment 2682 | 2683 | expected & operator=( expected const & other ) 2684 | { 2685 | expected( other ).swap( *this ); 2686 | return *this; 2687 | } 2688 | 2689 | expected & operator=( expected && other ) noexcept 2690 | ( 2691 | std::is_nothrow_move_assignable::value && 2692 | std::is_nothrow_move_constructible::value ) 2693 | { 2694 | expected( std::move( other ) ).swap( *this ); 2695 | return *this; 2696 | } 2697 | 2698 | void emplace() 2699 | { 2700 | expected().swap( *this ); 2701 | } 2702 | 2703 | // x.x.4.4 swap 2704 | 2705 | template< typename G = E > 2706 | nsel_REQUIRES_R( void, 2707 | std17::is_swappable::value 2708 | && std::is_move_constructible::value 2709 | ) 2710 | swap( expected & other ) noexcept 2711 | ( 2712 | std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value 2713 | ) 2714 | { 2715 | using std::swap; 2716 | 2717 | if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); } 2718 | else if ( bool(*this) && ! bool(other) ) { contained.construct_error( std::move( other.error() ) ); 2719 | bool has_value = contained.has_value(); 2720 | bool other_has_value = other.has_value(); 2721 | other.contained.set_has_value(has_value); 2722 | contained.set_has_value(other_has_value); 2723 | } 2724 | else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); } 2725 | } 2726 | 2727 | // x.x.4.5 observers 2728 | 2729 | constexpr explicit operator bool() const noexcept 2730 | { 2731 | return has_value(); 2732 | } 2733 | 2734 | constexpr bool has_value() const noexcept 2735 | { 2736 | return contained.has_value(); 2737 | } 2738 | 2739 | void value() const 2740 | { 2741 | if ( ! has_value() ) 2742 | { 2743 | error_traits::rethrow( contained.error() ); 2744 | } 2745 | } 2746 | 2747 | constexpr error_type const & error() const & 2748 | { 2749 | return assert( ! has_value() ), contained.error(); 2750 | } 2751 | 2752 | error_type & error() & 2753 | { 2754 | return assert( ! has_value() ), contained.error(); 2755 | } 2756 | 2757 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2758 | 2759 | constexpr error_type const && error() const && 2760 | { 2761 | return std::move( ( assert( ! has_value() ), contained.error() ) ); 2762 | } 2763 | 2764 | error_type && error() && 2765 | { 2766 | return std::move( ( assert( ! has_value() ), contained.error() ) ); 2767 | } 2768 | 2769 | #endif 2770 | 2771 | constexpr unexpected_type get_unexpected() const 2772 | { 2773 | return make_unexpected( contained.error() ); 2774 | } 2775 | 2776 | template< typename Ex > 2777 | bool has_exception() const 2778 | { 2779 | using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type; 2780 | return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; 2781 | } 2782 | 2783 | #if nsel_P2505R >= 4 2784 | template< typename G = E 2785 | nsel_REQUIRES_T( 2786 | std::is_copy_constructible< E >::value 2787 | && std::is_convertible< G, E >::value 2788 | ) 2789 | > 2790 | nsel_constexpr error_type error_or( G && e ) const & 2791 | { 2792 | return has_value() 2793 | ? static_cast< E >( std::forward< G >( e ) ) 2794 | : contained.error(); 2795 | } 2796 | 2797 | template< typename G = E 2798 | nsel_REQUIRES_T( 2799 | std::is_move_constructible< E >::value 2800 | && std::is_convertible< G, E >::value 2801 | ) 2802 | > 2803 | nsel_constexpr14 error_type error_or( G && e ) && 2804 | { 2805 | return has_value() 2806 | ? static_cast< E >( std::forward< G >( e ) ) 2807 | : std::move( contained.error() ); 2808 | } 2809 | #endif // nsel_P2505R >= 4 2810 | 2811 | #if nsel_P2505R >= 3 2812 | // Monadic operations (P2505) 2813 | template >::value 2816 | && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value 2817 | && std::is_constructible< error_type, error_type & >::value 2818 | ) 2819 | > 2820 | nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) & 2821 | { 2822 | return has_value() 2823 | ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) 2824 | : detail::invoke_result_nocvref_t< F >( unexpect, error() ); 2825 | } 2826 | 2827 | template >::value 2830 | && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value 2831 | && std::is_constructible< error_type, const error_type & >::value 2832 | ) 2833 | > 2834 | nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const & 2835 | { 2836 | return has_value() 2837 | ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) 2838 | : detail::invoke_result_nocvref_t< F >( unexpect, error() ); 2839 | } 2840 | 2841 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2842 | template >::value 2845 | && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value 2846 | && std::is_constructible< error_type, error_type && >::value 2847 | ) 2848 | > 2849 | nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) && 2850 | { 2851 | return has_value() 2852 | ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) 2853 | : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) ); 2854 | } 2855 | 2856 | template >::value 2859 | && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value 2860 | && std::is_constructible< error_type, const error_type && >::value 2861 | ) 2862 | > 2863 | nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const && 2864 | { 2865 | return has_value() 2866 | ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) 2867 | : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) ); 2868 | } 2869 | #endif 2870 | 2871 | template >::value 2874 | && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type >::value 2875 | ) 2876 | > 2877 | nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) & 2878 | { 2879 | return has_value() 2880 | ? detail::invoke_result_nocvref_t< F, error_type & >() 2881 | : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); 2882 | } 2883 | 2884 | template >::value 2887 | && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type >::value 2888 | ) 2889 | > 2890 | nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const & 2891 | { 2892 | return has_value() 2893 | ? detail::invoke_result_nocvref_t< F, const error_type & >() 2894 | : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); 2895 | } 2896 | 2897 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2898 | template >::value 2901 | && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type >::value 2902 | ) 2903 | > 2904 | nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) && 2905 | { 2906 | return has_value() 2907 | ? detail::invoke_result_nocvref_t< F, error_type && >() 2908 | : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); 2909 | } 2910 | 2911 | template >::value 2914 | && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type >::value 2915 | ) 2916 | > 2917 | nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const && 2918 | { 2919 | return has_value() 2920 | ? detail::invoke_result_nocvref_t< F, const error_type && >() 2921 | : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); 2922 | } 2923 | #endif 2924 | 2925 | template::value 2928 | && !std::is_void< detail::transform_invoke_result_t< F > >::value 2929 | ) 2930 | > 2931 | nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) & 2932 | { 2933 | return has_value() 2934 | ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) 2935 | : make_unexpected( error() ); 2936 | } 2937 | 2938 | template::value 2941 | && std::is_void< detail::transform_invoke_result_t< F > >::value 2942 | ) 2943 | > 2944 | nsel_constexpr14 expected< void, error_type > transform( F && f ) & 2945 | { 2946 | return has_value() 2947 | ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) 2948 | : make_unexpected( error() ); 2949 | } 2950 | 2951 | template::value 2954 | && !std::is_void< detail::transform_invoke_result_t< F > >::value 2955 | ) 2956 | > 2957 | nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const & 2958 | { 2959 | return has_value() 2960 | ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) 2961 | : make_unexpected( error() ); 2962 | } 2963 | 2964 | template::value 2967 | && std::is_void< detail::transform_invoke_result_t< F > >::value 2968 | ) 2969 | > 2970 | nsel_constexpr expected< void, error_type > transform( F && f ) const & 2971 | { 2972 | return has_value() 2973 | ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) 2974 | : make_unexpected( error() ); 2975 | } 2976 | 2977 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 2978 | template::value 2981 | && !std::is_void< detail::transform_invoke_result_t< F > >::value 2982 | ) 2983 | > 2984 | nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) && 2985 | { 2986 | return has_value() 2987 | ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) 2988 | : make_unexpected( error() ); 2989 | } 2990 | 2991 | template::value 2994 | && std::is_void< detail::transform_invoke_result_t< F > >::value 2995 | ) 2996 | > 2997 | nsel_constexpr14 expected< void, error_type > transform( F && f ) && 2998 | { 2999 | return has_value() 3000 | ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) 3001 | : make_unexpected( error() ); 3002 | } 3003 | 3004 | template::value 3007 | && !std::is_void< detail::transform_invoke_result_t< F > >::value 3008 | ) 3009 | > 3010 | nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const && 3011 | { 3012 | return has_value() 3013 | ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) 3014 | : make_unexpected( error() ); 3015 | } 3016 | 3017 | template::value 3020 | && std::is_void< detail::transform_invoke_result_t< F > >::value 3021 | ) 3022 | > 3023 | nsel_constexpr expected< void, error_type > transform( F && f ) const && 3024 | { 3025 | return has_value() 3026 | ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) 3027 | : make_unexpected( error() ); 3028 | } 3029 | #endif 3030 | 3031 | template >::value 3034 | ) 3035 | > 3036 | nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) & 3037 | { 3038 | return has_value() 3039 | ? expected< void, detail::transform_invoke_result_t< F, error_type & > >() 3040 | : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); 3041 | } 3042 | 3043 | template >::value 3046 | ) 3047 | > 3048 | nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const & 3049 | { 3050 | return has_value() 3051 | ? expected< void, detail::transform_invoke_result_t< F, const error_type & > >() 3052 | : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); 3053 | } 3054 | 3055 | #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 3056 | template >::value 3059 | ) 3060 | > 3061 | nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) && 3062 | { 3063 | return has_value() 3064 | ? expected< void, detail::transform_invoke_result_t< F, error_type && > >() 3065 | : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); 3066 | } 3067 | 3068 | template >::value 3071 | ) 3072 | > 3073 | nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const && 3074 | { 3075 | return has_value() 3076 | ? expected< void, detail::transform_invoke_result_t< F, const error_type && > >() 3077 | : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); 3078 | } 3079 | #endif 3080 | #endif // nsel_P2505R >= 3 3081 | 3082 | // template constexpr 'see below' unwrap() const&; 3083 | // 3084 | // template 'see below' unwrap() &&; 3085 | 3086 | // factories 3087 | 3088 | // template< typename Ex, typename F> 3089 | // expected catch_exception(F&& f); 3090 | // 3091 | // template< typename F> 3092 | // expected map(F&& func) ; 3093 | // 3094 | // template< typename F> 3095 | // 'see below' bind(F&& func) ; 3096 | // 3097 | // template< typename F> 3098 | // expected catch_error(F&& f); 3099 | // 3100 | // template< typename F> 3101 | // 'see below' then(F&& func); 3102 | 3103 | private: 3104 | detail::storage_t 3105 | < 3106 | void 3107 | , E 3108 | , std::is_copy_constructible::value 3109 | , std::is_move_constructible::value 3110 | > 3111 | contained; 3112 | }; 3113 | 3114 | // x.x.4.6 expected<>: comparison operators 3115 | 3116 | template< typename T1, typename E1, typename T2, typename E2 3117 | nsel_REQUIRES_T( 3118 | !std::is_void::value && !std::is_void::value 3119 | ) 3120 | > 3121 | constexpr bool operator==( expected const & x, expected const & y ) 3122 | { 3123 | return bool(x) != bool(y) ? false : bool(x) ? *x == *y : x.error() == y.error(); 3124 | } 3125 | 3126 | template< typename T1, typename E1, typename T2, typename E2 3127 | nsel_REQUIRES_T( 3128 | std::is_void::value && std::is_void::value 3129 | ) 3130 | > 3131 | constexpr bool operator==( expected const & x, expected const & y ) 3132 | { 3133 | return bool(x) != bool(y) ? false : bool(x) || static_cast( x.error() == y.error() ); 3134 | } 3135 | 3136 | template< typename T1, typename E1, typename T2, typename E2 > 3137 | constexpr bool operator!=( expected const & x, expected const & y ) 3138 | { 3139 | return !(x == y); 3140 | } 3141 | 3142 | #if nsel_P0323R <= 2 3143 | 3144 | template< typename T, typename E > 3145 | constexpr bool operator<( expected const & x, expected const & y ) 3146 | { 3147 | return (!y) ? false : (!x) ? true : *x < *y; 3148 | } 3149 | 3150 | template< typename T, typename E > 3151 | constexpr bool operator>( expected const & x, expected const & y ) 3152 | { 3153 | return (y < x); 3154 | } 3155 | 3156 | template< typename T, typename E > 3157 | constexpr bool operator<=( expected const & x, expected const & y ) 3158 | { 3159 | return !(y < x); 3160 | } 3161 | 3162 | template< typename T, typename E > 3163 | constexpr bool operator>=( expected const & x, expected const & y ) 3164 | { 3165 | return !(x < y); 3166 | } 3167 | 3168 | #endif 3169 | 3170 | // x.x.4.7 expected: comparison with T 3171 | 3172 | template< typename T1, typename E1, typename T2 3173 | nsel_REQUIRES_T( 3174 | !std::is_void::value 3175 | ) 3176 | > 3177 | constexpr bool operator==( expected const & x, T2 const & v ) 3178 | { 3179 | return bool(x) ? *x == v : false; 3180 | } 3181 | 3182 | template< typename T1, typename E1, typename T2 3183 | nsel_REQUIRES_T( 3184 | !std::is_void::value 3185 | ) 3186 | > 3187 | constexpr bool operator==(T2 const & v, expected const & x ) 3188 | { 3189 | return bool(x) ? v == *x : false; 3190 | } 3191 | 3192 | template< typename T1, typename E1, typename T2 > 3193 | constexpr bool operator!=( expected const & x, T2 const & v ) 3194 | { 3195 | return bool(x) ? *x != v : true; 3196 | } 3197 | 3198 | template< typename T1, typename E1, typename T2 > 3199 | constexpr bool operator!=( T2 const & v, expected const & x ) 3200 | { 3201 | return bool(x) ? v != *x : true; 3202 | } 3203 | 3204 | #if nsel_P0323R <= 2 3205 | 3206 | template< typename T, typename E > 3207 | constexpr bool operator<( expected const & x, T const & v ) 3208 | { 3209 | return bool(x) ? *x < v : true; 3210 | } 3211 | 3212 | template< typename T, typename E > 3213 | constexpr bool operator<( T const & v, expected const & x ) 3214 | { 3215 | return bool(x) ? v < *x : false; 3216 | } 3217 | 3218 | template< typename T, typename E > 3219 | constexpr bool operator>( T const & v, expected const & x ) 3220 | { 3221 | return bool(x) ? *x < v : false; 3222 | } 3223 | 3224 | template< typename T, typename E > 3225 | constexpr bool operator>( expected const & x, T const & v ) 3226 | { 3227 | return bool(x) ? v < *x : false; 3228 | } 3229 | 3230 | template< typename T, typename E > 3231 | constexpr bool operator<=( T const & v, expected const & x ) 3232 | { 3233 | return bool(x) ? ! ( *x < v ) : false; 3234 | } 3235 | 3236 | template< typename T, typename E > 3237 | constexpr bool operator<=( expected const & x, T const & v ) 3238 | { 3239 | return bool(x) ? ! ( v < *x ) : true; 3240 | } 3241 | 3242 | template< typename T, typename E > 3243 | constexpr bool operator>=( expected const & x, T const & v ) 3244 | { 3245 | return bool(x) ? ! ( *x < v ) : false; 3246 | } 3247 | 3248 | template< typename T, typename E > 3249 | constexpr bool operator>=( T const & v, expected const & x ) 3250 | { 3251 | return bool(x) ? ! ( v < *x ) : true; 3252 | } 3253 | 3254 | #endif // nsel_P0323R 3255 | 3256 | // x.x.4.8 expected: comparison with unexpected_type 3257 | 3258 | template< typename T1, typename E1 , typename E2 > 3259 | constexpr bool operator==( expected const & x, unexpected_type const & u ) 3260 | { 3261 | return (!x) ? x.get_unexpected() == u : false; 3262 | } 3263 | 3264 | template< typename T1, typename E1 , typename E2 > 3265 | constexpr bool operator==( unexpected_type const & u, expected const & x ) 3266 | { 3267 | return ( x == u ); 3268 | } 3269 | 3270 | template< typename T1, typename E1 , typename E2 > 3271 | constexpr bool operator!=( expected const & x, unexpected_type const & u ) 3272 | { 3273 | return ! ( x == u ); 3274 | } 3275 | 3276 | template< typename T1, typename E1 , typename E2 > 3277 | constexpr bool operator!=( unexpected_type const & u, expected const & x ) 3278 | { 3279 | return ! ( x == u ); 3280 | } 3281 | 3282 | #if nsel_P0323R <= 2 3283 | 3284 | template< typename T, typename E > 3285 | constexpr bool operator<( expected const & x, unexpected_type const & u ) 3286 | { 3287 | return (!x) ? ( x.get_unexpected() < u ) : false; 3288 | } 3289 | 3290 | template< typename T, typename E > 3291 | constexpr bool operator<( unexpected_type const & u, expected const & x ) 3292 | { 3293 | return (!x) ? ( u < x.get_unexpected() ) : true ; 3294 | } 3295 | 3296 | template< typename T, typename E > 3297 | constexpr bool operator>( expected const & x, unexpected_type const & u ) 3298 | { 3299 | return ( u < x ); 3300 | } 3301 | 3302 | template< typename T, typename E > 3303 | constexpr bool operator>( unexpected_type const & u, expected const & x ) 3304 | { 3305 | return ( x < u ); 3306 | } 3307 | 3308 | template< typename T, typename E > 3309 | constexpr bool operator<=( expected const & x, unexpected_type const & u ) 3310 | { 3311 | return ! ( u < x ); 3312 | } 3313 | 3314 | template< typename T, typename E > 3315 | constexpr bool operator<=( unexpected_type const & u, expected const & x) 3316 | { 3317 | return ! ( x < u ); 3318 | } 3319 | 3320 | template< typename T, typename E > 3321 | constexpr bool operator>=( expected const & x, unexpected_type const & u ) 3322 | { 3323 | return ! ( u > x ); 3324 | } 3325 | 3326 | template< typename T, typename E > 3327 | constexpr bool operator>=( unexpected_type const & u, expected const & x ) 3328 | { 3329 | return ! ( x > u ); 3330 | } 3331 | 3332 | #endif // nsel_P0323R 3333 | 3334 | /// x.x.x Specialized algorithms 3335 | 3336 | template< typename T, typename E 3337 | nsel_REQUIRES_T( 3338 | ( std::is_void::value || std::is_move_constructible::value ) 3339 | && std::is_move_constructible::value 3340 | && std17::is_swappable::value 3341 | && std17::is_swappable::value ) 3342 | > 3343 | void swap( expected & x, expected & y ) noexcept ( noexcept ( x.swap(y) ) ) 3344 | { 3345 | x.swap( y ); 3346 | } 3347 | 3348 | #if nsel_P0323R <= 3 3349 | 3350 | template< typename T > 3351 | constexpr auto make_expected( T && v ) -> expected< typename std::decay::type > 3352 | { 3353 | return expected< typename std::decay::type >( std::forward( v ) ); 3354 | } 3355 | 3356 | // expected specialization: 3357 | 3358 | auto inline make_expected() -> expected 3359 | { 3360 | return expected( in_place ); 3361 | } 3362 | 3363 | template< typename T > 3364 | constexpr auto make_expected_from_current_exception() -> expected 3365 | { 3366 | return expected( make_unexpected_from_current_exception() ); 3367 | } 3368 | 3369 | template< typename T > 3370 | auto make_expected_from_exception( std::exception_ptr v ) -> expected 3371 | { 3372 | return expected( unexpected_type( std::forward( v ) ) ); 3373 | } 3374 | 3375 | template< typename T, typename E > 3376 | constexpr auto make_expected_from_error( E e ) -> expected::type> 3377 | { 3378 | return expected::type>( make_unexpected( e ) ); 3379 | } 3380 | 3381 | template< typename F 3382 | nsel_REQUIRES_T( ! std::is_same::type, void>::value ) 3383 | > 3384 | /*nsel_constexpr14*/ 3385 | auto make_expected_from_call( F f ) -> expected< typename std::result_of::type > 3386 | { 3387 | try 3388 | { 3389 | return make_expected( f() ); 3390 | } 3391 | catch (...) 3392 | { 3393 | return make_unexpected_from_current_exception(); 3394 | } 3395 | } 3396 | 3397 | template< typename F 3398 | nsel_REQUIRES_T( std::is_same::type, void>::value ) 3399 | > 3400 | /*nsel_constexpr14*/ 3401 | auto make_expected_from_call( F f ) -> expected 3402 | { 3403 | try 3404 | { 3405 | f(); 3406 | return make_expected(); 3407 | } 3408 | catch (...) 3409 | { 3410 | return make_unexpected_from_current_exception(); 3411 | } 3412 | } 3413 | 3414 | #endif // nsel_P0323R 3415 | 3416 | } // namespace expected_lite 3417 | 3418 | using namespace expected_lite; 3419 | 3420 | // using expected_lite::expected; 3421 | // using ... 3422 | 3423 | } // namespace nonstd 3424 | 3425 | namespace std { 3426 | 3427 | // expected: hash support 3428 | 3429 | template< typename T, typename E > 3430 | struct hash< nonstd::expected > 3431 | { 3432 | using result_type = std::size_t; 3433 | using argument_type = nonstd::expected; 3434 | 3435 | constexpr result_type operator()(argument_type const & arg) const 3436 | { 3437 | return arg ? std::hash{}(*arg) : result_type{}; 3438 | } 3439 | }; 3440 | 3441 | // TBD - ?? remove? see spec. 3442 | template< typename T, typename E > 3443 | struct hash< nonstd::expected > 3444 | { 3445 | using result_type = std::size_t; 3446 | using argument_type = nonstd::expected; 3447 | 3448 | constexpr result_type operator()(argument_type const & arg) const 3449 | { 3450 | return arg ? std::hash{}(*arg) : result_type{}; 3451 | } 3452 | }; 3453 | 3454 | // TBD - implement 3455 | // bool(e), hash>()(e) shall evaluate to the hashing true; 3456 | // otherwise it evaluates to an unspecified value if E is exception_ptr or 3457 | // a combination of hashing false and hash()(e.error()). 3458 | 3459 | template< typename E > 3460 | struct hash< nonstd::expected > 3461 | { 3462 | }; 3463 | 3464 | } // namespace std 3465 | 3466 | namespace nonstd { 3467 | 3468 | // void unexpected() is deprecated && removed in C++17 3469 | 3470 | #if nsel_CPP17_OR_GREATER || nsel_COMPILER_MSVC_VERSION > 141 3471 | template< typename E > 3472 | using unexpected = unexpected_type; 3473 | #endif 3474 | 3475 | } // namespace nonstd 3476 | 3477 | #undef nsel_REQUIRES 3478 | #undef nsel_REQUIRES_0 3479 | #undef nsel_REQUIRES_T 3480 | 3481 | nsel_RESTORE_WARNINGS() 3482 | 3483 | #endif // nsel_USES_STD_EXPECTED 3484 | 3485 | #endif // NONSTD_EXPECTED_LITE_HPP 3486 | -------------------------------------------------------------------------------- /xmake.lua: -------------------------------------------------------------------------------- 1 | add_rules("mode.debug", "mode.release", "mode.releasedbg") 2 | 3 | add_repositories("liteldev-repo https://github.com/LiteLDev/xmake-repo.git") 4 | 5 | if not has_config("vs_runtime") then 6 | set_runtimes("MD") 7 | end 8 | 9 | add_requires("zlib-ng 2.1.3") 10 | 11 | -- Latest release 12 | add_requires("levilamina develop") 13 | 14 | -- Latest commit on develop 15 | -- add_requires("levilamina develop") 16 | -- package("levilamina") 17 | -- add_urls("https://github.com/LiteLDev/LeviLamina.git") 18 | -- 19 | -- add_deps("ctre 3.8.1") 20 | -- add_deps("entt 3.12.2") 21 | -- add_deps("fmt 10.1.1") 22 | -- add_deps("gsl 4.0.0") 23 | -- add_deps("leveldb 1.23") 24 | -- add_deps("magic_enum 0.9.0") 25 | -- add_deps("nlohmann_json 3.11.2") 26 | -- add_deps("rapidjson 1.1.0") 27 | -- add_deps("pcg_cpp 1.0.0") 28 | -- add_deps("pfr 2.1.1") 29 | -- add_deps("preloader 1.4.0") 30 | -- add_deps("symbolprovider 1.1.0") 31 | -- 32 | -- -- You may need to change this to the target BDS version of your choice. 33 | -- add_deps("bdslibrary 1.20.61.01") 34 | -- 35 | -- on_install(function (package) 36 | -- import("package.tools.xmake").install(package) 37 | -- end) 38 | 39 | target("DataExtractor") -- Change this to your plugin name. 40 | add_cxflags( 41 | "/EHa", 42 | "/utf-8" 43 | ) 44 | add_defines( 45 | "_HAS_CXX23=1" -- To enable C++23 features 46 | ) 47 | add_files( 48 | "src/**.cpp" 49 | ) 50 | add_includedirs( 51 | "src" 52 | ) 53 | add_packages( 54 | "levilamina", 55 | "zlib-ng" 56 | ) 57 | add_shflags( 58 | "/DELAYLOAD:bedrock_server.dll" -- Magic to import symbols from BDS 59 | ) 60 | set_exceptions("none") -- To avoid conflicts with /EHa 61 | set_kind("shared") 62 | set_languages("cxx20") 63 | 64 | after_build(function (target) 65 | local plugin_packer = import("scripts.after_build") 66 | 67 | local plugin_define = { 68 | pluginName = target:name(), 69 | pluginFile = path.filename(target:targetfile()), 70 | } 71 | 72 | plugin_packer.pack_plugin(target,plugin_define) 73 | end) 74 | --------------------------------------------------------------------------------