diff --git a/docs/reference/utility.md b/docs/reference/utility.md index 6be8ae7a6..1cadd53e8 100644 --- a/docs/reference/utility.md +++ b/docs/reference/utility.md @@ -76,6 +76,15 @@ tail mixing, result word order and the existing public signatures are unchanged; `murmur_hash3_x86_128` remains an instance method, and the other variants remain static. MurmurHash2 retains its fixed seed zero. +The Murmur header itself uses only standard C++20 headers. It does not include +`ark/macros.hpp` or `ark/platform.hpp`; callers using their declarations or macros +must include those headers explicitly. Public macro definitions are unchanged. +This header independence does not change `ark::core` or its CMake package's +dependency requirements. `check-murmur-hash-header` compiles the logical public +header with an isolated include directory and no SDK target dependencies; it is +also included in `check-core`. See [core regressions](../../tests/core/README.md) +for the standalone check commands. + ### Digest compatibility and legacy access **Breaking change:** default MurmurHash3 now reads full blocks as little endian diff --git a/docs/reference/utility_CN.md b/docs/reference/utility_CN.md index 747cec544..18fb89616 100644 --- a/docs/reference/utility_CN.md +++ b/docs/reference/utility_CN.md @@ -68,6 +68,12 @@ MurmurHash3 使用 C++20 `std::rotl`,旋转次数保持不变。种子、尾 原有公开签名不变;`murmur_hash3_x86_128` 仍为实例方法,其余变体仍为静态方法。 MurmurHash2 保留固定种子零。 +Murmur 头文件自身仅使用标准 C++20 头文件,不再包含 `ark/macros.hpp` 或 +`ark/platform.hpp`。调用方若使用其中的声明或宏,须显式包含对应头文件;公开宏定义 +保持不变。头文件独立性不改变 `ark::core` 或其 CMake 包的依赖要求。 +`check-murmur-hash-header` 仅通过隔离的包含目录编译逻辑公开头文件,不依赖 SDK +目标,并纳入 `check-core`。独立检查命令见[核心回归](../../tests/core/README_CN.md)。 + ### 摘要兼容性与旧结果入口 **不兼容变更:** 默认 MurmurHash3 现在在所有支持的平台上按小端方式读取完整块, diff --git a/docs/site/package-lock.json b/docs/site/package-lock.json index 37ca23691..cf2c3678b 100644 --- a/docs/site/package-lock.json +++ b/docs/site/package-lock.json @@ -3442,9 +3442,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", - "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.9.tgz", + "integrity": "sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==", "dev": true, "funding": [ { diff --git a/src/core/container/consistent_hash.hpp b/src/core/container/consistent_hash.hpp index 2932a634e..3c8f8fb6f 100644 --- a/src/core/container/consistent_hash.hpp +++ b/src/core/container/consistent_hash.hpp @@ -23,6 +23,7 @@ #include "ark/dep.hpp" #include "ark/hash/crc.hpp" #include "ark/hash/murmur_hash.hpp" +#include "ark/macros.hpp" namespace ark { diff --git a/src/core/hash/murmur_hash.hpp b/src/core/hash/murmur_hash.hpp index 20fbdc7fd..a7b793c17 100644 --- a/src/core/hash/murmur_hash.hpp +++ b/src/core/hash/murmur_hash.hpp @@ -28,9 +28,6 @@ #include #include -#include "ark/macros.hpp" -#include "ark/platform.hpp" - namespace ark { class murmur_hash @@ -289,8 +286,8 @@ class murmur_hash uint64_t h1 = seed; uint64_t h2 = seed; - const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5); - const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f); + const uint64_t c1 = 0x87c37b91114253d5ULL; + const uint64_t c2 = 0x4cf5ad432745937fULL; //---------- // body @@ -492,9 +489,9 @@ class murmur_hash static uint64_t fmix(uint64_t k) { k ^= k >> 33; - k *= BIG_CONSTANT(0xff51afd7ed558ccd); + k *= 0xff51afd7ed558ccdULL; k ^= k >> 33; - k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); + k *= 0xc4ceb9fe1a85ec53ULL; k ^= k >> 33; return k; diff --git a/tests/app/net_plugin.cpp b/tests/app/net_plugin.cpp index 6eb53f4a3..e89307883 100644 --- a/tests/app/net_plugin.cpp +++ b/tests/app/net_plugin.cpp @@ -37,6 +37,33 @@ void wait_for(predicate ready, pump update) { require(ready(), "Timed out waiting for owned loopback peer"); } +arknet::error_code listener_probe(asio::io_context&, const asio::ip::tcp::endpoint& endpoint) { + asio::io_context context; + asio::ip::tcp::socket probe(context); + asio::steady_timer deadline(context, 5s); + arknet::error_code result = asio::error::operation_aborted; + bool completed = false; + bool timed_out = false; + deadline.async_wait([&](const arknet::error_code& error) { + if (!error && !completed) + { + timed_out = true; + arknet::error_code ignored; + probe.cancel(ignored); + probe.close(ignored); + } + }); + probe.async_connect(endpoint, [&](const arknet::error_code& error) { + completed = true; + result = timed_out ? arknet::error_code(asio::error::timed_out) : error; + deadline.cancel(); + }); + // Drain both the connect completion and the cancelled timer before their + // stack captures go out of scope. A deadline is not a refused connection. + context.run(); + return result; +} + struct receiver { void on_message(const ark::net_msg* message, ark::conv_id_t session) { @@ -86,8 +113,17 @@ int main(int argc, char* argv[]) { receiver received; require(server->reg_msg_callback(45000, &received, &receiver::on_message), "Net message callback rejected"); std::weak_ptr endpoint = server->get_net(); + const asio::ip::tcp::endpoint listener_endpoint(asio::ip::make_address("127.0.0.1"), port); + const auto live_probe = listener_probe(context, listener_endpoint); + require(!live_probe, "Live Net listener negative control failed: " + live_probe.message()); + std::atomic peer_closed{}; + arknet::error_code peer_close_error; arknet::tcp_client client; client.set_auto_reconnect(false); + client.bind_disconnect([&] { + peer_close_error = arknet::get_last_error(); + peer_closed.store(true); + }); require(client.start("127.0.0.1", port), "Owned TCP peer failed to start"); ark::s_msg_header header; header.set_message_id(45000); @@ -143,16 +179,27 @@ int main(int argc, char* argv[]) { const auto cancelled = pending.get(); require(!cancelled.first && cancelled.second == arknet::error_code(asio::error::operation_aborted).message(), "HTTP DSO shutdown changed pending-request cancellation"); - client.stop(); peer.stop(); + require(client.is_started() && !peer_closed.load(), "Owned TCP peer must remain live across Net shutdown"); server.reset(); require(manager.stop(++tick), "Net DSO shutdown did not complete"); require(endpoint.expired(), "Net listener survived normal module unregistration"); require(manager.get_shutdown_state() == ark::plugin_manager::shutdown_state::stopped, "Net resources were retained instead of normally stopped"); + // Keep the peer open until the server closes its accepted socket. Stopping + // the client first would hide a retained server-side connection. + wait_for([&] { return peer_closed.load(); }, [] {}); + require(peer_close_error == asio::error::eof || peer_close_error == asio::error::connection_reset, + "Net shutdown did not remotely close the owned TCP peer: " + peer_close_error.message()); + client.stop(); require(manager.stop(++tick), "Repeated Net shutdown failed"); - asio::ip::tcp::acceptor rebound(context, {asio::ip::make_address("127.0.0.1"), port}); - require(rebound.is_open(), "Net shutdown did not release its listener"); - std::cout << "Net actual DSOs: interface RTTI lookup, manager-owned TCP/HTTP callbacks, listener release and " + // Binding the same port also tests unrelated kernel port-reuse state. A + // refused new connection checks listener closure directly, with no retry. + // The successful probe above is the negative control for a live listener. + const auto closed_probe = listener_probe(context, listener_endpoint); + require(closed_probe == asio::error::connection_refused, + "Net listener closure probe must be refused: " + closed_probe.message()); + std::cout << "Net actual DSOs: interface RTTI lookup, manager-owned TCP/HTTP callbacks, listener refusal, remote " + "peer closure and " "normal repeated shutdown passed\n"; } diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt index 768a291bb..0d324c919 100644 --- a/tests/core/CMakeLists.txt +++ b/tests/core/CMakeLists.txt @@ -4,11 +4,13 @@ add_library(ark_core_header_checks OBJECT headers/queue.cpp headers/guid128.cpp headers/object_vector.cpp headers/error_code.cpp headers/logger.cpp headers/murmur_hash.cpp) target_link_libraries(ark_core_header_checks PRIVATE ark::core) +add_subdirectory(hash_header) + add_executable(ark_core_tests main.cpp strings.cpp containers.cpp templates.cpp callbacks.cpp header_regressions.cpp cxx20_language.cpp concurrency.cpp plugin_manager_startup.cpp data_strings.cpp node_data_storage.cpp object_vectors.cpp plugin_construction.cpp module_factory.cpp random_generator.cpp xxtea.cpp murmur_hash.cpp) target_link_libraries(ark_core_tests PRIVATE ark::core ark::kernel ark::utility) -add_dependencies(ark_core_tests ark_core_header_checks) +add_dependencies(ark_core_tests ark_core_header_checks ark_murmur_hash_standalone_check) add_library(ark_construction_header_checks OBJECT headers/module_base.cpp headers/plugin_base.cpp) set_property(TARGET ark_construction_header_checks PROPERTY LINK_LIBRARIES ark::core) add_dependencies(ark_core_tests ark_construction_header_checks) diff --git a/tests/core/README.md b/tests/core/README.md index d57d4a947..bfe66a033 100644 --- a/tests/core/README.md +++ b/tests/core/README.md @@ -30,6 +30,19 @@ See [Murmur compatibility](../../docs/reference/utility.md#core-murmur-hashes) for canonical little-endian output and the explicit legacy MSVC migration path. AddressSanitizer and UndefinedBehaviorSanitizer builds exercise overread and alignment checks. +The existing mapped public-header check remains. An additional compile-only check +stages just `` and uses C++20 without project, platform, +spdlog or Boost include paths or SDK target dependencies. It is part of +`check-core` and can also run without configuring the full dependency graph: + +```sh +cmake -S tests/core/hash_header -B hash-header-build -G Ninja +cmake --build hash-header-build --target check-murmur-hash-header +``` + +Header independence does not remove the dependencies required by `ark::core` or +its CMake package. + With `ARK_BUILD_PROTO=ON`, additional cases verify Protobuf parse failures, actor identity, binary messages, legacy wire payloads and external JSON field names. They also exercise the new `ark::protobuf` descriptor and enum names. diff --git a/tests/core/README_CN.md b/tests/core/README_CN.md index 12571eea9..56005e362 100644 --- a/tests/core/README_CN.md +++ b/tests/core/README_CN.md @@ -27,6 +27,17 @@ Murmur 回归包含独立的上游 SMHasher 验证常量、旧版完整块交换 [Murmur 兼容性说明](../../docs/reference/utility_CN.md#core-murmur-哈希)。 AddressSanitizer 和 UndefinedBehaviorSanitizer 构建可检查越界读取和无效对齐。 +现有公开头映射检查继续保留。新增的纯编译检查仅映射 ``, +使用 C++20,不引入项目、平台、spdlog 或 Boost 包含路径,也不依赖 SDK 目标。 +该检查纳入 `check-core`,也可独立运行,无需配置完整依赖图: + +```sh +cmake -S tests/core/hash_header -B hash-header-build -G Ninja +cmake --build hash-header-build --target check-murmur-hash-header +``` + +头文件独立性不改变 `ark::core` 或其 CMake 包所需的依赖。 + 公共头检查将 `` 放在首个包含位置,并重复包含两次;编译期断言 验证其无符号 32 位底层类型及所有已声明的错误值。 diff --git a/tests/core/hash_header/CMakeLists.txt b/tests/core/hash_header/CMakeLists.txt new file mode 100644 index 000000000..f12fbb21b --- /dev/null +++ b/tests/core/hash_header/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.21) +project(ark_murmur_hash_header_check LANGUAGES CXX) + +# Only this logical public header is available; no project or third-party SDK. +set(hash_include_dir "${CMAKE_CURRENT_BINARY_DIR}/include") +configure_file("${CMAKE_CURRENT_LIST_DIR}/../../../src/core/hash/murmur_hash.hpp" + "${hash_include_dir}/ark/hash/murmur_hash.hpp" COPYONLY) +add_library(ark_murmur_hash_standalone_check OBJECT ../headers/murmur_hash.cpp) +# Drop the parent project's directory-wide ark::ark link and include paths. +set_target_properties(ark_murmur_hash_standalone_check PROPERTIES + LINK_LIBRARIES "" + INCLUDE_DIRECTORIES "${hash_include_dir}" + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF) +add_custom_target(check-murmur-hash-header DEPENDS ark_murmur_hash_standalone_check)