diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8a6c241 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Preserve upstream document bytes and original whitespace on every platform. +upstream/** -text -whitespace diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc17bf2..ef44195 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,12 +54,14 @@ jobs: - name: Checkout uses: actions/checkout@v4 - # Holds the toolchains AND the built compat.godot-cpp (1022 TUs), so a + # Holds the toolchains AND the built compat.godot-cpp (1089 TUs), so a # repeat run rebuilds little. Keyed off the tracked inputs only -- # `git ls-files -s` reads the index, so build output can never enter the # hash the way a hashFiles() glob would. - name: Mwrap identity and bilingual README contract - run: python3 tools/check_mwrap_release.py + run: | + python3 tools/check_mwrap_release.py + python3 tools/test_gen_module_cppm.py - name: Compute registry cache key shell: bash @@ -114,10 +116,33 @@ jobs: "$MCPP" --version "$MCPP" index update + - name: Checkout candidate SDK index + uses: actions/checkout@v4 + with: + repository: mcpplibs/mcpp-index + ref: feat/mwrap-opencv-onnxruntime + path: .candidate-index + + - name: Route the unpublished SDK through the candidate compat view + shell: bash + run: | + python3 - <<'PYTHON' + import json + from pathlib import Path + import subprocess + import sys + source = Path('.candidate-index').resolve() + subprocess.run([sys.executable, str(source / 'tests/prepare_mwrap_indices.py')], check=True) + view = source / 'tests/mwrap/.indices/compat' + for manifest in (Path('mcpp.toml'), Path('examples/summator/mcpp.toml')): + with manifest.open('a', encoding='utf-8') as output: + output.write('\n[indices.compat]\npath = ' + json.dumps(view.as_posix()) + '\n') + PYTHON + # No explicit toolchain: mcpp picks the platform default (gcc on Linux, # LLVM on macOS/Windows), which is what a consumer gets and what # mcpp-index CI exercises. - # Cold: compat.godot-cpp builds 1022 TUs from source underneath this. + # Cold: compat.godot-cpp builds 1089 TUs from source underneath this. - name: Build the module layer shell: bash env: @@ -136,7 +161,7 @@ jobs: shell: bash env: MCPP_INDEX_MIRROR: GLOBAL - run: python3 tools/test_template.py --mcpp "$MCPP" --toolchain "${{ matrix.toolchain }}" + run: python3 tools/test_template.py --mcpp "$MCPP" --toolchain "${{ matrix.toolchain }}" --index .candidate-index # Verify the native shared-library shape on every supported platform. # Loading this library still requires a matching Godot process. diff --git a/LICENSE b/LICENSE index ec6c5d0..d645695 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,202 @@ -MIT License - -Copyright (c) 2026 godot-cpp-m module contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..fa44c85 --- /dev/null +++ b/NOTICE @@ -0,0 +1,11 @@ +godot-cpp-m: C++ module wrapper +Copyright (c) 2026 mcpp-community contributors + +The wrapper contributions are licensed under the Apache License, Version 2.0. +Upstream code, copied interfaces, generated bindings and dependencies retain +their original licenses and copyright notices. Original upstream README and +license documents are retained in upstream/godot-cpp/; provenance and checksums +are recorded in upstream/documents.json. + +The inherited wrapper permission and copyright notice is retained in +upstream/wrapper-legacy/LICENSE. diff --git a/README.md b/README.md index 615d782..9a26dfc 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # godot-cpp-m -> godot-cpp 10.0.0-rc1 as C++23 modules, preserving godot:: APIs. +> godot-cpp 10.0.0 as C++23 modules, preserving godot:: APIs. **English** · [简体中文](README.zh.md) · [Upstream](https://github.com/godotengine/godot-cpp) · [Releases](https://github.com/mcpplibs/godot-cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) [![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE) +[![mcpp-community](https://img.shields.io/badge/mcpp--community-mwrap-blue)](https://github.com/mcpp-community) [![CI](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml) ## Modules @@ -18,14 +19,14 @@ ## Install ```sh -mcpp new godot_math --template mcpplibs.mwrap.godot_cpp@10.0.0-rc1 +mcpp new godot_math --template mcpplibs.mwrap.godot_cpp@10.0.0 cd godot_math mcpp run ``` ```toml [dependencies] -mcpplibs.mwrap.godot_cpp = "10.0.0-rc1" +mcpplibs.mwrap.godot_cpp = "10.0.0" ``` ## Macros @@ -33,10 +34,6 @@ mcpplibs.mwrap.godot_cpp = "10.0.0-rc1" Use `.macros` for version mappings. For GDCLASS, D_METHOD and memory/control macros, include `` before `import mcpplibs.mwrap.godot_cpp;`. -## The hashfuncs shim - -A generated linkage adapter keeps upstream template bodies usable by named modules. [Details](docs/usage.md) - ## Example ```cpp @@ -53,8 +50,10 @@ Use `tools/gen_module_cppm.py` with the exact compat.godot-cpp source and genera ## Tests `mcpp test` covers module/math and textual macros; CI also builds the extension on Linux/macOS/Windows. -This is a prerelease binding, not certification of engine loading. +Uses the upstream-default Godot 4.7 API; engine loading requires a matching runtime. ## License -[MIT](LICENSE); compat.godot-cpp carries upstream sources, generated bindings and notices. +[Apache-2.0](LICENSE); compat.godot-cpp carries upstream sources, generated bindings and notices. + +Wrapper: Apache-2.0, mcpp-community. [Original upstream README and licenses](upstream/godot-cpp/). Upstream licenses remain unchanged. diff --git a/README.zh.md b/README.zh.md index 5f862de..63c71e8 100644 --- a/README.zh.md +++ b/README.zh.md @@ -1,11 +1,12 @@ # godot-cpp-m -> godot-cpp 10.0.0-rc1 的 C++23 模块封装,保留 godot:: API。 +> godot-cpp 10.0.0 的 C++23 模块封装,保留 godot:: API。 [English](README.md) · **简体中文** · [Upstream](https://github.com/godotengine/godot-cpp) · [Releases](https://github.com/mcpplibs/godot-cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) [![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE) +[![mcpp-community](https://img.shields.io/badge/mcpp--community-mwrap-blue)](https://github.com/mcpp-community) [![CI](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml) ## 模块 @@ -18,14 +19,14 @@ ## 安装 ```sh -mcpp new godot_math --template mcpplibs.mwrap.godot_cpp@10.0.0-rc1 +mcpp new godot_math --template mcpplibs.mwrap.godot_cpp@10.0.0 cd godot_math mcpp run ``` ```toml [dependencies] -mcpplibs.mwrap.godot_cpp = "10.0.0-rc1" +mcpplibs.mwrap.godot_cpp = "10.0.0" ``` ## 宏 @@ -33,10 +34,6 @@ mcpplibs.mwrap.godot_cpp = "10.0.0-rc1" 版本映射使用 `.macros`;GDCLASS、D_METHOD 与内存/控制宏在 import 前包含 ``,再 `import mcpplibs.mwrap.godot_cpp;`。 -## hashfuncs 适配 - -生成的链接属性适配使上游模板实现可用于命名模块;见[详情](docs/usage.md)。 - ## 示例 ```cpp @@ -53,8 +50,10 @@ int main() { return godot::Vector2(3, 4).length() == 5 ? 0 : 1; } ## 测试 `mcpp test` 覆盖模块、数学与文本宏;CI 还在 Linux/macOS/Windows 构建扩展。 -这是预发布绑定,不代表引擎实际加载认证。 +使用上游默认 Godot 4.7 API;引擎加载需要匹配的运行时。 ## 许可证 -[MIT](LICENSE);compat.godot-cpp 提供上游源码、生成绑定及通知。 +[Apache-2.0](LICENSE);compat.godot-cpp 提供上游源码、生成绑定及通知。 + +封装:Apache-2.0,mcpp-community。[上游原始 README 与许可证](upstream/godot-cpp/),上游许可保持原样。 diff --git a/docs/usage.md b/docs/usage.md index 3b459a2..fd9e478 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -2,7 +2,7 @@ > godot-cpp as a C++23 module for mcpp — the same API, reached with `import mcpplibs.mwrap.godot_cpp;`. > -> Targets **Godot 4.6** (`compat.godot-cpp` 10.0.0-rc1). For Godot 4.5, use `godot-cpp-m = "4.5.0"`. +> Targets **Godot 4.7** (`compat.godot-cpp` 10.0.0). Other engine API profiles require a matching generated provider. ```cpp import std; @@ -30,17 +30,16 @@ int main() { ```toml [dependencies] -"mcpplibs.mwrap.godot_cpp" = "10.0.0-rc1" # Godot 4.6; use "4.5.0" for Godot 4.5 +"mcpplibs.mwrap.godot_cpp" = "10.0.0" # Upstream-default Godot 4.7 API ``` The version tracks upstream godot-cpp. A numeric wrapper revision may follow -the upstream version: candidate `10.0.0-rc1` still uses SDK `10.0.0-rc1`. +the upstream version: candidate `10.0.0` still uses SDK `10.0.0`. The historical upstream mapping is: | package version | upstream tag | engine | |---|---|---| -| `10.0.0-rc1` | `10.0.0-rc1` | Godot 4.6 | -| `4.5.0` | `godot-4.5-stable` | Godot 4.5 | +| `10.0.0` | `10.0.0-stable` | Godot 4.7 (upstream-default API) | ## Macros @@ -75,37 +74,12 @@ include and the import this way is well-formed. `tests/godot_cpp_macros.cpp` covers exactly this shape. Any other upstream header can be included the same way — they are all on the include path. -## The hashfuncs shim +## Hash function ownership -`include/godot_cpp/templates/hashfuncs.hpp` is generated, and it is what makes -the whole `godot` namespace exportable at all. - -godot-cpp declares `hash_murmur3_one_float` / `_double` `static`, and each -declares an unnamed union inside its body. A local class has no linkage, and -`static` makes the enclosing function TU-local, so once the module interface -exposes it — which it does, reachable from many inline bodies — GCC rejects the -module outright: - -``` -error: 'uint32_t godot::hash_murmur3_one_float(float, uint32_t)' exposes - TU-local entity 'union ...::' -note: ... is also TU-local but has been exposed elsewhere -``` - -That is a hard error, not the `-Wexpose-global-module-tu-local` warning: -`-Wno-...`, `-fpermissive` and `-Wno-error=` all leave it standing. Exporting -less does not help either — with 10.x a single engine class is enough to -trigger it. - -The shim is upstream's header with `static` dropped from those two functions -and nothing else changed. This package's `include/` precedes the dependency's -on the command line, so only this package's translation units see it; -`compat.godot-cpp` keeps compiling upstream's copy untouched. The bodies are -identical — the sole difference is linkage, internal to inline — and the -generator refuses to run if either declaration stops matching exactly once. - -With it in place nothing has to be held back: `HashMap`, `HashSet`, `AHashMap`, -`Pair`, the hashers and the rest of `templates/` all re-export normally. +Upstream `10.0.0-stable` defines the float/double hash functions out of line. +The wrapper uses those original definitions and no longer shadows hashfuncs.hpp. +The generator retains support for reproducing legacy releases that required the +small linkage shim; it removes that obsolete shim for the stable source layout. ## Example @@ -115,7 +89,7 @@ methods, entry point — built as the shared library Godot loads, written with ```sh cd examples/summator && mcpp build -# then drop the library + summator.gdextension into a matching Godot 4.6 project +# then drop the library + summator.gdextension into a matching Godot 4.7 project ``` ## Regenerating the module diff --git a/examples/summator/mcpp.toml b/examples/summator/mcpp.toml index 208ad93..ac6da42 100644 --- a/examples/summator/mcpp.toml +++ b/examples/summator/mcpp.toml @@ -4,11 +4,11 @@ # # mcpp build # # then point summator.gdextension at the produced library and drop both -# # into a matching Godot 4.6 project +# # into a matching Godot 4.7 project [package] name = "summator" version = "0.1.0" -description = "Minimal Godot 4.6 GDExtension written with import mcpplibs.mwrap.godot_cpp;" +description = "Minimal Godot 4.7 GDExtension written with import mcpplibs.mwrap.godot_cpp;" license = "MIT" [targets.summator] diff --git a/examples/summator/src/summator.cpp b/examples/summator/src/summator.cpp index b367e83..c227636 100644 --- a/examples/summator/src/summator.cpp +++ b/examples/summator/src/summator.cpp @@ -1,4 +1,4 @@ -// A complete Godot 4.5 GDExtension -- registered class, bound methods, +// A complete Godot 4.7 GDExtension -- registered class, bound methods, // entry point -- written with `import mcpplibs.mwrap.godot_cpp;`. // // Compare with upstream's C++ version of the same example: the only diff --git a/examples/summator/summator.gdextension b/examples/summator/summator.gdextension index 39b4ac1..8a9f74a 100644 --- a/examples/summator/summator.gdextension +++ b/examples/summator/summator.gdextension @@ -1,6 +1,6 @@ [configuration] entry_symbol = "summator_library_init" -compatibility_minimum = "4.6" +compatibility_minimum = "4.7" [libraries] linux.debug.x86_64 = "res://bin/libsummator.so" diff --git a/include/godot_cpp/templates/hashfuncs.hpp b/include/godot_cpp/templates/hashfuncs.hpp deleted file mode 100644 index a639bdf..0000000 --- a/include/godot_cpp/templates/hashfuncs.hpp +++ /dev/null @@ -1,669 +0,0 @@ -// GENERATED by tools/gen_module_cppm.py -- do not hand-edit. -// -// This is godot-cpp's own include/godot_cpp/templates/hashfuncs.hpp, byte for byte, with -// ONE difference: `static` is dropped from hash_murmur3_one_float and -// hash_murmur3_one_double. -// -// Why: those two declare an unnamed union inside their bodies, and a local -// class has no linkage. `static` makes the enclosing function TU-local, and -// the module interface exposes it (reachable from many inline bodies), so GCC -// rejects the module outright -- "exposes TU-local entity 'union ... -// '", a hard error that -Wno-expose-global-module-tu-local, -// -fpermissive and -Wno-error= do not touch. -// -// This package's include/ precedes the dependency's on the command line, so -// only this package's translation units see the file; compat.godot-cpp keeps -// compiling upstream's copy untouched. The bodies are identical -- the sole -// change is linkage, internal to inline. -/**************************************************************************/ -/* hashfuncs.hpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#pragma once - -// Needed for fastmod. -#if defined(_MSC_VER) -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * Hashing functions - */ - -namespace godot { - -/** - * DJB2 Hash function - * @param C String - * @return 32-bits hashcode - */ -static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) { - const unsigned char *chr = (const unsigned char *)p_cstr; - uint32_t hash = 5381; - uint32_t c = *chr++; - - while (c) { - hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */ - c = *chr++; - } - - return hash; -} - -static _FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) { - uint32_t hash = p_prev; - - for (int i = 0; i < p_len; i++) { - hash = ((hash << 5) + hash) ^ p_buff[i]; /* hash * 33 + c */ - } - - return hash; -} - -static _FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) { - return ((p_prev << 5) + p_prev) ^ p_in; -} - -/** - * Thomas Wang's 64-bit to 32-bit Hash function: - * https://web.archive.org/web/20071223173210/https:/www.concentric.net/~Ttwang/tech/inthash.htm - * - * @param p_int - 64-bit unsigned integer key to be hashed - * @return unsigned 32-bit value representing hashcode - */ -static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) { - uint64_t v = p_int; - v = (~v) + (v << 18); // v = (v << 18) - v - 1; - v = v ^ (v >> 31); - v = v * 21; // v = (v + (v << 2)) + (v << 4); - v = v ^ (v >> 11); - v = v + (v << 6); - v = v ^ (v >> 22); - return uint32_t(v); -} - -static _FORCE_INLINE_ uint64_t hash64_murmur3_64(uint64_t key, uint64_t seed) { - key ^= seed; - key ^= key >> 33; - key *= 0xff51afd7ed558ccd; - key ^= key >> 33; - key *= 0xc4ceb9fe1a85ec53; - key ^= key >> 33; - return key; -} - -#define HASH_MURMUR3_SEED 0x7F07C65 -// Murmurhash3 32-bit version. -// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code. - -static _FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { - p_in *= 0xcc9e2d51; - p_in = (p_in << 15) | (p_in >> 17); - p_in *= 0x1b873593; - - p_seed ^= p_in; - p_seed = (p_seed << 13) | (p_seed >> 19); - p_seed = p_seed * 5 + 0xe6546b64; - - return p_seed; -} - -_FORCE_INLINE_ uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { - union { - float f; - uint32_t i; - } u; - - // Normalize +/- 0.0 and NaN values so they hash the same. - if (p_in == 0.0f) { - u.f = 0.0; - } else if (Math::is_nan(p_in)) { - u.f = NAN; - } else { - u.f = p_in; - } - - return hash_murmur3_one_32(u.i, p_seed); -} - -static _FORCE_INLINE_ uint32_t hash_murmur3_one_64(uint64_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { - p_seed = hash_murmur3_one_32(p_in & 0xFFFFFFFF, p_seed); - return hash_murmur3_one_32(p_in >> 32, p_seed); -} - -_FORCE_INLINE_ uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { - union { - double d; - uint64_t i; - } u; - - // Normalize +/- 0.0 and NaN values so they hash the same. - if (p_in == 0.0f) { - u.d = 0.0; - } else if (Math::is_nan(p_in)) { - u.d = NAN; - } else { - u.d = p_in; - } - - return hash_murmur3_one_64(u.i, p_seed); -} - -static _FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { -#ifdef REAL_T_IS_DOUBLE - return hash_murmur3_one_double(p_in, p_seed); -#else - return hash_murmur3_one_float(p_in, p_seed); -#endif -} - -static _FORCE_INLINE_ uint32_t hash_rotl32(uint32_t x, int8_t r) { - return (x << r) | (x >> (32 - r)); -} - -static _FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) { - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; -} - -static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length, const uint32_t seed = HASH_MURMUR3_SEED) { - // Although not required, this is a random prime number. - const uint8_t *data = (const uint8_t *)key; - const int nblocks = length / 4; - - uint32_t h1 = seed; - - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; - - const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4); - - for (int i = -nblocks; i; i++) { - uint32_t k1 = blocks[i]; - - k1 *= c1; - k1 = hash_rotl32(k1, 15); - k1 *= c2; - - h1 ^= k1; - h1 = hash_rotl32(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - } - - const uint8_t *tail = (const uint8_t *)(data + nblocks * 4); - - uint32_t k1 = 0; - - switch (length & 3) { - case 3: - k1 ^= tail[2] << 16; - [[fallthrough]]; - case 2: - k1 ^= tail[1] << 8; - [[fallthrough]]; - case 1: - k1 ^= tail[0]; - k1 *= c1; - k1 = hash_rotl32(k1, 15); - k1 *= c2; - h1 ^= k1; - }; - - // Finalize with additional bit mixing. - h1 ^= length; - return hash_fmix32(h1); -} - -static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) { - union { - double d; - uint64_t i; - } u; - - // Normalize +/- 0.0 and NaN values so they hash the same. - if (p_in == 0.0f) { - u.d = 0.0; - } else if (Math::is_nan(p_in)) { - u.d = NAN; - } else { - u.d = p_in; - } - - return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i); -} - -template -static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) { - union { - T t; - uint32_t _u32; - } _u; - _u._u32 = 0; - _u.t = p_in; - return _u._u32; -} - -static _FORCE_INLINE_ uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) { - union { - double d; - uint64_t i; - } u; - - // Normalize +/- 0.0 and NaN values so they hash the same. - if (p_in == 0.0f) { - u.d = 0.0; - } else if (Math::is_nan(p_in)) { - u.d = NAN; - } else { - u.d = p_in; - } - - return ((p_prev << 5) + p_prev) + u.i; -} - -static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) { - return ((p_prev << 5) + p_prev) ^ p_in; -} - -template -static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) { - union { - T t; - uint64_t _u64; - } _u; - _u._u64 = 0; // in case p_in is smaller - - _u.t = p_in; - return _u._u64; -} - -template -class Ref; - -struct HashMapHasherDefault { - // Generic hash function for any type. - template - static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); } - - template - static _FORCE_INLINE_ uint32_t hash(const Ref &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); } - - template - static _FORCE_INLINE_ uint32_t hash(const Pair &p_pair) { - uint64_t h1 = hash(p_pair.first); - uint64_t h2 = hash(p_pair.second); - return hash_one_uint64((h1 << 32) | h2); - } - - static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } - static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); } - static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(uint32_t(p_wchar)); } - static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); } - static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); } - static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); } - static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.get_data()); } - static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); } - static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); } - static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); } - static _FORCE_INLINE_ uint32_t hash(const Callable &p_callable) { return p_callable.hash(); } - - static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); } - static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(uint64_t(p_int)); } - static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_murmur3_one_float(p_float); } - static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_murmur3_one_double(p_double); } - static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return hash_fmix32(p_int); } - static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(uint32_t(p_int)); } - static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(uint32_t(p_int)); } - static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(uint32_t(p_int)); } - static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(uint32_t(p_int)); } - static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(uint32_t(p_int)); } - static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) { - uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x)); - h = hash_murmur3_one_32(uint32_t(p_vec.y), h); - return hash_fmix32(h); - } - static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) { - uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x)); - h = hash_murmur3_one_32(uint32_t(p_vec.y), h); - h = hash_murmur3_one_32(uint32_t(p_vec.z), h); - return hash_fmix32(h); - } - static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) { - uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x)); - h = hash_murmur3_one_32(uint32_t(p_vec.y), h); - h = hash_murmur3_one_32(uint32_t(p_vec.z), h); - h = hash_murmur3_one_32(uint32_t(p_vec.w), h); - return hash_fmix32(h); - } - static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) { - uint32_t h = hash_murmur3_one_real(p_vec.x); - h = hash_murmur3_one_real(p_vec.y, h); - return hash_fmix32(h); - } - static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) { - uint32_t h = hash_murmur3_one_real(p_vec.x); - h = hash_murmur3_one_real(p_vec.y, h); - h = hash_murmur3_one_real(p_vec.z, h); - return hash_fmix32(h); - } - static _FORCE_INLINE_ uint32_t hash(const Vector4 &p_vec) { - uint32_t h = hash_murmur3_one_real(p_vec.x); - h = hash_murmur3_one_real(p_vec.y, h); - h = hash_murmur3_one_real(p_vec.z, h); - h = hash_murmur3_one_real(p_vec.w, h); - return hash_fmix32(h); - } - static _FORCE_INLINE_ uint32_t hash(const Color &p_vec) { - uint32_t h = hash_murmur3_one_float(p_vec.r); - h = hash_murmur3_one_float(p_vec.g, h); - h = hash_murmur3_one_float(p_vec.b, h); - h = hash_murmur3_one_float(p_vec.a, h); - return hash_fmix32(h); - } - static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) { - uint32_t h = hash_murmur3_one_32(uint32_t(p_rect.position.x)); - h = hash_murmur3_one_32(uint32_t(p_rect.position.y), h); - h = hash_murmur3_one_32(uint32_t(p_rect.size.x), h); - h = hash_murmur3_one_32(uint32_t(p_rect.size.y), h); - return hash_fmix32(h); - } - static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) { - uint32_t h = hash_murmur3_one_real(p_rect.position.x); - h = hash_murmur3_one_real(p_rect.position.y, h); - h = hash_murmur3_one_real(p_rect.size.x, h); - h = hash_murmur3_one_real(p_rect.size.y, h); - return hash_fmix32(h); - } - static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) { - uint32_t h = hash_murmur3_one_real(p_aabb.position.x); - h = hash_murmur3_one_real(p_aabb.position.y, h); - h = hash_murmur3_one_real(p_aabb.position.z, h); - h = hash_murmur3_one_real(p_aabb.size.x, h); - h = hash_murmur3_one_real(p_aabb.size.y, h); - h = hash_murmur3_one_real(p_aabb.size.z, h); - return hash_fmix32(h); - } -}; - -struct HashHasher { - static _FORCE_INLINE_ uint32_t hash(const int32_t hash) { return hash; } - static _FORCE_INLINE_ uint32_t hash(const uint32_t hash) { return hash; } - static _FORCE_INLINE_ uint64_t hash(const int64_t hash) { return hash; } - static _FORCE_INLINE_ uint64_t hash(const uint64_t hash) { return hash; } -}; - -// TODO: Fold this into HashMapHasherDefault once C++20 concepts are allowed -template -struct HashableHasher { - static _FORCE_INLINE_ uint32_t hash(const T &hashable) { return hashable.hash(); } -}; - -template -struct HashMapComparatorDefault { - static bool compare(const T &p_lhs, const T &p_rhs) { - return p_lhs == p_rhs; - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const float &p_lhs, const float &p_rhs) { - return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const double &p_lhs, const double &p_rhs) { - return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Color &p_lhs, const Color &p_rhs) { - return ((p_lhs.r == p_rhs.r) || (Math::is_nan(p_lhs.r) && Math::is_nan(p_rhs.r))) && ((p_lhs.g == p_rhs.g) || (Math::is_nan(p_lhs.g) && Math::is_nan(p_rhs.g))) && ((p_lhs.b == p_rhs.b) || (Math::is_nan(p_lhs.b) && Math::is_nan(p_rhs.b))) && ((p_lhs.a == p_rhs.a) || (Math::is_nan(p_lhs.a) && Math::is_nan(p_rhs.a))); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) { - return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Vector3 &p_lhs, const Vector3 &p_rhs) { - return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Vector4 &p_lhs, const Vector4 &p_rhs) { - return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))) && ((p_lhs.w == p_rhs.w) || (Math::is_nan(p_lhs.w) && Math::is_nan(p_rhs.w))); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Rect2 &p_lhs, const Rect2 &p_rhs) { - return HashMapComparatorDefault().compare(p_lhs.position, p_rhs.position) && HashMapComparatorDefault().compare(p_lhs.size, p_rhs.size); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const AABB &p_lhs, const AABB &p_rhs) { - return HashMapComparatorDefault().compare(p_lhs.position, p_rhs.position) && HashMapComparatorDefault().compare(p_lhs.size, p_rhs.size); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Plane &p_lhs, const Plane &p_rhs) { - return HashMapComparatorDefault().compare(p_lhs.normal, p_rhs.normal) && ((p_lhs.d == p_rhs.d) || (Math::is_nan(p_lhs.d) && Math::is_nan(p_rhs.d))); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Transform2D &p_lhs, const Transform2D &p_rhs) { - for (int i = 0; i < 3; ++i) { - if (!HashMapComparatorDefault().compare(p_lhs.columns[i], p_rhs.columns[i])) { - return false; - } - } - - return true; - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Basis &p_lhs, const Basis &p_rhs) { - for (int i = 0; i < 3; ++i) { - if (!HashMapComparatorDefault().compare(p_lhs.rows[i], p_rhs.rows[i])) { - return false; - } - } - - return true; - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Transform3D &p_lhs, const Transform3D &p_rhs) { - return HashMapComparatorDefault().compare(p_lhs.basis, p_rhs.basis) && HashMapComparatorDefault().compare(p_lhs.origin, p_rhs.origin); - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Projection &p_lhs, const Projection &p_rhs) { - for (int i = 0; i < 4; ++i) { - if (!HashMapComparatorDefault().compare(p_lhs.columns[i], p_rhs.columns[i])) { - return false; - } - } - - return true; - } -}; - -template <> -struct HashMapComparatorDefault { - static bool compare(const Quaternion &p_lhs, const Quaternion &p_rhs) { - return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))) && ((p_lhs.w == p_rhs.w) || (Math::is_nan(p_lhs.w) && Math::is_nan(p_rhs.w))); - } -}; - -constexpr uint32_t HASH_TABLE_SIZE_MAX = 29; - -inline constexpr uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = { - 5, - 13, - 23, - 47, - 97, - 193, - 389, - 769, - 1543, - 3079, - 6151, - 12289, - 24593, - 49157, - 98317, - 196613, - 393241, - 786433, - 1572869, - 3145739, - 6291469, - 12582917, - 25165843, - 50331653, - 100663319, - 201326611, - 402653189, - 805306457, - 1610612741, -}; - -// Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array. -inline constexpr uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = { - 3689348814741910324, - 1418980313362273202, - 802032351030850071, - 392483916461905354, - 190172619316593316, - 95578984837873325, - 47420935922132524, - 23987963684927896, - 11955116055547344, - 5991147799191151, - 2998982941588287, - 1501077717772769, - 750081082979285, - 375261795343686, - 187625172388393, - 93822606204624, - 46909513691883, - 23456218233098, - 11728086747027, - 5864041509391, - 2932024948977, - 1466014921160, - 733007198436, - 366503839517, - 183251896093, - 91625960335, - 45812983922, - 22906489714, - 11453246088 -}; - -/** - * Fastmod computes ( n mod d ) given the precomputed c much faster than n % d. - * The implementation of fastmod is based on the following paper by Daniel Lemire et al. - * Faster Remainder by Direct Computation: Applications to Compilers and Software Libraries - * https://arxiv.org/abs/1902.01961 - */ -static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const uint32_t d) { -#if defined(_MSC_VER) - // Returns the upper 64 bits of the product of two 64-bit unsigned integers. - // This intrinsic function is required since MSVC does not support unsigned 128-bit integers. -#if defined(_M_X64) || defined(_M_ARM64) - return __umulh(c * n, d); -#else - // Fallback to the slower method for 32-bit platforms. - return n % d; -#endif // _M_X64 || _M_ARM64 -#else -#ifdef __SIZEOF_INT128__ - // Prevent compiler warning, because we know what we are doing. - uint64_t lowbits = c * n; - __extension__ typedef unsigned __int128 uint128; - return static_cast(((uint128)lowbits * d) >> 64); -#else - // Fallback to the slower method if no 128-bit unsigned integer type is available. - return n % d; -#endif // __SIZEOF_INT128__ -#endif // _MSC_VER -} - -} // namespace godot diff --git a/mcpp.toml b/mcpp.toml index 25156d6..fac2796 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -2,9 +2,10 @@ [package] namespace = "mcpplibs.mwrap" name = "godot_cpp" -version = "10.0.0-rc1" +version = "10.0.0" description = "godot-cpp as a C++23 module (import mcpplibs.mwrap.godot_cpp;) on top of the compat.godot-cpp source build" -license = "MIT" +license = "Apache-2.0" +authors = ["mcpp-community"] repo = "https://github.com/mcpplibs/godot-cpp-m" platforms = ["linux", "macos", "windows"] @@ -29,7 +30,30 @@ cxxflags = ["-Wno-expose-global-module-tu-local"] [dependencies] # Upstream tree + pre-generated bindings + the whole source build recipe. -compat.godot-cpp = "10.0.0-rc1" +compat.godot-cpp = "10.0.0" [package.metadata.mwrap] -upstream-version = "10.0.0-rc1" +wrapper-revision = 0 +upstream-version = "10.0.0" +upstream-tag = "10.0.0-stable" +engine-api = "4.7" + +[[runtime.deploy]] +from = "LICENSE" +to = "licenses/godot_cpp" + +[[runtime.deploy]] +from = "NOTICE" +to = "licenses/godot_cpp" + +[[runtime.deploy]] +from = "upstream/godot-cpp/README.md" +to = "licenses/godot_cpp/upstream/godot-cpp" + +[[runtime.deploy]] +from = "upstream/godot-cpp/LICENSE.md" +to = "licenses/godot_cpp/upstream/godot-cpp" + +[[runtime.deploy]] +from = "upstream/wrapper-legacy/LICENSE" +to = "licenses/godot_cpp/upstream/wrapper-legacy" diff --git a/src/godot_cpp.cppm b/src/godot_cpp.cppm index 35fbac5..9272286 100644 --- a/src/godot_cpp.cppm +++ b/src/godot_cpp.cppm @@ -1,4 +1,4 @@ -// godot_cpp -- C++23 module interface unit for godot-cpp 4.6.0. +// godot_cpp -- C++23 module interface unit for godot-cpp 4.7.0. // // GENERATED by tools/gen_module_cppm.py from the godot-cpp headers // (upstream `include/` plus the `gen/` tree produced by upstream's own @@ -26,10 +26,10 @@ module; #include #include #include +#include #include #include #include -#include #include #include #include @@ -43,18 +43,18 @@ module; #include #include #include +#include #include #include #include #include #include -#include #include #include +#include +#include #include -#include #include -#include #include #include #include @@ -87,6 +87,7 @@ module; #include #include #include +#include #include #include #include @@ -122,6 +123,7 @@ module; #include #include #include +#include #include #include #include @@ -185,10 +187,12 @@ module; #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -289,6 +293,7 @@ module; #include #include #include +#include #include #include #include @@ -373,7 +378,10 @@ module; #include #include #include +#include #include +#include +#include #include #include #include @@ -731,13 +739,17 @@ module; #include #include #include +#include +#include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -963,6 +975,7 @@ module; #include #include #include +#include #include #include #include @@ -1154,8 +1167,9 @@ export namespace godot { using ::godot::EditorPlugin; using ::godot::StringName; using ::godot::EditorPlugins; -using ::godot::RefCounted; using ::godot::Ref; +using ::godot::memnew_result; +using ::godot::postinitialize_handler; using ::godot::PtrToArg; using ::godot::GetTypeInfo; using ::godot::ClassDB; @@ -1203,9 +1217,7 @@ using ::godot::SIGN; using ::godot::MIN; using ::godot::MAX; using ::godot::CLAMP; -using ::godot::is_power_of_2; -using ::godot::floor_log2; -using ::godot::get_num_bits; +using ::godot::std_size; using ::godot::Comparator; using ::godot::_global_lock; using ::godot::_global_unlock; @@ -1214,20 +1226,29 @@ using ::godot::IndexSequence; using ::godot::BuildIndexSequence; using ::godot::is_zero_constructible; using ::godot::is_zero_constructible_v; +using ::godot::is_fully_defined; using ::godot::String; using ::godot::_err_print_error; using ::godot::_err_print_index_error; using ::godot::_err_flush_stdout; +using ::godot::is_print_verbose_enabled; +using ::godot::CMP_EPSILON; +using ::godot::CMP_EPSILON2; +using ::godot::CMP_NORMALIZE_TOLERANCE; +using ::godot::CMP_POINT_IN_PLANE_EPSILON; +using ::godot::UNIT_EPSILON; using ::godot::real_t; -using ::godot::Memory; -using ::godot::postinitialize_handler; +using ::godot::DefaultAllocator; +using ::godot::memnew_result_t; using ::godot::_post_initialize; using ::godot::memdelete; using ::godot::memdelete_allocator; -using ::godot::DefaultAllocator; using ::godot::DefaultTypedAllocator; using ::godot::_get_element_count_ptr; using ::godot::memnew_arr_template; +using ::godot::memnew_arr_placement; +using ::godot::copy_arr_placement; +using ::godot::destruct_arr_placement; using ::godot::memarr_len; using ::godot::memdelete_arr; using ::godot::_GlobalNil; @@ -1245,7 +1266,6 @@ using ::godot::MethodBindTRC; using ::godot::MethodBindTS; using ::godot::create_static_method_bind; using ::godot::MethodBindTRS; -using ::godot::MutexLock; using ::godot::MethodInfo; using ::godot::ObjectDB; using ::godot::ObjectID; @@ -1253,7 +1273,6 @@ using ::godot::print_error; using ::godot::print_line; using ::godot::print_line_rich; using ::godot::print_verbose; -using ::godot::is_print_verbose_enabled; using ::godot::PropertyInfo; using ::godot::EnableIf; using ::godot::TypesAreSame; @@ -1270,16 +1289,27 @@ using ::godot::MODULE_INITIALIZATION_LEVEL_SCENE; using ::godot::MODULE_INITIALIZATION_LEVEL_EDITOR; using ::godot::MODULE_INITIALIZATION_LEVEL_MAX; using ::godot::GDExtensionBinding; -using ::godot::HashMapData; +using ::godot::Variant; using ::godot::AHashMap; -using ::godot::Vector; -using ::godot::VMap; -using ::godot::CharStringT; -using ::godot::CowData; using ::godot::HashMapElement; -using ::godot::_hashmap_variant_less_than; using ::godot::HashMap; using ::godot::HashSet; +using ::godot::hash_djb2; +using ::godot::hash_djb2_buffer; +using ::godot::hash_djb2_one_32; +using ::godot::hash_one_uint64; +using ::godot::hash64_murmur3_64; +using ::godot::hash_murmur3_one_32; +using ::godot::hash_murmur3_one_64; +using ::godot::hash_murmur3_one_float; +using ::godot::hash_murmur3_one_double; +using ::godot::hash_murmur3_one_real; +using ::godot::hash_rotl32; +using ::godot::hash_fmix32; +using ::godot::hash_murmur3_buffer; +using ::godot::hash_djb2_one_float; +using ::godot::hash_djb2_one_float_64; +using ::godot::hash_djb2_one_64; using ::godot::HashMapHasherDefault; using ::godot::HashHasher; using ::godot::HashableHasher; @@ -1289,6 +1319,10 @@ using ::godot::hash_table_size_primes_inv; using ::godot::List; using ::godot::LocalVector; using ::godot::TightLocalVector; +using ::godot::MutexLock; +using ::godot::MutexImpl; +using ::godot::Mutex; +using ::godot::BinaryMutex; using ::godot::Pair; using ::godot::PairSort; using ::godot::KeyValue; @@ -1301,15 +1335,17 @@ using ::godot::RID_Owner; using ::godot::SafeNumeric; using ::godot::SafeFlag; using ::godot::SafeRefCount; -using ::godot::SearchArray; using ::godot::SelfList; -using ::godot::_DefaultComparator; using ::godot::SortArray; +using ::godot::SortList; +using ::godot::are_spans_equal; +using ::godot::Span; +using ::godot::operator==; +using ::godot::operator!=; using ::godot::SpinLock; -using ::godot::ThreadWorkPool; +using ::godot::Vector; using ::godot::VectorWriteProxy; using ::godot::VSet; -using ::godot::Variant; using ::godot::AABB; using ::godot::Basis; using ::godot::Object; @@ -1329,6 +1365,7 @@ using ::godot::xid_continue; using ::godot::uppercase_letter; using ::godot::lowercase_letter; using ::godot::unicode_letter; +using ::godot::CharStringT; using ::godot::CharProxy; using ::godot::CharString; using ::godot::Char16String; @@ -1394,6 +1431,8 @@ using ::godot::Button; using ::godot::Label; using ::godot::LineEdit; using ::godot::AcceptDialog; +using ::godot::Callable; +using ::godot::AccessibilityServer; using ::godot::AESContext; using ::godot::AimModifier3D; using ::godot::AnimatableBody2D; @@ -1436,6 +1475,8 @@ using ::godot::Node2D; using ::godot::Area2D; using ::godot::Node3D; using ::godot::Area3D; +using ::godot::Texture2D; +using ::godot::AreaLight3D; using ::godot::PackedByteArray; using ::godot::ArrayMesh; using ::godot::PackedInt32Array; @@ -1504,14 +1545,15 @@ using ::godot::AudioStreamPolyphonic; using ::godot::AudioStreamRandomizer; using ::godot::AudioStreamSynchronized; using ::godot::AudioStreamWAV; +using ::godot::AwaitTweener; using ::godot::BackBufferCopy; using ::godot::ButtonGroup; using ::godot::Shortcut; using ::godot::BaseButton; -using ::godot::Texture2D; using ::godot::BaseMaterial3D; using ::godot::Image; using ::godot::BitMap; +using ::godot::BlitMaterial; using ::godot::Bone2D; using ::godot::Skeleton3D; using ::godot::BoneAttachment3D; @@ -1597,7 +1639,6 @@ using ::godot::ConeTwistJoint3D; using ::godot::ConfigFile; using ::godot::ConfirmationDialog; using ::godot::Container; -using ::godot::Callable; using ::godot::Theme; using ::godot::ConvertTransformModifier3D; using ::godot::ConvexPolygonShape2D; @@ -1633,6 +1674,7 @@ using ::godot::DirectionalLight2D; using ::godot::DirectionalLight3D; using ::godot::DisplayServer; using ::godot::DPITexture; +using ::godot::DrawableTexture2D; using ::godot::PacketPeerDTLS; using ::godot::PacketPeerUDP; using ::godot::TLSOptions; @@ -1736,6 +1778,9 @@ using ::godot::FramebufferCacheRD; using ::godot::GDExtension; using ::godot::GDExtensionManager; using ::godot::GDScript; +using ::godot::GDScriptTextDocument; +using ::godot::GDScriptWorkspace; +using ::godot::GDScriptLanguageProtocol; using ::godot::GDScriptSyntaxHighlighter; using ::godot::Generic6DOFJoint3D; using ::godot::Geometry2D; @@ -2036,6 +2081,11 @@ using ::godot::JOY_BUTTON_PADDLE2; using ::godot::JOY_BUTTON_PADDLE3; using ::godot::JOY_BUTTON_PADDLE4; using ::godot::JOY_BUTTON_TOUCHPAD; +using ::godot::JOY_BUTTON_MISC2; +using ::godot::JOY_BUTTON_MISC3; +using ::godot::JOY_BUTTON_MISC4; +using ::godot::JOY_BUTTON_MISC5; +using ::godot::JOY_BUTTON_MISC6; using ::godot::JOY_BUTTON_SDL_MAX; using ::godot::JOY_BUTTON_MAX; using ::godot::JoyAxis; @@ -2356,7 +2406,6 @@ using ::godot::MultiplayerPeerExtension; using ::godot::MultiplayerSpawner; using ::godot::SceneReplicationConfig; using ::godot::MultiplayerSynchronizer; -using ::godot::Mutex; using ::godot::NativeMenu; using ::godot::NavigationPathQueryResult2D; using ::godot::NavigationAgent2D; @@ -2408,6 +2457,7 @@ using ::godot::OpenXRCompositionLayerEquirect; using ::godot::OpenXRCompositionLayerQuad; using ::godot::OpenXRDpadBindingModifier; using ::godot::OpenXRAPIExtension; +using ::godot::OpenXRInteractionProfileMetadata; using ::godot::OpenXRExtensionWrapper; using ::godot::OpenXRExtensionWrapperExtension; using ::godot::OpenXRFrameSynthesisExtension; @@ -2419,13 +2469,13 @@ using ::godot::OpenXRIPBinding; using ::godot::OpenXRIPBindingModifier; using ::godot::OpenXRInteractionProfileEditor; using ::godot::OpenXRInteractionProfileEditorBase; -using ::godot::OpenXRInteractionProfileMetadata; using ::godot::OpenXRInterface; using ::godot::OpenXRMarkerTracker; using ::godot::OpenXRPlaneTracker; using ::godot::OpenXRRenderModel; using ::godot::OpenXRRenderModelExtension; using ::godot::OpenXRRenderModelManager; +using ::godot::OpenXRSpatialComponentData; using ::godot::OpenXRSpatialAnchorCapability; using ::godot::OpenXRSpatialCapabilityConfigurationAnchor; using ::godot::OpenXRSpatialCapabilityConfigurationAprilTag; @@ -2437,7 +2487,6 @@ using ::godot::OpenXRSpatialCapabilityConfigurationQrCode; using ::godot::OpenXRSpatialComponentAnchorList; using ::godot::OpenXRSpatialComponentBounded2DList; using ::godot::OpenXRSpatialComponentBounded3DList; -using ::godot::OpenXRSpatialComponentData; using ::godot::OpenXRSpatialComponentMarkerList; using ::godot::OpenXRSpatialComponentMesh2DList; using ::godot::OpenXRSpatialComponentMesh3DList; @@ -2449,11 +2498,11 @@ using ::godot::OpenXRSpatialComponentPolygon2DList; using ::godot::OpenXRSpatialContextPersistenceConfig; using ::godot::PackedInt64Array; using ::godot::OpenXRSpatialEntityExtension; +using ::godot::OpenXRStructureBase; using ::godot::OpenXRSpatialEntityTracker; using ::godot::OpenXRSpatialMarkerTrackingCapability; using ::godot::OpenXRSpatialPlaneTrackingCapability; using ::godot::OpenXRSpatialQueryResultData; -using ::godot::OpenXRStructureBase; using ::godot::OpenXRVisibilityMask; using ::godot::OptimizedTranslation; using ::godot::OptionButton; @@ -2550,7 +2599,11 @@ using ::godot::RandomNumberGenerator; using ::godot::Range; using ::godot::RayCast2D; using ::godot::RayCast3D; +using ::godot::RDAccelerationStructureGeometry; +using ::godot::RDAccelerationStructureInstance; using ::godot::RDAttachmentFormat; +using ::godot::RDPipelineShader; +using ::godot::RDHitGroup; using ::godot::RDPipelineColorBlendStateAttachment; using ::godot::RDPipelineColorBlendState; using ::godot::RDPipelineDepthStencilState; @@ -2566,6 +2619,7 @@ using ::godot::RDTextureView; using ::godot::RDUniform; using ::godot::RDVertexAttribute; using ::godot::RectangleShape2D; +using ::godot::RefCounted; using ::godot::ReferenceRect; using ::godot::ReflectionProbe; using ::godot::RegExMatch; @@ -2726,6 +2780,7 @@ using ::godot::TranslationServer; using ::godot::Tree; using ::godot::TreeItem; using ::godot::TubeTrailMesh; +using ::godot::Signal; using ::godot::Tweener; using ::godot::TwoBoneIK3D; using ::godot::UDPServer; @@ -2745,6 +2800,7 @@ using ::godot::VideoStream; using ::godot::VideoStreamPlayer; using ::godot::VideoStreamTheora; using ::godot::ViewportTexture; +using ::godot::VirtualJoystick; using ::godot::VisibleOnScreenEnabler2D; using ::godot::VisibleOnScreenEnabler3D; using ::godot::VisibleOnScreenNotifier2D; @@ -2900,9 +2956,6 @@ using ::godot::XRVRS; using ::godot::ZIPPacker; using ::godot::ZIPReader; using ::godot::PackedVector4Array; -using ::godot::Signal; -using ::godot::operator==; -using ::godot::operator!=; using ::godot::operator+; using ::godot::itos; using ::godot::uitos; @@ -2912,13 +2965,10 @@ using ::godot::UtilityFunctions; } export namespace godot::Math { -using ::godot::Math::fmod; -using ::godot::Math::fposmod; -using ::godot::Math::fposmodp; -using ::godot::Math::posmod; -using ::godot::Math::floor; -using ::godot::Math::ceil; -using ::godot::Math::exp; +using ::godot::Math::clamp; +using ::godot::Math::min; +using ::godot::Math::max; +using ::godot::Math::sign; using ::godot::Math::sin; using ::godot::Math::cos; using ::godot::Math::tan; @@ -2931,50 +2981,83 @@ using ::godot::Math::asin; using ::godot::Math::acos; using ::godot::Math::atan; using ::godot::Math::atan2; +using ::godot::Math::asinh; +using ::godot::Math::acosh; +using ::godot::Math::atanh; using ::godot::Math::sqrt; +using ::godot::Math::fmod; +using ::godot::Math::modf; +using ::godot::Math::floor; +using ::godot::Math::ceil; using ::godot::Math::pow; using ::godot::Math::log; +using ::godot::Math::log1p; +using ::godot::Math::log2; +using ::godot::Math::exp; +using ::godot::Math::abs; +using ::godot::Math::is_nan; +using ::godot::Math::is_inf; +using ::godot::Math::division_round_up; +using ::godot::Math::division_no_overflow; +using ::godot::Math::modulo_no_overflow; +using ::godot::Math::is_finite; +using ::godot::Math::fposmod; +using ::godot::Math::fposmodp; +using ::godot::Math::posmod; +using ::godot::Math::deg_to_rad; +using ::godot::Math::rad_to_deg; using ::godot::Math::lerp; -using ::godot::Math::lerp_angle; using ::godot::Math::cubic_interpolate; using ::godot::Math::cubic_interpolate_angle; using ::godot::Math::cubic_interpolate_in_time; using ::godot::Math::cubic_interpolate_angle_in_time; using ::godot::Math::bezier_interpolate; using ::godot::Math::bezier_derivative; -using ::godot::Math::clamp; -using ::godot::Math::min; -using ::godot::Math::max; -using ::godot::Math::sign; -using ::godot::Math::abs; -using ::godot::Math::deg_to_rad; -using ::godot::Math::rad_to_deg; +using ::godot::Math::angle_difference; +using ::godot::Math::lerp_angle; using ::godot::Math::inverse_lerp; using ::godot::Math::remap; -using ::godot::Math::is_nan; -using ::godot::Math::is_inf; -using ::godot::Math::is_finite; using ::godot::Math::is_equal_approx; using ::godot::Math::is_zero_approx; -using ::godot::Math::absf; -using ::godot::Math::absd; +using ::godot::Math::is_same; using ::godot::Math::smoothstep; using ::godot::Math::move_toward; -using ::godot::Math::linear2db; -using ::godot::Math::db2linear; +using ::godot::Math::rotate_toward; +using ::godot::Math::linear_to_db; +using ::godot::Math::db_to_linear; using ::godot::Math::round; -using ::godot::Math::wrapi; using ::godot::Math::wrapf; +using ::godot::Math::wrapi; using ::godot::Math::fract; using ::godot::Math::pingpong; -using ::godot::Math::fast_ftoi; using ::godot::Math::snapped; +using ::godot::Math::fast_ftoi; +using ::godot::Math::halfbits_to_floatbits; +using ::godot::Math::halfptr_to_float; +using ::godot::Math::half_to_float; +using ::godot::Math::make_half_float; using ::godot::Math::snap_scalar; using ::godot::Math::snap_scalar_separation; +using ::godot::Math::SQRT2; +using ::godot::Math::SQRT3; +using ::godot::Math::SQRT12; +using ::godot::Math::SQRT13; +using ::godot::Math::LN2; +using ::godot::Math::TAU; +using ::godot::Math::PI; +using ::godot::Math::E; +using ::godot::Math::is_power_of_2; +using ::godot::Math::next_power_of_2; +using ::godot::Math::previous_power_of_2; +using ::godot::Math::closest_power_of_2; +using ::godot::Math::get_shift_from_power_of_2; +using ::godot::Math::nearest_power_of_2_templated; +using ::godot::Math::nearest_shift; +using ::godot::Math::floor_log2; +using ::godot::Math::get_num_bits; } export namespace godot::helpers { using ::godot::helpers::append_all; } - diff --git a/tests/godot_cpp_module.cpp b/tests/godot_cpp_module.cpp index 843c975..1ba7e82 100644 --- a/tests/godot_cpp_module.cpp +++ b/tests/godot_cpp_module.cpp @@ -54,8 +54,14 @@ int main() { !Math::is_zero_approx(1.0f) && close(Math::lerp(0.0, 10.0, 0.25), 2.5); + const bool attributed_types_ok = sizeof(HashSet) > 0 && sizeof(List) > 0 && + sizeof(RBMap) > 0 && sizeof(RBSet) > 0 && + sizeof(VSet) > 0 && sizeof(SelfList) > 0; + const bool hash_ok = hash_murmur3_one_float(0.0f) == hash_murmur3_one_float(-0.0f) && + hash_murmur3_one_double(0.0) == hash_murmur3_one_double(-0.0); + const bool ok = vec2_ok && vec3_ok && basis_ok && color_ok && aabb_ok && - gen_ok && tmpl_ok; + gen_ok && tmpl_ok && hash_ok && attributed_types_ok; std::println("vec2={} vec3={} basis={} color={} aabb={} gen={} tmpl={}", vec2_ok, vec3_ok, basis_ok, color_ok, aabb_ok, gen_ok, tmpl_ok); return ok ? 0 : 1; diff --git a/tests/macros.cpp b/tests/macros.cpp index f2d230d..c9708a1 100644 --- a/tests/macros.cpp +++ b/tests/macros.cpp @@ -1,3 +1,3 @@ import mcpplibs.mwrap.godot_cpp.macros; namespace macros = mcpplibs::mwrap::godot_cpp::macros; -int main() { static_assert(macros::GODOT_VERSION_MAJOR >= 4); return 0; } +int main() { static_assert(macros::GODOT_VERSION_MAJOR == 4); static_assert(macros::GODOT_VERSION_MINOR == 7); return 0; } diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py index 227fd8d..9bedddb 100644 --- a/tools/check_mwrap_release.py +++ b/tools/check_mwrap_release.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 """Check the immutable mwrap release coordinate and bilingual entry pages.""" import argparse +import hashlib +import json from pathlib import Path import re import tomllib @@ -19,6 +21,21 @@ def main(): assert version == upstream or re.fullmatch(re.escape(upstream) + r'\.[1-9][0-9]*', version), (version, upstream) if args.tag: assert args.tag == 'mwrap-' + version, (args.tag, version) + assert package['license'] == 'Apache-2.0', package['license'] + assert package['authors'] == ['mcpp-community'], package.get('authors') + license_text = (root / 'LICENSE').read_text(encoding='utf-8') + assert 'Apache License' in license_text and 'Version 2.0' in license_text + assert 'mcpp-community' in (root / 'NOTICE').read_text(encoding='utf-8') + documents = json.loads((root / 'upstream/documents.json').read_text(encoding='utf-8'))['documents'] + assert any(Path(d['path']).name.startswith('README') for d in documents) + assert any(Path(d['path']).name.startswith(('LICENSE', 'COPYING')) for d in documents) + deployed = {entry['from'] for entry in tomllib.loads((root / 'mcpp.toml').read_text(encoding='utf-8')).get('runtime', {}).get('deploy', [])} + assert {'LICENSE', 'NOTICE'} <= deployed + for document in documents: + path = Path(document['path']) + assert not path.is_absolute() and '..' not in path.parts and path.parts[0] == 'upstream' + assert hashlib.sha256((root / path).read_bytes()).hexdigest() == document['sha256'], path + assert document['source'] and path.as_posix() in deployed, path identity = package['namespace'] + '.' + package['name'] for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: text = (root / name).read_text(encoding="utf-8") diff --git a/tools/gen_module_cppm.py b/tools/gen_module_cppm.py index fb63143..65a7713 100644 --- a/tools/gen_module_cppm.py +++ b/tools/gen_module_cppm.py @@ -82,7 +82,7 @@ # Attribute-ish macros godot-cpp puts in front of declarations. DECORATORS = { "_ALWAYS_INLINE_", "_FORCE_INLINE_", "_NO_DISCARD_", "GDE_EXPORT", - "_NO_INLINE_", "_ALLOW_DISCARD_", + "_NO_INLINE_", "_ALLOW_DISCARD_", "_WARN_UNUSED_", } @@ -107,7 +107,12 @@ def strip_noise(text: str) -> str: out.append("") continue out.append(line) - return "\n".join(out) + cleaned = "\n".join(out) + # Diagnostic pragma wrappers are standalone preprocessing invocations, + # not namespace declarations. Keep declarations following them intact. + return re.sub( + r'(?m)^[ \t]*GODOT_(?:(?:GCC|CLANG|MSVC)_WARNING_(?:PUSH_AND_IGNORE|IGNORE|PUSH|POP)(?:\([^\n]*\))?|(?:PUSH|POP)_IGNORE_DEPRECATION\(\))[ \t]*;?[ \t]*$', + '', cleaned) def split_template_head(head: str) -> str: @@ -413,6 +418,13 @@ def match_brace(text: str, start: int) -> int: def write_shim(root: Path, out_path: Path) -> None: src = root / "include" / SHIM_REL text = src.read_text(encoding="utf-8") + # Stable 10.x moved both functions out of the header. Preserve that upstream + # ownership and remove the obsolete shadow instead of patching declarations. + functions = ("hash_murmur3_one_float", "hash_murmur3_one_double") + if all(re.search(r"(?m)^uint32_t " + name + r"\([^;{}]+\);$", text) for name in functions): + out_path.unlink(missing_ok=True) + sys.stderr.write(f"no shim needed: upstream defines both hash functions out of line\n") + return for old, new in SHIM_EDITS: if text.count(old) != 1: raise SystemExit( diff --git a/tools/test_gen_module_cppm.py b/tools/test_gen_module_cppm.py new file mode 100644 index 0000000..7de3e15 --- /dev/null +++ b/tools/test_gen_module_cppm.py @@ -0,0 +1,25 @@ +import unittest +from gen_module_cppm import Scanner + + +class StableDeclarations(unittest.TestCase): + def test_warning_wrappers_and_record_attributes_preserve_real_names(self): + scanner = Scanner() + scanner.scan('''namespace godot { +GODOT_GCC_WARNING_PUSH +GODOT_GCC_WARNING_IGNORE("-Wclass-memaccess") +template class _WARN_UNUSED_ HashSet { T value; }; +GODOT_GCC_WARNING_POP +class _WARN_UNUSED_ List {}; +GODOT_PUSH_IGNORE_DEPRECATION() +void normal_function(); +GODOT_POP_IGNORE_DEPRECATION() +}''') + names = scanner.exported("godot") + self.assertEqual(set(names), {"HashSet", "List", "normal_function"}) + self.assertNotIn("_WARN_UNUSED_", names) + self.assertNotIn("GODOT_GCC_WARNING_IGNORE", names) + + +if __name__ == "__main__": + unittest.main() diff --git a/upstream/documents.json b/upstream/documents.json new file mode 100644 index 0000000..600acda --- /dev/null +++ b/upstream/documents.json @@ -0,0 +1,20 @@ +{ + "upstream": "https://github.com/godotengine/godot-cpp/tree/10.0.0-stable", + "documents": [ + { + "path": "upstream/godot-cpp/README.md", + "source": "https://github.com/godotengine/godot-cpp/tree/10.0.0-stable/README.md", + "sha256": "be3baedc5a896c42a9a3f208f00302f87e87755aea566782a578ad9b21a12aea" + }, + { + "path": "upstream/godot-cpp/LICENSE.md", + "source": "https://github.com/godotengine/godot-cpp/tree/10.0.0-stable/LICENSE.md", + "sha256": "26a5b210d90760156ce886267ce9df235787dcc6cebfd7ecd95ef5b6fdcc95bf" + }, + { + "path": "upstream/wrapper-legacy/LICENSE", + "source": "Previous wrapper LICENSE, retained copyright and permission notice", + "sha256": "02bfee1a9607e16b7ac6b178593d42ff142376c6de0e5340057f6223926e5f67" + } + ] +} diff --git a/upstream/godot-cpp/LICENSE.md b/upstream/godot-cpp/LICENSE.md new file mode 100644 index 0000000..eb446fe --- /dev/null +++ b/upstream/godot-cpp/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2017-present Godot Engine contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/upstream/godot-cpp/README.md b/upstream/godot-cpp/README.md new file mode 100644 index 0000000..b05cc20 --- /dev/null +++ b/upstream/godot-cpp/README.md @@ -0,0 +1,123 @@ +# godot-cpp + +> [!NOTE] +> +> For GDNative (Godot 3.x), switch to the [`3.x`](https://github.com/godotengine/godot-cpp/tree/3.x) +> or the [`3.6`](https://github.com/godotengine/godot-cpp/tree/3.6) branch. + +This repository contains the *C++ bindings* for the [**Godot Engine**](https://github.com/godotengine/godot)'s GDExtensions API. + +- [**Versioning**](#versioning) +- [**Compatibility**](#compatibility) +- [**Contributing**](#contributing) +- [**Getting started**](#getting-started) +- [**Examples and templates**](#examples-and-templates) + +## Versioning + +Starting with version 10.x, godot-cpp is versioned independently from Godot. +Using the `api_version` parameter (see below), godot-cpp v10 can target Godot 4.3 or later. + +## Compatibility + +GDExtensions targeting an earlier version of Godot should work in later minor versions, +but not vice-versa. For example, a GDExtension targeting Godot 4.3 should work just fine +in Godot 4.4, but one targeting Godot 4.4 won't work in Godot 4.3. + +You can specify which version you are targeting with the `api_version` option: + +``` +scons api_version=4.3 +``` + +... or by providing a custom `extension_api.json` generated by the Godot version you are +targeting: + +``` +godot --dump-extension-api +scons custom_api_file=extension_api.json +``` + +Extension authors can provide a default target API version by passing it to godot-cpp's +`SConstruct`, for example: + +```python +env = SConscript("godot-cpp/SConstruct", {"api_version": "4.7"}) +``` + +This is highly recommended! It allows the extension author to ensure that their extension +is built with a version that provides all the necessary features by default. + +## Contributing + +We greatly appreciate help in maintaining and extending this project. If you +wish to help out, please visit the [godot-cpp section of the Contributing docs](https://contributing.godotengine.org/en/latest/development/other/godot-cpp.html). + +## Getting started + +You need the same C++ pre-requisites installed that are required for the `godot` repository. Follow the [official build instructions for your target platform](https://docs.godotengine.org/en/latest/engine_details/development/compiling/index.html). + +Building your extension will create a shared library. To use this in your Godot project you'll need a `.gdextension` +file, for example: + +```ini +[configuration] + +entry_symbol = "example_library_init" +compatibility_minimum = "4.1" + +[libraries] + +macos.debug = "res://bin/libgdexample.macos.debug.framework" +macos.release = "res://bin/libgdexample.macos.release.framework" +windows.debug.x86_64 = "res://bin/libgdexample.windows.debug.x86_64.dll" +windows.release.x86_64 = "res://bin/libgdexample.windows.release.x86_64.dll" +linux.debug.x86_64 = "res://bin/libgdexample.linux.debug.x86_64.so" +linux.release.x86_64 = "res://bin/libgdexample.linux.release.x86_64.so" +# Repeat for other architectures to support arm64, rv64, etc. +``` + +See the [example.gdextension](https://github.com/godotengine/godot-cpp-template/blob/main/demo/bin/example.gdextension) +used in the template project for a complete example. + +The `entry_symbol` is the name of the function that initializes your library, for example: + +```cpp +extern "C" { + +// Initialization. + +GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) { + godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); + + init_obj.register_initializer(initialize_example_module); + init_obj.register_terminator(uninitialize_example_module); + init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE); + + return init_obj.init(); +} +} +``` + +The `initialize_example_module()` should register the classes in ClassDB, similar to a Godot module: + +```cpp +using namespace godot; +void initialize_example_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + GDREGISTER_CLASS(Example); +} +``` + +Any node and resource you register will be available in the corresponding `Create...` dialog. +Any class will be available to scripting as well. + +## Examples and templates + +See the [godot-cpp-template](https://github.com/godotengine/godot-cpp-template) project for a +generic reusable template. + +Or checkout the code for the [Summator example](https://github.com/paddy-exe/GDExtensionSummator) +as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/gdextension_cpp_example.html). diff --git a/upstream/sources.lock.toml b/upstream/sources.lock.toml new file mode 100644 index 0000000..a78d592 --- /dev/null +++ b/upstream/sources.lock.toml @@ -0,0 +1,13 @@ +[godot-cpp] +version = "10.0.0" +tag = "10.0.0-stable" +commit = "507ed9d840c01a3c5b2a39af8bb4000bfac30bf5" +repo = "https://github.com/godotengine/godot-cpp" +upstream-archive-sha256 = "ebbf64f0f8f8b8b66bc4bc4d3797db97f95b19cf0dfb5b3f8cf56683d9df7db4" +provider = "compat.godot-cpp@10.0.0" +provider-archive-sha256 = "66aaafb642e7a390482dc381818640b1d0e583da2ef0cc9709214bcd13b68264" +engine-api = "4.7" +architecture-bits = 64 +precision = "single" +template-get-node = true +generation = "Unmodified upstream binding_generator.py; upstream tree byte-identical; gen/ is the only addition" diff --git a/upstream/wrapper-legacy/LICENSE b/upstream/wrapper-legacy/LICENSE new file mode 100644 index 0000000..ec6c5d0 --- /dev/null +++ b/upstream/wrapper-legacy/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 godot-cpp-m module contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.