From 73561f10a3c2ec02a8736479d099252f541c8ce7 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Thu, 22 Dec 2022 17:12:05 -0500 Subject: [PATCH] support c++ tools on macos (#2063) Running reference tests/decompiler should now be possible on macos (arm). Most of the changes were just cleaning up places where we were sloppy with ifdefs, but there were two interesting ones: - `Printer.cpp` was updated to not use a recursive function for printing lists, to avoid stack overflow - I replaced xxhash with another version of the same library that supports arm (the one that comes in zstd). The interface is C instead of C++ but it's not bad to use. I confirmed that the extractor succeeds on jak 1 iso so it looks like this gives us the same results as the old library. --- .gitignore | 4 + CMakeLists.txt | 28 + common/CMakeLists.txt | 2 + common/common_types.h | 4 + common/cross_os_debug/xdbg.cpp | 48 + common/cross_os_debug/xdbg.h | 2 +- common/cross_sockets/XSocket.cpp | 17 +- common/cross_sockets/XSocket.h | 7 +- common/cross_sockets/XSocketServer.cpp | 3 +- common/cross_sockets/XSocketServer.h | 1 + common/global_profiler/GlobalProfiler.cpp | 11 +- common/global_profiler/GlobalProfiler.h | 2 +- common/goos/Printer.cpp | 14 +- common/util/FrameLimiter.cpp | 4 +- common/util/Timer.cpp | 6 +- common/util/crc32.cpp | 23 +- common/util/os.cpp | 7 + common/util/read_iso_file.cpp | 4 +- common/util/read_iso_file.h | 4 +- decompiler/IR2/Form.cpp | 4 +- decompiler/extractor/extractor_util.hpp | 88 +- decompiler/extractor/main.cpp | 2 +- decompiler/level_extractor/fr3_to_gltf.cpp | 2 + game/kernel/common/kmachine.cpp | 4 +- game/kernel/common/kmachine.h | 2 +- game/kernel/common/kprint.h | 8 +- game/kernel/jak1/kmachine.cpp | 14 +- game/kernel/jak2/kmachine.cpp | 14 +- game/runtime.cpp | 8 +- game/system/SystemThread.cpp | 7 +- goalc/build_level/collide_pack.cpp | 1 + goalc/debugger/Debugger.cpp | 2 + goalc/emitter/CodeTester.cpp | 3 +- test/offline/framework/orchestration.cpp | 2 +- test/offline/offline_test_main.cpp | 10 +- third-party/xxhash.hpp | 1942 -------------------- 36 files changed, 254 insertions(+), 2050 deletions(-) delete mode 100644 third-party/xxhash.hpp diff --git a/.gitignore b/.gitignore index 54b409f92d..4b2ebfba39 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,10 @@ decompiler_out/* decompiler_out2/* logs/* +# for vscode/clangd +.cache/* +.DS_Store + # wsl apparently builds to here? linux-default/ diff --git a/CMakeLists.txt b/CMakeLists.txt index c3fce75498..c0c3caf097 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,34 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") endif() set(THIRDPARTY_IGNORED_WARNINGS "-w") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + message(STATUS "AppleClang detected - Setting Defaults") + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} \ + -Wall \ + -Winit-self \ + -ggdb \ + -Wextra \ + -Wno-cast-align \ + -Wcast-qual \ + -Wdisabled-optimization \ + -Wformat \ + -Wextra \ + -Wmissing-include-dirs \ + -Woverloaded-virtual \ + -Wredundant-decls \ + -Wshadow \ + -Wsign-promo \ + -O3 \ + -fdiagnostics-color=always" + ) + + # additional c++ flags for release mode for our projects + if(CMAKE_BUILD_TYPE MATCHES "Release") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") + endif() + set(THIRDPARTY_IGNORED_WARNINGS "-w") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-stack_size -Wl,0x20000000") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") message(STATUS "MSVC detected - Setting Defaults") diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 06d1ec91be..9177c46667 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -57,6 +57,8 @@ target_link_libraries(common fmt lzokay replxx libzstd_static) if(WIN32) target_link_libraries(common wsock32 ws2_32 windowsapp) +elseif(APPLE) + # don't need anything special else() target_link_libraries(common stdc++fs) endif() diff --git a/common/common_types.h b/common/common_types.h index 5c9c55e267..7e0cbcedb1 100644 --- a/common/common_types.h +++ b/common/common_types.h @@ -30,3 +30,7 @@ struct u128 { }; }; static_assert(sizeof(u128) == 16, "u128"); + +#if defined __linux || defined __linux__ || defined __APPLE__ +#define OS_POSIX +#endif diff --git a/common/cross_os_debug/xdbg.cpp b/common/cross_os_debug/xdbg.cpp index 3768baab34..2a9d7c1cef 100644 --- a/common/cross_os_debug/xdbg.cpp +++ b/common/cross_os_debug/xdbg.cpp @@ -688,6 +688,54 @@ bool set_regs_now(const ThreadID& tid, const Regs& out) { // todo, set fprs. return true; } +#elif __APPLE__ +ThreadID::ThreadID(const std::string& str) {} + +std::string ThreadID::to_string() const { + return "invalid"; +} + +ThreadID get_current_thread_id(); +bool attach_and_break(const ThreadID& tid); +void allow_debugging(); +bool detach_and_resume(const ThreadID& tid) { + return false; +} +bool get_regs_now(const ThreadID& tid, Regs* out) { + return false; +} +bool set_regs_now(const ThreadID& tid, const Regs& in) { + return false; +} +bool break_now(const ThreadID& tid) { + return false; +} +bool cont_now(const ThreadID& tid) { + return false; +} +bool open_memory(const ThreadID& tid, MemoryHandle* out); +bool close_memory(const ThreadID& tid, MemoryHandle* handle) { + return false; +} +bool read_goal_memory(u8* dest_buffer, + int size, + u32 goal_addr, + const DebugContext& context, + const MemoryHandle& mem) { + return false; +} + +bool write_goal_memory(const u8* src_buffer, + int size, + u32 goal_addr, + const DebugContext& context, + const MemoryHandle& mem) { + return false; +} + +bool check_stopped(const ThreadID& tid, SignalInfo* out) { + return false; +} #endif const char* gpr_names[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", diff --git a/common/cross_os_debug/xdbg.h b/common/cross_os_debug/xdbg.h index d928c37c94..2a01c4593b 100644 --- a/common/cross_os_debug/xdbg.h +++ b/common/cross_os_debug/xdbg.h @@ -20,7 +20,7 @@ #endif namespace xdbg { -#ifdef __linux +#ifdef OS_POSIX /*! * Identification for a thread. diff --git a/common/cross_sockets/XSocket.cpp b/common/cross_sockets/XSocket.cpp index 1200743d6f..4154e5e44a 100644 --- a/common/cross_sockets/XSocket.cpp +++ b/common/cross_sockets/XSocket.cpp @@ -4,7 +4,8 @@ */ // clang-format off -#ifdef __linux +#include "common/common_types.h" +#ifdef OS_POSIX #include #include #include @@ -22,7 +23,7 @@ // clang-format on int open_socket(int af, int type, int protocol) { -#ifdef __linux +#ifdef OS_POSIX return socket(af, type, protocol); #elif _WIN32 WSADATA wsaData = {0}; @@ -45,7 +46,7 @@ int connect_socket(int socket, sockaddr* addr, int nameLen) { return result; } -#ifdef __linux +#ifdef OS_POSIX int accept_socket(int socket, sockaddr* addr, socklen_t* addrLen) { return accept(socket, addr, addrLen); } @@ -106,7 +107,7 @@ void close_socket(int sock) { if (sock < 0) { return; } -#ifdef __linux +#ifdef OS_POSIX close(sock); #elif _WIN32 closesocket(sock); @@ -130,7 +131,7 @@ int set_socket_option(int socket, int level, int optname, const void* optval, in } int set_socket_timeout(int socket, long microSeconds) { -#ifdef __linux +#ifdef OS_POSIX struct timeval timeout = {}; timeout.tv_sec = 0; timeout.tv_usec = microSeconds; @@ -150,7 +151,7 @@ int set_socket_timeout(int socket, long microSeconds) { int write_to_socket(int socket, const char* buf, int len) { int bytes_wrote = 0; -#ifdef __linux +#ifdef OS_POSIX bytes_wrote = send(socket, buf, len, MSG_NOSIGNAL); #elif _WIN32 bytes_wrote = send(socket, buf, len, 0); @@ -162,7 +163,7 @@ int write_to_socket(int socket, const char* buf, int len) { } int read_from_socket(int socket, char* buf, int len) { -#ifdef __linux +#ifdef OS_POSIX return read(socket, buf, len); #elif _WIN32 return recv(socket, buf, len, 0); @@ -170,7 +171,7 @@ int read_from_socket(int socket, char* buf, int len) { } bool socket_timed_out() { -#ifdef __linux +#ifdef OS_POSIX return errno == EAGAIN; #elif _WIN32 auto err = WSAGetLastError(); diff --git a/common/cross_sockets/XSocket.h b/common/cross_sockets/XSocket.h index ce9143cc94..a6dd4e5b05 100644 --- a/common/cross_sockets/XSocket.h +++ b/common/cross_sockets/XSocket.h @@ -6,7 +6,8 @@ */ // clang-format off -#ifdef __linux +#include "common/common_types.h" +#ifdef OS_POSIX #include #include #include @@ -24,11 +25,13 @@ const int TCP_SOCKET_LEVEL = SOL_TCP; #elif _WIN32 const int TCP_SOCKET_LEVEL = IPPROTO_TCP; +#elif __APPLE__ +const int TCP_SOCKET_LEVEL = IPPROTO_TCP; #endif int open_socket(int af, int type, int protocol); int connect_socket(int socket, sockaddr* addr, int nameLen); -#ifdef __linux +#ifdef OS_POSIX int accept_socket(int socket, sockaddr* addr, socklen_t* addrLen); int select_and_accept_socket(int socket, sockaddr* addr, socklen_t* addrLen, int microSeconds); #elif _WIN32 diff --git a/common/cross_sockets/XSocketServer.cpp b/common/cross_sockets/XSocketServer.cpp index 6a47671dc7..dd5e5fd9e9 100644 --- a/common/cross_sockets/XSocketServer.cpp +++ b/common/cross_sockets/XSocketServer.cpp @@ -2,6 +2,7 @@ #include "XSocketServer.h" #include "common/cross_sockets/XSocket.h" +#include "common/common_types.h" #include "third-party/fmt/core.h" @@ -41,7 +42,7 @@ bool XSocketServer::init_server() { return false; } -#ifdef __linux +#ifdef OS_POSIX int server_socket_opt = SO_REUSEADDR | SO_REUSEPORT; #elif _WIN32 int server_socket_opt = SO_EXCLUSIVEADDRUSE; diff --git a/common/cross_sockets/XSocketServer.h b/common/cross_sockets/XSocketServer.h index 5d9e0899ba..495868c3c9 100644 --- a/common/cross_sockets/XSocketServer.h +++ b/common/cross_sockets/XSocketServer.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "common/common_types.h" #include "common/cross_sockets/XSocket.h" diff --git a/common/global_profiler/GlobalProfiler.cpp b/common/global_profiler/GlobalProfiler.cpp index 1a459dfd7c..04ce0e3c46 100644 --- a/common/global_profiler/GlobalProfiler.cpp +++ b/common/global_profiler/GlobalProfiler.cpp @@ -7,21 +7,22 @@ #include "common/util/Assert.h" #include "common/util/FileUtil.h" +#include "common/common_types.h" #include "third-party/fmt/core.h" #include "third-party/json.hpp" -#ifdef __linux__ -u32 get_current_tid() { - return (u32)pthread_self(); +#ifdef OS_POSIX +u64 get_current_tid() { + return (u64)pthread_self(); } #else #define NOMINMAX #define WIN32_LEAN_AND_MEAN #include #include "Processthreadsapi.h" -u32 get_current_tid() { - return (u32)GetCurrentThreadId(); +u64 get_current_tid() { + return (u64)GetCurrentThreadId(); } #endif #include "common/log/log.h" diff --git a/common/global_profiler/GlobalProfiler.h b/common/global_profiler/GlobalProfiler.h index b155a646c0..a156517a04 100644 --- a/common/global_profiler/GlobalProfiler.h +++ b/common/global_profiler/GlobalProfiler.h @@ -8,9 +8,9 @@ struct ProfNode { u64 ts; + u64 tid; char name[32]; enum Kind : u8 { BEGIN, END, INSTANT, UNUSED } kind = UNUSED; - u32 tid; }; class GlobalProfiler { diff --git a/common/goos/Printer.cpp b/common/goos/Printer.cpp index 35b1577583..489ac90279 100644 --- a/common/goos/Printer.cpp +++ b/common/goos/Printer.cpp @@ -3,6 +3,8 @@ #include #include +#include "common/goos/Object.h" + #include "third-party/fmt/core.h" namespace pretty_print { @@ -74,14 +76,12 @@ goos::Object build_list(const std::vector& objects) { // build a list out of an array of forms goos::Object build_list(const goos::Object* objects, int count) { ASSERT(count); - auto car = objects[0]; - goos::Object cdr; - if (count - 1) { - cdr = build_list(objects + 1, count - 1); - } else { - cdr = goos::Object::make_empty_list(); + goos::Object result = goos::Object::make_empty_list(); + for (int i = count; i-- > 0;) { + result = goos::PairObject::make_new(objects[i], result); } - return goos::PairObject::make_new(car, cdr); + + return result; } // build a list out of a vector of strings that are converted to symbols diff --git a/common/util/FrameLimiter.cpp b/common/util/FrameLimiter.cpp index 8c8f1e6067..5aee6baa8f 100644 --- a/common/util/FrameLimiter.cpp +++ b/common/util/FrameLimiter.cpp @@ -2,6 +2,8 @@ #include +#include "common/common_types.h" + double FrameLimiter::round_to_nearest_60fps(double current) { double one_frame = 1.f / 60.f; int frames_missed = (current / one_frame); // rounds down @@ -11,7 +13,7 @@ double FrameLimiter::round_to_nearest_60fps(double current) { return (frames_missed + 1) * one_frame; } -#ifdef __linux__ +#ifdef OS_POSIX FrameLimiter::FrameLimiter() {} diff --git a/common/util/Timer.cpp b/common/util/Timer.cpp index 6050c990a0..4aad44cdb1 100644 --- a/common/util/Timer.cpp +++ b/common/util/Timer.cpp @@ -1,5 +1,7 @@ #include "Timer.h" +#include "common/common_types.h" + #ifdef _WIN32 #define NOMINMAX #define WIN32_LEAN_AND_MEAN @@ -37,7 +39,7 @@ int Timer::clock_gettime_monotonic(struct timespec* tv) const { #endif void Timer::start() { -#ifdef __linux__ +#ifdef OS_POSIX clock_gettime(CLOCK_MONOTONIC, &_startTime); #elif _WIN32 clock_gettime_monotonic(&_startTime); @@ -46,7 +48,7 @@ void Timer::start() { int64_t Timer::getNs() const { struct timespec now = {}; -#ifdef __linux__ +#ifdef OS_POSIX clock_gettime(CLOCK_MONOTONIC, &now); #elif _WIN32 clock_gettime_monotonic(&now); diff --git a/common/util/crc32.cpp b/common/util/crc32.cpp index dc75238cc6..001039b1b0 100644 --- a/common/util/crc32.cpp +++ b/common/util/crc32.cpp @@ -1,6 +1,26 @@ #include "crc32.h" #include + +#ifdef __APPLE__ +#include +u32 crc32(const u8* data, size_t size) { + u32 result = 0xffffffff; + while (size >= 4) { + u32 x; + memcpy(&x, data, 4); + data += 4; + size -= 4; + result = __crc32w(result, x); + } + while (size) { + result = __crc32b(result, *data); + data++; + size--; + } + return ~result; +} +#else #include u32 crc32(const u8* data, size_t size) { @@ -18,4 +38,5 @@ u32 crc32(const u8* data, size_t size) { size--; } return ~result; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/common/util/os.cpp b/common/util/os.cpp index 795ddd4cad..51ebce452a 100644 --- a/common/util/os.cpp +++ b/common/util/os.cpp @@ -21,6 +21,13 @@ size_t get_peak_rss() { #ifdef _WIN32 // windows has a __cpuid #include +#elif __APPLE__ +// for now, just return 0's. +void __cpuidex(int result[4], int eax, int ecx) { + for (int i = 0; i < 4; i++) { + result[i] = 0; + } +} #else // using int to be compatible with msvc's intrinsic void __cpuidex(int result[4], int eax, int ecx) { diff --git a/common/util/read_iso_file.cpp b/common/util/read_iso_file.cpp index 14ac1cc2da..cf4312ffce 100644 --- a/common/util/read_iso_file.cpp +++ b/common/util/read_iso_file.cpp @@ -5,6 +5,8 @@ #include "common/util/Assert.h" #include "common/util/FileUtil.h" +#include "third-party/zstd/lib/common/xxhash.h" + IsoFile::IsoFile() { root.is_dir = true; } @@ -102,7 +104,7 @@ void unpack_entry(FILE* fp, file_util::write_binary_file(path_to_entry.string(), buffer.data(), buffer.size()); iso.files_extracted++; if (iso.shouldHash) { - xxh::hash_t<64> hash = xxh::xxhash<64>(buffer); + auto hash = XXH64(buffer.data(), buffer.size(), 0); iso.hashes.push_back(hash); } } diff --git a/common/util/read_iso_file.h b/common/util/read_iso_file.h index a25fd0a404..d5cf02a7f8 100644 --- a/common/util/read_iso_file.h +++ b/common/util/read_iso_file.h @@ -5,8 +5,6 @@ #include "common/util/FileUtil.h" -#include "third-party/xxhash.hpp" - struct IsoFile { struct Entry { bool is_dir = false; @@ -29,7 +27,7 @@ struct IsoFile { bool shouldHash = false; // There is no reason to map to the files, as we don't retain mappings of each file's expected // hash - std::vector hashes = {}; + std::vector hashes = {}; IsoFile(); }; diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index 239a1d0c4c..922928c784 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -1108,7 +1108,7 @@ void EmptyElement::get_modified_regs(RegSet&) const {} ///////////////////////////// bool cmp(Register x, Register y) { - int comparison = x.to_string().compare(y.to_string()); + int comparison = x.to_string() > y.to_string(); if (comparison <= 0) return true; return false; @@ -1118,7 +1118,7 @@ RLetElement::RLetElement(Form* _body, RegSet _regs) : body(_body) { for (auto& reg : _regs) { sorted_regs.push_back(reg); } - std::sort(sorted_regs.begin(), sorted_regs.end(), cmp); + std::stable_sort(sorted_regs.begin(), sorted_regs.end(), cmp); } void RLetElement::apply(const std::function& f) { diff --git a/decompiler/extractor/extractor_util.hpp b/decompiler/extractor/extractor_util.hpp index d5a623e155..bebf60f5b6 100644 --- a/decompiler/extractor/extractor_util.hpp +++ b/decompiler/extractor/extractor_util.hpp @@ -13,7 +13,7 @@ #include "game/kernel/common/kboot.h" #include "third-party/json.hpp" -#include "third-party/xxhash.hpp" +#include "third-party/zstd/lib/common/xxhash.h" enum class ExtractorErrorCode { SUCCESS = 0, @@ -54,7 +54,7 @@ struct ISOMetadata { std::string canonical_name; int region; // territory code int num_files; - xxh::hash64_t contents_hash; + uint64_t contents_hash; std::string decomp_config; std::string game_name; std::vector flags; @@ -65,7 +65,7 @@ struct ISOMetadata { // then the database isn't adequate and everything must change struct BuildInfo { std::string serial = ""; - xxh::hash64_t elf_hash = 0; + uint64_t elf_hash = 0; }; void to_json(nlohmann::json& j, const BuildInfo& info) { @@ -101,35 +101,35 @@ static const ISOMetadata jak1_ntsc_black_label_info = { {"jak1-black-label"}}; // { SERIAL : { ELF_HASH : ISOMetadataDatabase } } -static const std::unordered_map> - isoDatabase{{"SCUS-97124", - {{7280758013604870207U, jak1_ntsc_black_label_info}, - {744661860962747854, - {"Jak & Daxter™: The Precursor Legacy", - GAME_TERRITORY_SCEA, - 338, - 8538304367812415885U, - "jak1_jp", - "jak1", - {}}}}}, - {"SCES-50361", - {{12150718117852276522U, - {"Jak & Daxter™: The Precursor Legacy", - GAME_TERRITORY_SCEE, - 338, - 16850370297611763875U, - "jak1_pal", - "jak1", - {}}}}}, - {"SCPS-15021", - {{16909372048085114219U, - {"ジャックXダクスター ~ 旧世界の遺産", - GAME_TERRITORY_SCEI, - 338, - 1262350561338887717, - "jak1_jp", - "jak1", - {}}}}}}; +static const std::unordered_map> isoDatabase{ + {"SCUS-97124", + {{7280758013604870207U, jak1_ntsc_black_label_info}, + {744661860962747854, + {"Jak & Daxter™: The Precursor Legacy", + GAME_TERRITORY_SCEA, + 338, + 8538304367812415885U, + "jak1_jp", + "jak1", + {}}}}}, + {"SCES-50361", + {{12150718117852276522U, + {"Jak & Daxter™: The Precursor Legacy", + GAME_TERRITORY_SCEE, + 338, + 16850370297611763875U, + "jak1_pal", + "jak1", + {}}}}}, + {"SCPS-15021", + {{16909372048085114219U, + {"ジャックXダクスター ~ 旧世界の遺産", + GAME_TERRITORY_SCEI, + 338, + 1262350561338887717, + "jak1_jp", + "jak1", + {}}}}}}; std::optional get_version_info_from_build_info(const BuildInfo& build_info) { if (build_info.serial.empty() || build_info.elf_hash == 0) { @@ -168,10 +168,10 @@ ISOMetadata get_version_info_or_default(const fs::path& iso_data_path) { return version_info; } -std::tuple, std::optional> findElfFile( +std::tuple, std::optional> findElfFile( const fs::path& extracted_iso_path) { std::optional serial = std::nullopt; - std::optional elf_hash = std::nullopt; + std::optional elf_hash = std::nullopt; for (const auto& entry : fs::directory_iterator(extracted_iso_path)) { auto as_str = entry.path().filename().string(); if (std::regex_match(as_str, std::regex(".{4}_.{3}\\..{2}"))) { @@ -184,7 +184,7 @@ std::tuple, std::optional> findElfFile std::vector buffer(size); rewind(fp); fread(&buffer[0], sizeof(std::vector::value_type), buffer.size(), fp); - elf_hash = std::make_optional(xxh::xxhash<64>(buffer)); + elf_hash = std::make_optional(XXH64(buffer.data(), buffer.size(), 0)); fclose(fp); break; } @@ -194,9 +194,9 @@ std::tuple, std::optional> findElfFile void log_potential_new_db_entry(ExtractorErrorCode error_code, const std::string& serial, - const xxh::hash64_t elf_hash, + const uint64_t elf_hash, const int files_extracted, - const xxh::hash64_t contents_hash) { + const uint64_t contents_hash) { // Finally, return the result // Generate the map entry to make things simple, just convienance if (error_code == ExtractorErrorCode::VALIDATION_SERIAL_MISSING_FROM_DB) { @@ -237,28 +237,28 @@ std::tuple is_iso_file(fs::path path_to_supposed_iso) return {true, ExtractorErrorCode::SUCCESS}; } -std::tuple calculate_extraction_hash(const IsoFile& iso_file) { +std::tuple calculate_extraction_hash(const IsoFile& iso_file) { // - XOR all hashes together and hash the result. This makes the ordering of the hashes (aka // files) irrelevant - xxh::hash64_t combined_hash = 0; + uint64_t combined_hash = 0; for (const auto& hash : iso_file.hashes) { combined_hash ^= hash; } - return {xxh::xxhash<64>({combined_hash}), iso_file.hashes.size()}; + return {XXH64(&combined_hash, sizeof(uint64_t), 0), iso_file.hashes.size()}; } -std::tuple calculate_extraction_hash(const fs::path& extracted_iso_path) { +std::tuple calculate_extraction_hash(const fs::path& extracted_iso_path) { // - XOR all hashes together and hash the result. This makes the ordering of the hashes (aka // files) irrelevant - xxh::hash64_t combined_hash = 0; + uint64_t combined_hash = 0; int filec = 0; for (auto const& dir_entry : fs::recursive_directory_iterator(extracted_iso_path)) { if (dir_entry.is_regular_file()) { auto buffer = file_util::read_binary_file(dir_entry.path().string()); - auto hash = xxh::xxhash<64>(buffer); + auto hash = XXH64(buffer.data(), buffer.size(), 0); combined_hash ^= hash; filec++; } } - return {xxh::xxhash<64>({combined_hash}), filec}; + return {XXH64(&combined_hash, sizeof(uint64_t), 0), filec}; } diff --git a/decompiler/extractor/main.cpp b/decompiler/extractor/main.cpp index 8622e5968a..5528b02a2a 100644 --- a/decompiler/extractor/main.cpp +++ b/decompiler/extractor/main.cpp @@ -35,7 +35,7 @@ IsoFile extract_files(fs::path input_file_path, fs::path extracted_iso_path) { std::tuple, ExtractorErrorCode> validate( const fs::path& extracted_iso_path, - const xxh::hash64_t expected_hash, + const uint64_t expected_hash, const int expected_num_files) { if (!fs::exists(extracted_iso_path / "DGO")) { lg::error("input folder doesn't have a DGO folder. Is this the right input?"); diff --git a/decompiler/level_extractor/fr3_to_gltf.cpp b/decompiler/level_extractor/fr3_to_gltf.cpp index 35de534b66..21f0f459a6 100644 --- a/decompiler/level_extractor/fr3_to_gltf.cpp +++ b/decompiler/level_extractor/fr3_to_gltf.cpp @@ -1,5 +1,7 @@ #include "fr3_to_gltf.h" +#include + #include "common/custom_data/Tfrag3Data.h" #include "common/math/Vector.h" diff --git a/game/kernel/common/kmachine.cpp b/game/kernel/common/kmachine.cpp index 984741fdf2..fdb17a35cd 100644 --- a/game/kernel/common/kmachine.cpp +++ b/game/kernel/common/kmachine.cpp @@ -26,7 +26,7 @@ OverlordDataSource isodrv; u32 modsrc; // Reboot IOP with IOP kernel from DVD/CD on boot -u32 reboot; +u32 reboot_iop; const char* init_types[] = {"fakeiso", "deviso", "iso_cd"}; u8 pad_dma_buf[2 * SCE_PAD_DMA_BUFFER_SIZE]; @@ -41,7 +41,7 @@ void kmachine_init_globals_common() { memset(pad_dma_buf, 0, sizeof(pad_dma_buf)); isodrv = fakeiso; // changed. fakeiso is the only one that works in opengoal. modsrc = 1; - reboot = 1; + reboot_iop = 1; vif1_interrupt_handler = 0; vblank_interrupt_handler = 0; ee_clock_timer = Timer(); diff --git a/game/kernel/common/kmachine.h b/game/kernel/common/kmachine.h index cdcf117a0e..284376b720 100644 --- a/game/kernel/common/kmachine.h +++ b/game/kernel/common/kmachine.h @@ -19,7 +19,7 @@ extern OverlordDataSource isodrv; extern u32 modsrc; // Reboot IOP on start? -extern u32 reboot; +extern u32 reboot_iop; // renamed to reboot_iop to avoid conflict extern const char* init_types[]; extern u32 vblank_interrupt_handler; diff --git a/game/kernel/common/kprint.h b/game/kernel/common/kprint.h index 515f7f1c39..e5610a7161 100644 --- a/game/kernel/common/kprint.h +++ b/game/kernel/common/kprint.h @@ -63,7 +63,7 @@ void output_unload(const char* name); */ void output_segment_load(const char* name, Ptr link_block, u32 flags); -#ifdef __linux__ +#ifdef OS_POSIX /*! * Print to the GOAL print buffer from C */ @@ -80,7 +80,7 @@ void cprintf(const char* format, ...); */ void reverse(char* s); -#ifdef __linux__ +#ifdef OS_POSIX /*! * Print directly to the C stdout * The "k" parameter is ignored, so this is just like printf @@ -94,7 +94,7 @@ void Msg(s32 k, const char* format, ...) __attribute__((format(printf, 2, 3))); void Msg(s32 k, const char* format, ...); #endif -#ifdef __linux__ +#ifdef OS_POSIX /*! * Print directly to the C stdout * This is identical to Msg. @@ -107,7 +107,7 @@ void MsgWarn(const char* format, ...) __attribute__((format(printf, 1, 2))); */ void MsgWarn(const char* format, ...); #endif -#ifdef __linux__ +#ifdef OS_POSIX /*! * Print directly to the C stdout * This is identical to Msg. diff --git a/game/kernel/jak1/kmachine.cpp b/game/kernel/jak1/kmachine.cpp index 9fa45b87b2..20c5ab9e3d 100644 --- a/game/kernel/jak1/kmachine.cpp +++ b/game/kernel/jak1/kmachine.cpp @@ -60,7 +60,7 @@ void InitParms(int argc, const char* const* argv) { DiskBoot = 1; isodrv = fakeiso; modsrc = 0; - reboot = 0; + reboot_iop = 0; DebugSegment = 0; MasterDebug = 0; } @@ -75,7 +75,7 @@ void InitParms(int argc, const char* const* argv) { Msg(6, "dkernel: cd mode\n"); isodrv = iso_cd; // use the actual DVD drive for data files modsrc = 1; // use the DVD drive data for IOP modules - reboot = 1; // Reboot the IOP (load new IOP runtime) + reboot_iop = 1; // Reboot the IOP (load new IOP runtime) } // the "cddata" uses the DVD drive for everything but IOP modules. @@ -83,7 +83,7 @@ void InitParms(int argc, const char* const* argv) { Msg(6, "dkernel: cddata mode\n"); isodrv = iso_cd; // tell IOP to use actual DVD drive for data files modsrc = 0; // don't use DVD drive for IOP modules - reboot = 0; // no need to reboot the IOP + reboot_iop = 0; // no need to reboot the IOP } // the "deviso" mode is one of two modes for testing without the need for DVDs @@ -91,7 +91,7 @@ void InitParms(int argc, const char* const* argv) { Msg(6, "dkernel: deviso mode\n"); isodrv = deviso; // IOP deviso mode modsrc = 0; // no IOP module loading (there's no DVD to load from!) - reboot = 0; + reboot_iop = 0; } // the "fakeiso" mode is the other of two modes for testing without the need for DVDs @@ -99,7 +99,7 @@ void InitParms(int argc, const char* const* argv) { Msg(6, "dkernel: fakeiso mode\n"); isodrv = fakeiso; // IOP fakeeiso mode modsrc = 0; // no IOP module loading (there's no DVD to load from!) - reboot = 0; + reboot_iop = 0; } // an added mode to allow booting without a KERNEL.CGO for testing @@ -165,12 +165,12 @@ void InitIOP() { // before doing anything with the I/O Processor, we need to set up SIF RPC sceSifInitRpc(0); - if ((isodrv == iso_cd) || modsrc || reboot) { + if ((isodrv == iso_cd) || modsrc || reboot_iop) { // we will need the DVD drive to bring up the IOP InitCD(); } - if (!reboot) { + if (!reboot_iop) { // reboot with development IOP kernel lg::debug("Rebooting IOP..."); while (!sceSifRebootIop("host0:/usr/local/sce/iop/modules/ioprp221.img")) { diff --git a/game/kernel/jak2/kmachine.cpp b/game/kernel/jak2/kmachine.cpp index a89d2db503..7619c9cf65 100644 --- a/game/kernel/jak2/kmachine.cpp +++ b/game/kernel/jak2/kmachine.cpp @@ -51,7 +51,7 @@ void InitParms(int argc, const char* const* argv) { DiskBoot = 1; isodrv = fakeiso; modsrc = 0; - reboot = 0; + reboot_iop = 0; DebugSegment = 0; MasterDebug = 0; } @@ -66,7 +66,7 @@ void InitParms(int argc, const char* const* argv) { Msg(6, "dkernel: cd mode\n"); isodrv = iso_cd; // use the actual DVD drive for data files modsrc = 1; // use the DVD drive data for IOP modules - reboot = 1; // Reboot the IOP (load new IOP runtime) + reboot_iop = 1; // Reboot the IOP (load new IOP runtime) } // the "cddata" uses the DVD drive for everything but IOP modules. @@ -74,7 +74,7 @@ void InitParms(int argc, const char* const* argv) { Msg(6, "dkernel: cddata mode\n"); isodrv = iso_cd; // tell IOP to use actual DVD drive for data files modsrc = 0; // don't use DVD drive for IOP modules - reboot = 0; // no need to reboot the IOP + reboot_iop = 0; // no need to reboot the IOP } if (arg == "-demo") { @@ -99,14 +99,14 @@ void InitParms(int argc, const char* const* argv) { Msg(6, "dkernel: deviso mode\n"); isodrv = deviso; // IOP deviso mode modsrc = 2; // now 2 for Jak 2 - reboot = 0; + reboot_iop = 0; } // the "fakeiso" mode is the other of two modes for testing without the need for DVDs if (arg == "-fakeiso") { Msg(6, "dkernel: fakeiso mode\n"); isodrv = fakeiso; // IOP fakeeiso mode modsrc = 0; // no IOP module loading (there's no DVD to load from!) - reboot = 0; + reboot_iop = 0; } // the "boot" mode is used to set GOAL up for running the game in retail mode @@ -185,11 +185,11 @@ void InitIOP() { sceSifInitRpc(0); // init cd if we need it - if (((isodrv == iso_cd) || (modsrc == 1)) || (reboot == 1)) { + if (((isodrv == iso_cd) || (modsrc == 1)) || (reboot_iop == 1)) { InitCD(); } - if (reboot == 0) { + if (reboot_iop == 0) { // iop with dev kernel printf("Rebooting IOP...\n"); while (!sceSifRebootIop("host0:/usr/local/sce/iop/modules/ioprp271.img")) { diff --git a/game/runtime.cpp b/game/runtime.cpp index b62967ae48..ca3df3f57c 100644 --- a/game/runtime.cpp +++ b/game/runtime.cpp @@ -3,7 +3,8 @@ * Setup and launcher for the runtime. */ -#ifdef __linux__ +#include "common/common_types.h" +#ifdef OS_POSIX #include #include @@ -129,7 +130,12 @@ void ee_runner(SystemThreadInterface& iface) { if (EE_MEM_LOW_MAP) { g_ee_main_mem = (u8*)mmap((void*)0x10000000, EE_MAIN_MEM_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE, +#ifdef __APPLE__ + // has no map_populate + MAP_ANONYMOUS | MAP_32BIT | MAP_PRIVATE, 0, 0); +#else MAP_ANONYMOUS | MAP_32BIT | MAP_PRIVATE | MAP_POPULATE, 0, 0); +#endif } else { g_ee_main_mem = (u8*)mmap((void*)EE_MAIN_MEM_MAP, EE_MAIN_MEM_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE, diff --git a/game/system/SystemThread.cpp b/game/system/SystemThread.cpp index 9af0d955aa..45aa034a7f 100644 --- a/game/system/SystemThread.cpp +++ b/game/system/SystemThread.cpp @@ -1,9 +1,10 @@ #include "SystemThread.h" +#include "common/common_types.h" #include "common/log/log.h" #include "common/util/unicode_util.h" -#ifdef __linux +#ifdef OS_POSIX #include #else // Include order matters... @@ -96,8 +97,10 @@ void* bootstrap_thread_func(void* x) { SystemThread* thd = (SystemThread*)x; SystemThreadInterface iface(thd); -#ifdef __linux__ +#ifdef __linux pthread_setname_np(pthread_self(), thd->name.c_str()); +#elif __APPLE__ + pthread_setname_np(thd->name.c_str()); #else SetThreadDescription(GetCurrentThread(), (LPCWSTR)utf8_string_to_wide_string(thd->name).c_str()); #endif diff --git a/goalc/build_level/collide_pack.cpp b/goalc/build_level/collide_pack.cpp index 3e2f7a421b..04e1b115fc 100644 --- a/goalc/build_level/collide_pack.cpp +++ b/goalc/build_level/collide_pack.cpp @@ -1,6 +1,7 @@ #include "collide_pack.h" #include +#include #include "common/log/log.h" #include "common/util/Assert.h" diff --git a/goalc/debugger/Debugger.cpp b/goalc/debugger/Debugger.cpp index 0b41ce22e4..3ac1a2a3b9 100644 --- a/goalc/debugger/Debugger.cpp +++ b/goalc/debugger/Debugger.cpp @@ -777,6 +777,8 @@ bool Debugger::try_start_watcher() { stop_watcher(); } return m_attach_response; +#else + return false; #endif } diff --git a/goalc/emitter/CodeTester.cpp b/goalc/emitter/CodeTester.cpp index 479fbceb62..f8f1216f57 100644 --- a/goalc/emitter/CodeTester.cpp +++ b/goalc/emitter/CodeTester.cpp @@ -6,7 +6,8 @@ * The CodeTester can't be used for tests requiring the full GOAL language/linking. */ -#ifdef __linux__ +#include "common/common_types.h" +#ifdef OS_POSIX #include #elif _WIN32 #include "third-party/mman/mman.h" diff --git a/test/offline/framework/orchestration.cpp b/test/offline/framework/orchestration.cpp index 989f70b77a..1e0a4b7190 100644 --- a/test/offline/framework/orchestration.cpp +++ b/test/offline/framework/orchestration.cpp @@ -67,7 +67,7 @@ OfflineTestDecompiler setup_decompiler(const OfflineTestWorkGroup& work, } if (db_files.size() != object_files.size()) { - lg::error("DB file error: has {} entries, but expected {", db_files.size(), + lg::error("DB file error: has {} entries, but expected {}", db_files.size(), object_files.size()); for (const auto& coll : work.work_collections) { for (auto& file : coll.source_files) { diff --git a/test/offline/offline_test_main.cpp b/test/offline/offline_test_main.cpp index c331dfb155..5ecffbf6a2 100644 --- a/test/offline/offline_test_main.cpp +++ b/test/offline/offline_test_main.cpp @@ -19,7 +19,7 @@ void clear_terminal() { #elif defined(__LINUX__) || defined(__gnu_linux__) || defined(__linux__) system("clear"); #elif defined(__APPLE__) - system("clear"); + // system("clear"); #endif } @@ -33,6 +33,7 @@ int main(int argc, char* argv[]) { int max_files = -1; std::string single_file = ""; uint32_t num_threads = 1; + std::string project_path; bool fail_on_cmp = false; bool pretty_print = false; @@ -54,6 +55,7 @@ int main(int argc, char* argv[]) { app.add_flag("--fail-on-cmp", fail_on_cmp, "Fail the tests immediately if the comparison fails"); app.add_flag("-p,--pretty-print", pretty_print, "Use the condensed and progress-indicating printing format"); + app.add_option("--proj-path", project_path, "Project path"); app.validate_positionals(); CLI11_PARSE(app, argc, argv); @@ -63,7 +65,11 @@ int main(int argc, char* argv[]) { } lg::initialize(); - if (!file_util::setup_project_path(std::nullopt)) { + std::optional pp; + if (!project_path.empty()) { + pp = project_path; + } + if (!file_util::setup_project_path(pp)) { lg::error("Couldn't setup project path, tool is supposed to be ran in the jak-project repo!"); return 1; } diff --git a/third-party/xxhash.hpp b/third-party/xxhash.hpp deleted file mode 100644 index 8a632ddfbe..0000000000 --- a/third-party/xxhash.hpp +++ /dev/null @@ -1,1942 +0,0 @@ -// Version - 0.7.3 -// - https://github.com/RedSpah/xxhash_cpp/blob/0.7.3/include/xxhash.hpp - -#pragma once -#include -#include -#include -#include -#include -#include - -/* -xxHash - Extremely Fast Hash algorithm -Header File -Copyright (C) 2012-2020, Yann Collet. -Copyright (C) 2017-2020, Red Gavin. -All rights reserved. - -BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: -* Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -You can contact the author at : -- xxHash source repository : https://github.com/Cyan4973/xxHash -- xxHash C++ port repository : https://github.com/RedSpah/xxhash_cpp -*/ - -/* Intrinsics - * Sadly has to be included in the global namespace or literally everything breaks - */ -#include - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wshadow" - -namespace xxh { -/* ************************************* - * Versioning - ***************************************/ - -namespace version { -constexpr int cpp_version_major = 0; -constexpr int cpp_version_minor = 7; -constexpr int cpp_version_release = 3; -} // namespace version - -constexpr uint32_t version_number() { - return version::cpp_version_major * 10000 + version::cpp_version_minor * 100 + - version::cpp_version_release; -} - -/* ************************************* - * Basic Types - Predefining uint128_t for intrin - ***************************************/ - -namespace typedefs { -struct alignas(16) uint128_t { - uint64_t low64 = 0; - uint64_t high64 = 0; - - bool operator==(const uint128_t& other) { - return (low64 == other.low64 && high64 == other.high64); - } - - bool operator>(const uint128_t& other) { return (high64 > other.high64 || low64 > other.low64); } - - bool operator>=(const uint128_t& other) { return (*this > other || *this == other); } - - bool operator<(const uint128_t& other) { return !(*this >= other); } - - bool operator<=(const uint128_t& other) { return !(*this > other); } - - bool operator!=(const uint128_t& other) { return !(*this == other); } - - uint128_t(uint64_t low, uint64_t high) : low64(low), high64(high) {} - - uint128_t() {} -}; - -} // namespace typedefs - -using uint128_t = typedefs::uint128_t; - -/* ************************************* - * Compiler / Platform Specific Features - ***************************************/ - -namespace intrin { -/*!XXH_CPU_LITTLE_ENDIAN : - * This is a CPU endian detection macro, will be - * automatically set to 1 (little endian) if it is left undefined. - * If compiling for a big endian system (why), XXH_CPU_LITTLE_ENDIAN has to be explicitly defined as - * 0. - */ -#ifndef XXH_CPU_LITTLE_ENDIAN -#define XXH_CPU_LITTLE_ENDIAN 1 -#endif - -/* Vectorization Detection - * NOTE: XXH_NEON and XXH_VSX aren't supported in this C++ port. - * The primary reason is that I don't have access to an ARM and PowerPC - * machines to test them, and the secondary reason is that I even doubt anyone writing - * code for such machines would bother using a C++ port rather than the original C version. - */ -#ifndef XXH_VECTOR /* can be predefined on command line */ -#if defined(__AVX2__) -#define XXH_VECTOR 2 /* AVX2 for Haswell and Bulldozer */ -#elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || \ - (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) -#define XXH_VECTOR 1 /* SSE2 for Pentium 4 and all x86_64 */ -#else -#define XXH_VECTOR 0 /* Portable scalar version */ -#endif -#endif - -constexpr int vector_mode = XXH_VECTOR; - -#if XXH_VECTOR == 2 /* AVX2 for Haswell and Bulldozer */ -constexpr int acc_align = 32; -using avx2_underlying = __m256i; -using sse2_underlying = __m128i; -#elif XXH_VECTOR == 1 /* SSE2 for Pentium 4 and all x86_64 */ -using avx2_underlying = void; // std::array<__m128i, 2>; -using sse2_underlying = __m128i; -constexpr int acc_align = 16; -#else /* Portable scalar version */ -using avx2_underlying = void; // std::array; -using sse2_underlying = void; // std::array; -constexpr int acc_align = 8; -#endif - -/* Compiler Specifics - * Defines inline macros and includes specific compiler's instrinsics. - * */ -#ifdef XXH_FORCE_INLINE /* First undefining the symbols in case they're already defined */ -#undef XXH_FORCE_INLINE -#endif -#ifdef XXH_NO_INLINE -#undef XXH_NO_INLINE -#endif - -#ifdef _MSC_VER /* Visual Studio */ -#pragma warning(disable : 4127) -#define XXH_FORCE_INLINE static __forceinline -#define XXH_NO_INLINE static __declspec(noinline) -#include -#elif defined(__GNUC__) /* Clang / GCC */ -#define XXH_FORCE_INLINE static inline __attribute__((always_inline)) -#define XXH_NO_INLINE static __attribute__((noinline)) -#include -#else -#define XXH_FORCE_INLINE static inline -#define XXH_NO_INLINE static -#endif - -/* Prefetch - * Can be disabled by defining XXH_NO_PREFETCH - */ -#if defined(XXH_NO_PREFETCH) -XXH_FORCE_INLINE void prefetch(const void* ptr) {} -#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) -XXH_FORCE_INLINE void prefetch(const void* ptr) { - _mm_prefetch((const char*)(ptr), _MM_HINT_T0); -} -#elif defined(__GNUC__) -XXH_FORCE_INLINE void prefetch(const void* ptr) { - __builtin_prefetch((ptr), 0, 3); -} -#else -XXH_FORCE_INLINE void prefetch(const void* ptr) {} -#endif - -/* Restrict - * Defines macro for restrict, which in C++ is sadly just a compiler extension (for now). - * Can be disabled by defining XXH_NO_RESTRICT - */ -#ifdef XXH_RESTRICT -#undef XXH_RESTRICT -#endif - -#if (defined(__GNUC__) || defined(_MSC_VER)) && defined(__cplusplus) && !defined(XXH_NO_RESTRICT) -#define XXH_RESTRICT __restrict -#else -#define XXH_RESTRICT -#endif - -/* Likely / Unlikely - * Defines macros for Likely / Unlikely, which are official in C++20, but sadly this library aims - * the previous standard. Not present on MSVC. Can be disabled by defining XXH_NO_BRANCH_HINTS - */ -#if ((defined(__GNUC__) && (__GNUC__ >= 3)) || \ - (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)) && \ - !defined(XXH_NO_BRANCH_HINTS) -#define XXH_likely(x) __builtin_expect(x, 1) -#define XXH_unlikely(x) __builtin_expect(x, 0) -#else -#define XXH_likely(x) (x) -#define XXH_unlikely(x) (x) -#endif - -namespace bit_ops { -#if defined(_MSC_VER) -static inline uint32_t rotl32(uint32_t x, int32_t r) { - return _rotl(x, r); -} -static inline uint64_t rotl64(uint64_t x, int32_t r) { - return _rotl64(x, r); -} -static inline uint32_t rotr32(uint32_t x, int32_t r) { - return _rotr(x, r); -} -static inline uint64_t rotr64(uint64_t x, int32_t r) { - return _rotr64(x, r); -} -#else -static inline uint32_t rotl32(uint32_t x, int32_t r) { - return ((x << r) | (x >> (32 - r))); -} -static inline uint64_t rotl64(uint64_t x, int32_t r) { - return ((x << r) | (x >> (64 - r))); -} -static inline uint32_t rotr32(uint32_t x, int32_t r) { - return ((x >> r) | (x << (32 - r))); -} -static inline uint64_t rotr64(uint64_t x, int32_t r) { - return ((x >> r) | (x << (64 - r))); -} -#endif - -#if defined(_MSC_VER) /* Visual Studio */ -static inline uint32_t swap32(uint32_t x) { - return _byteswap_ulong(x); -} -static inline uint64_t swap64(uint64_t x) { - return _byteswap_uint64(x); -} -#elif defined(__GNUC__) -static inline uint32_t swap32(uint32_t x) { - return __builtin_bswap32(x); -} -static inline uint64_t swap64(uint64_t x) { - return __builtin_bswap64(x); -} -#else -static inline uint32_t swap32(uint32_t x) { - return ((x << 24) & 0xff000000) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | - ((x >> 24) & 0x000000ff); -} -static inline uint64_t swap64(uint64_t x) { - return ((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) | - ((x << 24) & 0x0000ff0000000000ULL) | ((x << 8) & 0x000000ff00000000ULL) | - ((x >> 8) & 0x00000000ff000000ULL) | ((x >> 24) & 0x0000000000ff0000ULL) | - ((x >> 40) & 0x000000000000ff00ULL) | ((x >> 56) & 0x00000000000000ffULL); -} -#endif - -#if defined(_MSC_VER) && defined(_M_IX86) // Only for 32-bit MSVC. -XXH_FORCE_INLINE uint64_t mult32to64(uint32_t x, uint32_t y) { - return __emulu(x, y); -} -#else -XXH_FORCE_INLINE uint64_t mult32to64(uint32_t x, uint32_t y) { - return (uint64_t)(uint32_t)(x) * (uint64_t)(uint32_t)(y); -} -#endif - -#if defined(__GNUC__) && !defined(__clang__) && defined(__i386__) -__attribute__((__target__("no-sse"))) -#endif -static inline uint128_t -mult64to128(uint64_t lhs, uint64_t rhs) { - -#if defined(__GNUC__) && !defined(__wasm__) && defined(__SIZEOF_INT128__) || \ - (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) - - __uint128_t product = (__uint128_t)lhs * (__uint128_t)rhs; - uint128_t const r128 = {(uint64_t)(product), (uint64_t)(product >> 64)}; - return r128; - -#elif defined(_M_X64) || defined(_M_IA64) - -#ifndef _MSC_VER -#pragma intrinsic(_umul128) -#endif - uint64_t product_high; - uint64_t const product_low = _umul128(lhs, rhs, &product_high); - return uint128_t{product_low, product_high}; -#else - uint64_t const lo_lo = bit_ops::mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); - uint64_t const hi_lo = bit_ops::mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); - uint64_t const lo_hi = bit_ops::mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); - uint64_t const hi_hi = bit_ops::mult32to64(lhs >> 32, rhs >> 32); - - /* Now add the products together. These will never overflow. */ - uint64_t const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; - uint64_t const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; - uint64_t const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); - - uint128_t r128 = {lower, upper}; - return r128; -#endif -} -} // namespace bit_ops -} // namespace intrin - -/* ************************************* - * Basic Types - Everything else - ***************************************/ - -namespace typedefs { -/* ************************************* - * Basic Types - Detail - ***************************************/ - -template -struct hash_type { - using type = void; -}; - -template <> -struct hash_type<32> { - using type = uint32_t; -}; - -template <> -struct hash_type<64> { - using type = uint64_t; -}; - -template <> -struct hash_type<128> { - using type = uint128_t; -}; - -template -struct vec_type { - using type = void; -}; - -template <> -struct vec_type<64> { - using type = uint64_t; -}; - -template <> -struct vec_type<128> { - using type = intrin::sse2_underlying; -}; - -template <> -struct vec_type<256> { - using type = intrin::avx2_underlying; -}; - -/* Rationale - * On the surface level uint_type appears to be pointless, - * as it is just a copy of hash_type. They do use the same types, - * that is true, but the reasoning for the difference is aimed at humans, - * not the compiler, as a difference between values that are 'just' numbers, - * and those that represent actual hash values. - */ -template -struct uint_type { - using type = void; -}; - -template <> -struct uint_type<32> { - using type = uint32_t; -}; - -template <> -struct uint_type<64> { - using type = uint64_t; -}; - -template <> -struct uint_type<128> { - using type = uint128_t; -}; -} // namespace typedefs - -template -using hash_t = typename typedefs::hash_type::type; -using hash32_t = hash_t<32>; -using hash64_t = hash_t<64>; -using hash128_t = hash_t<128>; - -template -using vec_t = typename typedefs::vec_type::type; -using vec64_t = vec_t<64>; -using vec128_t = vec_t<128>; -using vec256_t = vec_t<256>; - -template -using uint_t = typename typedefs::uint_type::type; - -/* ************************************* - * Bit Operations - ***************************************/ - -namespace bit_ops { -/* **************************************** - * Bit Operations - ******************************************/ - -template -static inline uint_t rotl(uint_t n, int32_t r) { - if constexpr (N == 32) { - return intrin::bit_ops::rotl32(n, r); - } - - if constexpr (N == 64) { - return intrin::bit_ops::rotl64(n, r); - } -} - -template -static inline uint_t rotr(uint_t n, int32_t r) { - if constexpr (N == 32) { - return intrin::bit_ops::rotr32(n, r); - } - - if constexpr (N == 64) { - return intrin::bit_ops::rotr64(n, r); - } -} - -template -static inline uint_t swap(uint_t n) { - if constexpr (N == 32) { - return intrin::bit_ops::swap32(n); - } - - if constexpr (N == 64) { - return intrin::bit_ops::swap64(n); - } -} - -static inline uint64_t mul32to64(uint32_t x, uint32_t y) { - return intrin::bit_ops::mult32to64(x, y); -} - -static inline uint128_t mul64to128(uint64_t x, uint64_t y) { - return intrin::bit_ops::mult64to128(x, y); -} - -static inline uint64_t mul128fold64(uint64_t x, uint64_t y) { - uint128_t product = mul64to128(x, y); - - return (product.low64 ^ product.high64); -} -} // namespace bit_ops - -/* ************************************* - * Memory Functions - ***************************************/ - -namespace mem_ops { - -/* ************************************* - * Endianness - ***************************************/ - -constexpr bool is_little_endian() { - return (XXH_CPU_LITTLE_ENDIAN == 1); -} - -/* ************************************* - * Memory Access - ***************************************/ - -template -static inline uint_t read(const void* memPtr) { - uint_t val; - - memcpy(&val, memPtr, sizeof(val)); - return val; -} - -template -static inline uint_t readLE(const void* ptr) { - if constexpr (is_little_endian()) { - return read(ptr); - } else { - return bit_ops::swap(read(ptr)); - } -} - -template -static inline uint_t readBE(const void* ptr) { - if constexpr (is_little_endian()) { - return bit_ops::swap(read(ptr)); - } else { - return read(ptr); - } -} - -template -static void writeLE(void* dst, uint_t v) { - if constexpr (!is_little_endian()) { - v = bit_ops::swap(v); - } - - memcpy(dst, &v, sizeof(v)); -} -} // namespace mem_ops - -/* ************************************* - * Vector Functions - ***************************************/ - -namespace vec_ops { -template -XXH_FORCE_INLINE vec_t loadu(const vec_t* input) { - static_assert(!(N != 128 && N != 256 && N != 64), - "Invalid template argument passed to xxh::vec_ops::loadu"); - - if constexpr (N == 128) { - return _mm_loadu_si128(input); - } - - if constexpr (N == 256) { - return _mm256_loadu_si256(input); - } - - if constexpr (N == 64) { - return mem_ops::readLE<64>(input); - } -} - -// 'xorv' instead of 'xor' because 'xor' is a weird wacky alternate operator expression thing. -template -XXH_FORCE_INLINE vec_t xorv(vec_t a, vec_t b) { - static_assert(!(N != 128 && N != 256 && N != 64), - "Invalid argument passed to xxh::vec_ops::xorv"); - - if constexpr (N == 128) { - return _mm_xor_si128(a, b); - } - - if constexpr (N == 256) { - return _mm256_xor_si256(a, b); - } - - if constexpr (N == 64) { - return a ^ b; - } -} - -template -XXH_FORCE_INLINE vec_t mul(vec_t a, vec_t b) { - static_assert(!(N != 128 && N != 256 && N != 64), "Invalid argument passed to xxh::vec_ops::mul"); - - if constexpr (N == 128) { - return _mm_mul_epu32(a, b); - } - - if constexpr (N == 256) { - return _mm256_mul_epu32(a, b); - } - - if constexpr (N == 64) { - return a * b; - } -} - -template -XXH_FORCE_INLINE vec_t add(vec_t a, vec_t b) { - static_assert(!(N != 128 && N != 256 && N != 64), "Invalid argument passed to xxh::vec_ops::add"); - - if constexpr (N == 128) { - return _mm_add_epi64(a, b); - } - - if constexpr (N == 256) { - return _mm256_add_epi64(a, b); - } - - if constexpr (N == 64) { - return a + b; - } -} - -template -XXH_FORCE_INLINE vec_t shuffle(vec_t a) { - static_assert(!(N != 128 && N != 256 && N != 64), - "Invalid argument passed to xxh::vec_ops::shuffle"); - - if constexpr (N == 128) { - return _mm_shuffle_epi32(a, _MM_SHUFFLE(S1, S2, S3, S4)); - } - - if constexpr (N == 256) { - return _mm256_shuffle_epi32(a, _MM_SHUFFLE(S1, S2, S3, S4)); - } - - if constexpr (N == 64) { - return a; - } -} - -template -XXH_FORCE_INLINE vec_t set1(int a) { - static_assert(!(N != 128 && N != 256 && N != 64), - "Invalid argument passed to xxh::vec_ops::set1"); - - if constexpr (N == 128) { - return _mm_set1_epi32(a); - } - - if constexpr (N == 256) { - return _mm256_set1_epi32(a); - } - - if constexpr (N == 64) { - return a; - } -} - -template -XXH_FORCE_INLINE vec_t srli(vec_t n, int a) { - static_assert(!(N != 128 && N != 256 && N != 64), - "Invalid argument passed to xxh::vec_ops::srli"); - - if constexpr (N == 128) { - return _mm_srli_epi64(n, a); - } - - if constexpr (N == 256) { - return _mm256_srli_epi64(n, a); - } - - if constexpr (N == 64) { - return n >> a; - } -} - -template -XXH_FORCE_INLINE vec_t slli(vec_t n, int a) { - static_assert(!(N != 128 && N != 256 && N != 64), - "Invalid argument passed to xxh::vec_ops::slli"); - - if constexpr (N == 128) { - return _mm_slli_epi64(n, a); - } - - if constexpr (N == 256) { - return _mm256_slli_epi64(n, a); - } - - if constexpr (N == 64) { - return n << a; - } -} -} // namespace vec_ops - -/* ************************************* - * Algorithm Implementation - xxhash - ***************************************/ - -namespace detail { -using namespace mem_ops; -using namespace bit_ops; - -/* ************************************* - * Constants - ***************************************/ - -constexpr static std::array primes32 = {2654435761U, 2246822519U, 3266489917U, - 668265263U, 374761393U}; -constexpr static std::array primes64 = { - 11400714785074694791ULL, 14029467366897019727ULL, 1609587929392839161ULL, - 9650029242287828579ULL, 2870177450012600261ULL}; - -template -constexpr uint_t PRIME(uint64_t n) { - if constexpr (N == 32) { - return primes32[n - 1]; - } else { - return primes64[n - 1]; - } -} - -/* ************************************* - * Functions - ***************************************/ - -template -static inline uint_t round(uint_t seed, uint_t input) { - seed += input * PRIME(2); - - if constexpr (N == 32) { - seed = rotl(seed, 13); - } else { - seed = rotl(seed, 31); - } - - seed *= PRIME(1); - return seed; -} - -static inline uint64_t mergeRound64(hash64_t acc, uint64_t val) { - val = round<64>(0, val); - acc ^= val; - acc = acc * PRIME<64>(1) + PRIME<64>(4); - return acc; -} - -static inline void endian_align_sub_mergeround(hash64_t& hash_ret, - uint64_t v1, - uint64_t v2, - uint64_t v3, - uint64_t v4) { - hash_ret = mergeRound64(hash_ret, v1); - hash_ret = mergeRound64(hash_ret, v2); - hash_ret = mergeRound64(hash_ret, v3); - hash_ret = mergeRound64(hash_ret, v4); -} - -template -static inline hash_t endian_align_sub_ending(hash_t hash_ret, - const uint8_t* p, - const uint8_t* bEnd) { - if constexpr (N == 32) { - while ((p + 4) <= bEnd) { - hash_ret += readLE<32>(p) * PRIME<32>(3); - hash_ret = rotl<32>(hash_ret, 17) * PRIME<32>(4); - p += 4; - } - - while (p < bEnd) { - hash_ret += (*p) * PRIME<32>(5); - hash_ret = rotl<32>(hash_ret, 11) * PRIME<32>(1); - p++; - } - - hash_ret ^= hash_ret >> 15; - hash_ret *= PRIME<32>(2); - hash_ret ^= hash_ret >> 13; - hash_ret *= PRIME<32>(3); - hash_ret ^= hash_ret >> 16; - - return hash_ret; - } else { - while (p + 8 <= bEnd) { - const uint64_t k1 = round<64>(0, readLE<64>(p)); - - hash_ret ^= k1; - hash_ret = rotl<64>(hash_ret, 27) * PRIME<64>(1) + PRIME<64>(4); - p += 8; - } - - if (p + 4 <= bEnd) { - hash_ret ^= static_cast(readLE<32>(p)) * PRIME<64>(1); - hash_ret = rotl<64>(hash_ret, 23) * PRIME<64>(2) + PRIME<64>(3); - p += 4; - } - - while (p < bEnd) { - hash_ret ^= (*p) * PRIME<64>(5); - hash_ret = rotl<64>(hash_ret, 11) * PRIME<64>(1); - p++; - } - - hash_ret ^= hash_ret >> 33; - hash_ret *= PRIME<64>(2); - hash_ret ^= hash_ret >> 29; - hash_ret *= PRIME<64>(3); - hash_ret ^= hash_ret >> 32; - - return hash_ret; - } -} - -template -static inline hash_t endian_align(const void* input, size_t len, uint_t seed) { - static_assert(!(N != 32 && N != 64), "You can only call endian_align in 32 or 64 bit mode."); - - const uint8_t* p = static_cast(input); - const uint8_t* bEnd = p + len; - hash_t hash_ret; - - if (len >= (N / 2)) { - const uint8_t* const limit = bEnd - (N / 2); - uint_t v1 = seed + PRIME(1) + PRIME(2); - uint_t v2 = seed + PRIME(2); - uint_t v3 = seed + 0; - uint_t v4 = seed - PRIME(1); - - do { - v1 = round(v1, readLE(p)); - p += (N / 8); - v2 = round(v2, readLE(p)); - p += (N / 8); - v3 = round(v3, readLE(p)); - p += (N / 8); - v4 = round(v4, readLE(p)); - p += (N / 8); - } while (p <= limit); - - hash_ret = rotl(v1, 1) + rotl(v2, 7) + rotl(v3, 12) + rotl(v4, 18); - - if constexpr (N == 64) { - endian_align_sub_mergeround(hash_ret, v1, v2, v3, v4); - } - } else { - hash_ret = seed + PRIME(5); - } - - hash_ret += static_cast>(len); - - return endian_align_sub_ending(hash_ret, p, bEnd); -} -} // namespace detail - -/* ************************************* - * Algorithm Implementation - xxhash3 - ***************************************/ - -namespace detail3 { -using namespace vec_ops; -using namespace detail; -using namespace mem_ops; -using namespace bit_ops; - -/* ************************************* - * Enums - ***************************************/ - -enum class acc_width : uint8_t { acc_64bits, acc_128bits }; -enum class vec_mode : uint8_t { scalar = 0, sse2 = 1, avx2 = 2 }; - -/* ************************************* - * Constants - ***************************************/ - -constexpr uint64_t secret_default_size = 192; -constexpr uint64_t secret_size_min = 136; -constexpr uint64_t secret_consume_rate = 8; -constexpr uint64_t stripe_len = 64; -constexpr uint64_t acc_nb = 8; -constexpr uint64_t prefetch_distance = 384; -constexpr uint64_t secret_lastacc_start = 7; -constexpr uint64_t secret_mergeaccs_start = 11; -constexpr uint64_t midsize_max = 240; -constexpr uint64_t midsize_startoffset = 3; -constexpr uint64_t midsize_lastoffset = 17; - -constexpr vec_mode vector_mode = static_cast(intrin::vector_mode); -constexpr uint64_t acc_align = intrin::acc_align; -constexpr std::array vector_bit_width{64, 128, 256}; - -/* ************************************* - * Defaults - ***************************************/ - -alignas(64) constexpr uint8_t default_secret[secret_default_size] = { - 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, - 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, - 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, - 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, - 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, - 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, - 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, - 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, - 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, - 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, - 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, - 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, -}; - -constexpr std::array init_acc = {PRIME<32>(3), PRIME<64>(1), PRIME<64>(2), - PRIME<64>(3), PRIME<64>(4), PRIME<32>(2), - PRIME<64>(5), PRIME<32>(1)}; - -/* ************************************* - * Functions - ***************************************/ - -static hash_t<64> avalanche(hash_t<64> h64) { - constexpr uint64_t avalanche_mul_prime = 0x165667919E3779F9ULL; - - h64 ^= h64 >> 37; - h64 *= avalanche_mul_prime; - h64 ^= h64 >> 32; - return h64; -} - -template -XXH_FORCE_INLINE void accumulate_512(void* XXH_RESTRICT acc, - const void* XXH_RESTRICT input, - const void* XXH_RESTRICT secret, - acc_width width) { - constexpr uint64_t bits = vector_bit_width[static_cast(V)]; - - using vec_t = vec_t; - - alignas(sizeof(vec_t)) vec_t* const xacc = static_cast(acc); - const vec_t* const xinput = static_cast(input); - const vec_t* const xsecret = static_cast(secret); - - for (size_t i = 0; i < stripe_len / sizeof(vec_t); i++) { - vec_t const data_vec = loadu(xinput + i); - vec_t const key_vec = loadu(xsecret + i); - vec_t const data_key = xorv(data_vec, key_vec); - vec_t product = set1(0); - - if constexpr (V != vec_mode::scalar) { - vec_t const data_key_lo = shuffle(data_key); - - product = mul(data_key, data_key_lo); - - if (width == acc_width::acc_128bits) { - vec_t const data_swap = shuffle(data_vec); - vec_t const sum = add(xacc[i], data_swap); - - xacc[i] = add(sum, product); - } else { - vec_t const sum = add(xacc[i], data_vec); - - xacc[i] = add(sum, product); - } - } else { - product = mul32to64(data_key & 0xFFFFFFFF, data_key >> 32); - - if (width == acc_width::acc_128bits) { - xacc[i ^ 1] = add(xacc[i ^ 1], data_vec); - } else { - xacc[i] = add(xacc[i], data_vec); - } - - xacc[i] = add(xacc[i], product); - } - } -} - -template -XXH_FORCE_INLINE void scramble_acc(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { - constexpr uint64_t bits = vector_bit_width[static_cast(V)]; - ; - - using vec_t = vec_t; - - alignas(sizeof(vec_t)) vec_t* const xacc = (vec_t*)acc; - const vec_t* const xsecret = (const vec_t*)secret; - - for (size_t i = 0; i < stripe_len / sizeof(vec_t); i++) { - vec_t const acc_vec = xacc[i]; - vec_t const shifted = srli(acc_vec, 47); - vec_t const data_vec = xorv(acc_vec, shifted); - vec_t const key_vec = loadu(xsecret + i); - vec_t const data_key = xorv(data_vec, key_vec); - - if constexpr (V != vec_mode::scalar) { - vec_t const prime32 = set1(PRIME<32>(1)); - vec_t const data_key_hi = shuffle(data_key); - vec_t const prod_lo = mul(data_key, prime32); - vec_t const prod_hi = mul(data_key_hi, prime32); - - xacc[i] = add(prod_lo, vec_ops::slli(prod_hi, 32)); - } else { - xacc[i] = mul(data_key, PRIME<32>(1)); - } - } -} - -XXH_FORCE_INLINE void accumulate(uint64_t* XXH_RESTRICT acc, - const uint8_t* XXH_RESTRICT input, - const uint8_t* XXH_RESTRICT secret, - size_t nbStripes, - acc_width accWidth) { - for (size_t n = 0; n < nbStripes; n++) { - const uint8_t* const in = input + n * stripe_len; - - intrin::prefetch(in + prefetch_distance); - accumulate_512(acc, in, secret + n * secret_consume_rate, accWidth); - } -} - -XXH_FORCE_INLINE void hash_long_internal_loop(uint64_t* XXH_RESTRICT acc, - const uint8_t* XXH_RESTRICT input, - size_t len, - const uint8_t* XXH_RESTRICT secret, - size_t secretSize, - acc_width accWidth) { - size_t const nb_rounds = (secretSize - stripe_len) / secret_consume_rate; - size_t const block_len = stripe_len * nb_rounds; - size_t const nb_blocks = len / block_len; - - for (size_t n = 0; n < nb_blocks; n++) { - accumulate(acc, input + n * block_len, secret, nb_rounds, accWidth); - scramble_acc(acc, secret + secretSize - stripe_len); - } - - /* last partial block */ - size_t const nbStripes = (len - (block_len * nb_blocks)) / stripe_len; - - accumulate(acc, input + nb_blocks * block_len, secret, nbStripes, accWidth); - - /* last stripe */ - if (len & (stripe_len - 1)) { - const uint8_t* const p = input + len - stripe_len; - - accumulate_512(acc, p, secret + secretSize - stripe_len - secret_lastacc_start, - accWidth); - } -} - -XXH_FORCE_INLINE uint64_t mix_2_accs(const uint64_t* XXH_RESTRICT acc, - const uint8_t* XXH_RESTRICT secret) { - return mul128fold64(acc[0] ^ readLE<64>(secret), acc[1] ^ readLE<64>(secret + 8)); -} - -XXH_FORCE_INLINE uint64_t merge_accs(const uint64_t* XXH_RESTRICT acc, - const uint8_t* XXH_RESTRICT secret, - uint64_t start) { - uint64_t result64 = start; - - result64 += mix_2_accs(acc + 0, secret + 0); - result64 += mix_2_accs(acc + 2, secret + 16); - result64 += mix_2_accs(acc + 4, secret + 32); - result64 += mix_2_accs(acc + 6, secret + 48); - - return avalanche(result64); -} - -XXH_FORCE_INLINE void init_custom_secret(uint8_t* customSecret, uint64_t seed) { - for (uint64_t i = 0; i < secret_default_size / 16; i++) { - writeLE<64>(customSecret + i * 16, readLE<64>(default_secret + i * 16) + seed); - writeLE<64>(customSecret + i * 16 + 8, readLE<64>(default_secret + i * 16 + 8) - seed); - } -} - -template -XXH_FORCE_INLINE hash_t len_1to3(const uint8_t* input, - size_t len, - const uint8_t* secret, - uint64_t seed) { - if constexpr (N == 64) { - uint8_t const c1 = input[0]; - uint8_t const c2 = input[len >> 1]; - uint8_t const c3 = input[len - 1]; - uint32_t const combined = ((uint32_t)c1 << 16) | (((uint32_t)c2) << 24) | - (((uint32_t)c3) << 0) | (((uint32_t)len) << 8); - uint64_t const bitflip = (readLE<32>(secret) ^ readLE<32>(secret + 4)) + seed; - uint64_t const keyed = (uint64_t)combined ^ bitflip; - uint64_t const mixed = keyed * PRIME<64>(1); - - return avalanche(mixed); - } else { - uint8_t const c1 = input[0]; - uint8_t const c2 = input[len >> 1]; - uint8_t const c3 = input[len - 1]; - uint32_t const combinedl = ((uint32_t)c1 << 16) + (((uint32_t)c2) << 24) + - (((uint32_t)c3) << 0) + (((uint32_t)len) << 8); - uint32_t const combinedh = rotl<32>(swap<32>(combinedl), 13); - uint64_t const bitflipl = (readLE<32>(secret) ^ readLE<32>(secret + 4)) + seed; - uint64_t const bitfliph = (readLE<32>(secret + 8) ^ readLE<32>(secret + 12)) - seed; - uint64_t const keyed_lo = (uint64_t)combinedl ^ bitflipl; - uint64_t const keyed_hi = (uint64_t)combinedh ^ bitfliph; - uint64_t const mixedl = keyed_lo * PRIME<64>(1); - uint64_t const mixedh = keyed_hi * PRIME<64>(5); - hash128_t const h128 = {avalanche(mixedl), avalanche(mixedh)}; - - return h128; - } -} - -template -XXH_FORCE_INLINE hash_t len_4to8(const uint8_t* input, - size_t len, - const uint8_t* secret, - uint64_t seed) { - constexpr uint64_t mix_constant = 0x9FB21C651E98DF25ULL; - - seed ^= (uint64_t)swap<32>((uint32_t)seed) << 32; - - if constexpr (N == 64) { - uint32_t const input1 = readLE<32>(input); - uint32_t const input2 = readLE<32>(input + len - 4); - uint64_t const bitflip = (readLE<64>(secret + 8) ^ readLE<64>(secret + 16)) - seed; - uint64_t const input64 = input2 + ((uint64_t)input1 << 32); - uint64_t x = input64 ^ bitflip; - - x ^= rotl<64>(x, 49) ^ rotl<64>(x, 24); - x *= mix_constant; - x ^= (x >> 35) + len; - x *= mix_constant; - - return (x ^ (x >> 28)); - } else { - uint32_t const input_lo = readLE<32>(input); - uint32_t const input_hi = readLE<32>(input + len - 4); - uint64_t const input_64 = input_lo + ((uint64_t)input_hi << 32); - uint64_t const bitflip = (readLE<64>(secret + 16) ^ readLE<64>(secret + 24)) + seed; - uint64_t const keyed = input_64 ^ bitflip; - uint128_t m128 = mul64to128(keyed, PRIME<64>(1) + (len << 2)); - - m128.high64 += (m128.low64 << 1); - m128.low64 ^= (m128.high64 >> 3); - m128.low64 ^= (m128.low64 >> 35); - m128.low64 *= mix_constant; - m128.low64 ^= (m128.low64 >> 28); - m128.high64 = avalanche(m128.high64); - - return m128; - } -} - -template -XXH_FORCE_INLINE hash_t len_9to16(const uint8_t* input, - size_t len, - const uint8_t* secret, - uint64_t seed) { - if constexpr (N == 64) { - uint64_t const bitflip1 = (readLE<64>(secret + 24) ^ readLE<64>(secret + 32)) + seed; - uint64_t const bitflip2 = (readLE<64>(secret + 40) ^ readLE<64>(secret + 48)) - seed; - uint64_t const input_lo = readLE<64>(input) ^ bitflip1; - uint64_t const input_hi = readLE<64>(input + len - 8) ^ bitflip2; - uint64_t const acc = len + swap<64>(input_lo) + input_hi + mul128fold64(input_lo, input_hi); - - return avalanche(acc); - } else { - uint64_t const bitflipl = (readLE<64>(secret + 32) ^ readLE<64>(secret + 40)) - seed; - uint64_t const bitfliph = (readLE<64>(secret + 48) ^ readLE<64>(secret + 56)) + seed; - uint64_t const input_lo = readLE<64>(input); - uint64_t input_hi = readLE<64>(input + len - 8); - uint128_t m128 = mul64to128(input_lo ^ input_hi ^ bitflipl, PRIME<64>(1)); - - m128.low64 += (uint64_t)(len - 1) << 54; - input_hi ^= bitfliph; - - if constexpr (sizeof(void*) < sizeof(uint64_t)) // 32-bit version - { - m128.high64 += (input_hi & 0xFFFFFFFF00000000) + mul32to64((uint32_t)input_hi, PRIME<32>(2)); - } else { - m128.high64 += input_hi + mul32to64((uint32_t)input_hi, PRIME<32>(2) - 1); - } - - m128.low64 ^= swap<64>(m128.high64); - - hash128_t h128 = mul64to128(m128.low64, PRIME<64>(2)); - - h128.high64 += m128.high64 * PRIME<64>(2); - h128.low64 = avalanche(h128.low64); - h128.high64 = avalanche(h128.high64); - - return h128; - } -} - -template -XXH_FORCE_INLINE hash_t len_0to16(const uint8_t* input, - size_t len, - const uint8_t* secret, - uint64_t seed) { - if (XXH_likely(len > 8)) { - return len_9to16(input, len, secret, seed); - } else if (XXH_likely(len >= 4)) { - return len_4to8(input, len, secret, seed); - } else if (len) { - return len_1to3(input, len, secret, seed); - } else { - if constexpr (N == 64) { - return avalanche((PRIME<64>(1) + seed) ^ (readLE<64>(secret + 56) ^ readLE<64>(secret + 64))); - } else { - uint64_t const bitflipl = readLE<64>(secret + 64) ^ readLE<64>(secret + 72); - uint64_t const bitfliph = readLE<64>(secret + 80) ^ readLE<64>(secret + 88); - - return hash128_t(avalanche((PRIME<64>(1) + seed) ^ bitflipl), - avalanche((PRIME<64>(2) - seed) ^ bitfliph)); - } - } -} - -template -XXH_FORCE_INLINE hash_t hash_long_internal(const uint8_t* XXH_RESTRICT input, - size_t len, - const uint8_t* XXH_RESTRICT secret = default_secret, - size_t secretSize = sizeof(default_secret)) { - alignas(acc_align) std::array acc = init_acc; - - if constexpr (N == 64) { - hash_long_internal_loop(acc.data(), input, len, secret, secretSize, acc_width::acc_64bits); - - /* converge into final hash */ - return merge_accs(acc.data(), secret + secret_mergeaccs_start, (uint64_t)len * PRIME<64>(1)); - } else { - hash_long_internal_loop(acc.data(), input, len, secret, secretSize, acc_width::acc_128bits); - - /* converge into final hash */ - uint64_t const low64 = - merge_accs(acc.data(), secret + secret_mergeaccs_start, (uint64_t)len * PRIME<64>(1)); - uint64_t const high64 = - merge_accs(acc.data(), secret + secretSize - sizeof(acc) - secret_mergeaccs_start, - ~((uint64_t)len * PRIME<64>(2))); - - return hash128_t(low64, high64); - } -} - -XXH_FORCE_INLINE uint64_t mix_16b(const uint8_t* XXH_RESTRICT input, - const uint8_t* XXH_RESTRICT secret, - uint64_t seed) { - uint64_t const input_lo = readLE<64>(input); - uint64_t const input_hi = readLE<64>(input + 8); - - return mul128fold64(input_lo ^ (readLE<64>(secret) + seed), - input_hi ^ (readLE<64>(secret + 8) - seed)); -} - -XXH_FORCE_INLINE uint128_t mix_32b(uint128_t acc, - const uint8_t* input1, - const uint8_t* input2, - const uint8_t* secret, - uint64_t seed) { - acc.low64 += mix_16b(input1, secret + 0, seed); - acc.low64 ^= readLE<64>(input2) + readLE<64>(input2 + 8); - acc.high64 += mix_16b(input2, secret + 16, seed); - acc.high64 ^= readLE<64>(input1) + readLE<64>(input1 + 8); - - return acc; -} - -template -XXH_FORCE_INLINE hash_t len_17to128(const uint8_t* XXH_RESTRICT input, - size_t len, - const uint8_t* XXH_RESTRICT secret, - uint64_t seed) { - if constexpr (N == 64) { - hash64_t acc = len * PRIME<64>(1); - - if (len > 32) { - if (len > 64) { - if (len > 96) { - acc += mix_16b(input + 48, secret + 96, seed); - acc += mix_16b(input + len - 64, secret + 112, seed); - } - - acc += mix_16b(input + 32, secret + 64, seed); - acc += mix_16b(input + len - 48, secret + 80, seed); - } - - acc += mix_16b(input + 16, secret + 32, seed); - acc += mix_16b(input + len - 32, secret + 48, seed); - } - - acc += mix_16b(input + 0, secret + 0, seed); - acc += mix_16b(input + len - 16, secret + 16, seed); - - return avalanche(acc); - } else { - hash128_t acc = {len * PRIME<64>(1), 0}; - - if (len > 32) { - if (len > 64) { - if (len > 96) { - acc = mix_32b(acc, input + 48, input + len - 64, secret + 96, seed); - } - - acc = mix_32b(acc, input + 32, input + len - 48, secret + 64, seed); - } - - acc = mix_32b(acc, input + 16, input + len - 32, secret + 32, seed); - } - - acc = mix_32b(acc, input, input + len - 16, secret, seed); - - uint64_t const low64 = acc.low64 + acc.high64; - uint64_t const high64 = - (acc.low64 * PRIME<64>(1)) + (acc.high64 * PRIME<64>(4)) + ((len - seed) * PRIME<64>(2)); - - return {avalanche(low64), (uint64_t)0 - avalanche(high64)}; - } -} - -template -XXH_NO_INLINE hash_t len_129to240(const uint8_t* XXH_RESTRICT input, - size_t len, - const uint8_t* XXH_RESTRICT secret, - uint64_t seed) { - if constexpr (N == 64) { - uint64_t acc = len * PRIME<64>(1); - size_t const nbRounds = len / 16; - - for (size_t i = 0; i < 8; i++) { - acc += mix_16b(input + (i * 16), secret + (i * 16), seed); - } - - acc = avalanche(acc); - - for (size_t i = 8; i < nbRounds; i++) { - acc += mix_16b(input + (i * 16), secret + ((i - 8) * 16) + midsize_startoffset, seed); - } - - /* last bytes */ - acc += mix_16b(input + len - 16, secret + secret_size_min - midsize_lastoffset, seed); - - return avalanche(acc); - } else { - hash128_t acc; - uint64_t const nbRounds = len / 32; - - acc.low64 = len * PRIME<64>(1); - acc.high64 = 0; - - for (size_t i = 0; i < 4; i++) { - acc = mix_32b(acc, input + (i * 32), input + (i * 32) + 16, secret + (i * 32), seed); - } - - acc.low64 = avalanche(acc.low64); - acc.high64 = avalanche(acc.high64); - - for (size_t i = 4; i < nbRounds; i++) { - acc = mix_32b(acc, input + (i * 32), input + (i * 32) + 16, - secret + midsize_startoffset + ((i - 4) * 32), seed); - } - - /* last bytes */ - acc = mix_32b(acc, input + len - 16, input + len - 32, - secret + secret_size_min - midsize_lastoffset - 16, 0ULL - seed); - - uint64_t const low64 = acc.low64 + acc.high64; - uint64_t const high64 = - (acc.low64 * PRIME<64>(1)) + (acc.high64 * PRIME<64>(4)) + ((len - seed) * PRIME<64>(2)); - - return {avalanche(low64), (uint64_t)0 - avalanche(high64)}; - } -} - -template -XXH_NO_INLINE hash_t xxhash3_impl(const void* XXH_RESTRICT input, - size_t len, - hash64_t seed, - const void* XXH_RESTRICT secret = default_secret, - size_t secretSize = secret_default_size) { - alignas(8) uint8_t custom_secret[secret_default_size]; - const void* short_secret = secret; - - if (seed != 0) { - init_custom_secret(custom_secret, seed); - secret = custom_secret; - secretSize = secret_default_size; - short_secret = default_secret; - } - - if (len <= 16) { - return len_0to16(static_cast(input), len, - static_cast(short_secret), seed); - } else if (len <= 128) { - return len_17to128(static_cast(input), len, - static_cast(short_secret), seed); - } else if (len <= midsize_max) { - return len_129to240(static_cast(input), len, - static_cast(short_secret), seed); - } else { - return hash_long_internal(static_cast(input), len, - static_cast(secret), secretSize); - } -} -} // namespace detail3 - -/* ************************************* - * Public Access Point - xxhash - ***************************************/ - -template -inline hash_t xxhash(const void* input, size_t len, uint_t seed = 0) { - static_assert(!(bit_mode != 32 && bit_mode != 64), - "xxhash can only be used in 32 and 64 bit modes."); - return detail::endian_align(input, len, seed); -} - -template -inline hash_t xxhash(const std::basic_string& input, uint_t seed = 0) { - static_assert(!(bit_mode != 32 && bit_mode != 64), - "xxhash can only be used in 32 and 64 bit modes."); - return detail::endian_align(static_cast(input.data()), - input.length() * sizeof(T), seed); -} - -template -inline hash_t xxhash(ContiguousIterator begin, - ContiguousIterator end, - uint_t seed = 0) { - static_assert(!(bit_mode != 32 && bit_mode != 64), - "xxhash can only be used in 32 and 64 bit modes."); - using T = typename std::decay_t; - return detail::endian_align(static_cast(&*begin), - (end - begin) * sizeof(T), seed); -} - -template -inline hash_t xxhash(const std::vector& input, uint_t seed = 0) { - static_assert(!(bit_mode != 32 && bit_mode != 64), - "xxhash can only be used in 32 and 64 bit modes."); - return detail::endian_align(static_cast(input.data()), - input.size() * sizeof(T), seed); -} - -template -inline hash_t xxhash(const std::array& input, uint_t seed = 0) { - static_assert(!(bit_mode != 32 && bit_mode != 64), - "xxhash can only be used in 32 and 64 bit modes."); - return detail::endian_align(static_cast(input.data()), AN * sizeof(T), - seed); -} - -template -inline hash_t xxhash(const std::initializer_list& input, uint_t seed = 0) { - static_assert(!(bit_mode != 32 && bit_mode != 64), - "xxhash can only be used in 32 and 64 bit modes."); - return detail::endian_align(static_cast(input.begin()), - input.size() * sizeof(T), seed); -} - -/* ************************************* - * Public Access Point - xxhash3 - ***************************************/ - -template -inline hash_t xxhash3(const void* input, size_t len, uint64_t seed = 0) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(input, len, seed); -} - -template -inline hash_t xxhash3(const void* input, - size_t len, - const void* secret, - size_t secretSize) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(input, len, 0, secret, secretSize); -} - -template -inline hash_t xxhash3(const std::basic_string& input, uint64_t seed = 0) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(static_cast(input.data()), - input.length() * sizeof(T), seed); -} - -template -inline hash_t xxhash3(const std::basic_string& input, - const void* secret, - size_t secretSize) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(static_cast(input.data()), - input.length() * sizeof(T), 0, secret, secretSize); -} - -template -inline hash_t xxhash3(ContiguousIterator begin, ContiguousIterator end, uint64_t seed = 0) { - static_assert(!(N != 128 && N != 64), "xxhash3 can only be used in 64 and 128 bit modes."); - using T = typename std::decay_t; - return detail3::xxhash3_impl(static_cast(&*begin), (end - begin) * sizeof(T), - seed); -} - -template -inline hash_t xxhash3(ContiguousIterator begin, - ContiguousIterator end, - const void* secret, - size_t secretSize) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - using T = typename std::decay_t; - return detail3::xxhash3_impl(static_cast(&*begin), - (end - begin) * sizeof(T), 0, secret, secretSize); -} - -template -inline hash_t xxhash3(const std::vector& input, uint64_t seed = 0) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(static_cast(input.data()), - input.size() * sizeof(T), seed); -} - -template -inline hash_t xxhash3(const std::vector& input, - const void* secret, - size_t secretSize) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(static_cast(input.data()), - input.size() * sizeof(T), 0, secret, secretSize); -} - -template -inline hash_t xxhash3(const std::array& input, uint64_t seed = 0) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(static_cast(input.data()), AN * sizeof(T), - seed); -} - -template -inline hash_t xxhash3(const std::array& input, - const void* secret, - size_t secretSize) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(static_cast(input.data()), AN * sizeof(T), 0, - secret, secretSize); -} - -template -inline hash_t xxhash3(const std::initializer_list& input, uint64_t seed = 0) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(static_cast(input.begin()), - input.size() * sizeof(T), seed); -} - -template -inline hash_t xxhash3(const std::initializer_list& input, - const void* secret, - size_t secretSize) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 can only be used in 64 and 128 bit modes."); - return detail3::xxhash3_impl(static_cast(input.begin()), - input.size() * sizeof(T), 0, secret, secretSize); -} - -/* ************************************* - * Hash streaming - xxhash - ***************************************/ - -template -class hash_state_t { - uint64_t total_len = 0; - uint_t v1 = 0, v2 = 0, v3 = 0, v4 = 0; - std::array, 4> mem = {0, 0, 0, 0}; - uint32_t memsize = 0; - - inline void update_impl(const void* input, size_t length) { - const uint8_t* p = reinterpret_cast(input); - const uint8_t* const bEnd = p + length; - - total_len += length; - - if (memsize + length < (bit_mode / 2)) { /* fill in tmp buffer */ - memcpy(reinterpret_cast(mem.data()) + memsize, input, length); - memsize += static_cast(length); - return; - } - - if (memsize > 0) { /* some data left from previous update */ - memcpy(reinterpret_cast(mem.data()) + memsize, input, (bit_mode / 2) - memsize); - - const uint_t* ptr = mem.data(); - - v1 = detail::round(v1, mem_ops::readLE(ptr)); - ptr++; - v2 = detail::round(v2, mem_ops::readLE(ptr)); - ptr++; - v3 = detail::round(v3, mem_ops::readLE(ptr)); - ptr++; - v4 = detail::round(v4, mem_ops::readLE(ptr)); - - p += (bit_mode / 2) - memsize; - memsize = 0; - } - - if (p <= bEnd - (bit_mode / 2)) { - const uint8_t* const limit = bEnd - (bit_mode / 2); - - do { - v1 = detail::round(v1, mem_ops::readLE(p)); - p += (bit_mode / 8); - v2 = detail::round(v2, mem_ops::readLE(p)); - p += (bit_mode / 8); - v3 = detail::round(v3, mem_ops::readLE(p)); - p += (bit_mode / 8); - v4 = detail::round(v4, mem_ops::readLE(p)); - p += (bit_mode / 8); - } while (p <= limit); - } - - if (p < bEnd) { - memcpy(mem.data(), p, static_cast(bEnd - p)); - memsize = static_cast(bEnd - p); - } - } - - inline hash_t digest_impl() const { - const uint8_t* p = reinterpret_cast(mem.data()); - const uint8_t* const bEnd = reinterpret_cast(mem.data()) + memsize; - hash_t hash_ret; - - if (total_len >= (bit_mode / 2)) { - hash_ret = bit_ops::rotl(v1, 1) + bit_ops::rotl(v2, 7) + - bit_ops::rotl(v3, 12) + bit_ops::rotl(v4, 18); - - if constexpr (bit_mode == 64) { - detail::endian_align_sub_mergeround(hash_ret, v1, v2, v3, v4); - } - } else { - hash_ret = v3 + detail::PRIME(5); - } - - hash_ret += static_cast>(total_len); - - return detail::endian_align_sub_ending(hash_ret, p, bEnd); - } - - public: - hash_state_t(uint_t seed = 0) { - static_assert(!(bit_mode != 32 && bit_mode != 64), - "xxhash streaming can only be used in 32 and 64 bit modes."); - v1 = seed + detail::PRIME(1) + detail::PRIME(2); - v2 = seed + detail::PRIME(2); - v3 = seed + 0; - v4 = seed - detail::PRIME(1); - }; - - hash_state_t operator=(hash_state_t& other) { - memcpy(this, &other, sizeof(hash_state_t)); - } - - void reset(uint_t seed = 0) { - memset(this, 0, sizeof(hash_state_t)); - v1 = seed + detail::PRIME(1) + detail::PRIME(2); - v2 = seed + detail::PRIME(2); - v3 = seed + 0; - v4 = seed - detail::PRIME(1); - } - - void update(const void* input, size_t length) { return update_impl(input, length); } - - template - void update(const std::basic_string& input) { - return update_impl(static_cast(input.data()), input.length() * sizeof(T)); - } - - template - void update(ContiguousIterator begin, ContiguousIterator end) { - using T = typename std::decay_t; - return update_impl(static_cast(&*begin), (end - begin) * sizeof(T)); - } - - template - void update(const std::vector& input) { - return update_impl(static_cast(input.data()), input.size() * sizeof(T)); - } - - template - void update(const std::array& input) { - return update_impl(static_cast(input.data()), AN * sizeof(T)); - } - - template - void update(const std::initializer_list& input) { - return update_impl(static_cast(input.begin()), input.size() * sizeof(T)); - } - - hash_t digest() const { return digest_impl(); } -}; - -using hash_state32_t = hash_state_t<32>; -using hash_state64_t = hash_state_t<64>; - -/* ************************************* - * Hash streaming - xxhash3 - ***************************************/ - -template -class alignas(64) hash3_state_t { - constexpr static int internal_buffer_size = 256; - constexpr static int internal_buffer_stripes = (internal_buffer_size / detail3::stripe_len); - constexpr static detail3::acc_width accWidth = - (bit_mode == 64) ? detail3::acc_width::acc_64bits : detail3::acc_width::acc_128bits; - - alignas(64) uint64_t acc[8]; - alignas(64) uint8_t - customSecret[detail3::secret_default_size]; /* used to store a custom secret generated from - the seed. Makes state larger. Design might - change */ - alignas(64) uint8_t buffer[internal_buffer_size]; - uint32_t bufferedSize = 0; - uint32_t nbStripesPerBlock = 0; - uint32_t nbStripesSoFar = 0; - uint32_t secretLimit = 0; - uint32_t reserved32 = 0; - uint32_t reserved32_2 = 0; - uint64_t totalLen = 0; - uint64_t seed = 0; - uint64_t reserved64 = 0; - const uint8_t* secret = - nullptr; /* note : there is some padding after, due to alignment on 64 bytes */ - - void consume_stripes(uint64_t* acc, - uint32_t& nbStripesSoFar, - size_t totalStripes, - const uint8_t* input, - detail3::acc_width accWidth) { - if (nbStripesPerBlock - nbStripesSoFar <= totalStripes) /* need a scrambling operation */ - { - size_t const nbStripes = nbStripesPerBlock - nbStripesSoFar; - - detail3::accumulate(acc, input, secret + (nbStripesSoFar * detail3::secret_consume_rate), - nbStripes, accWidth); - detail3::scramble_acc(acc, secret + secretLimit); - detail3::accumulate(acc, input + nbStripes * detail3::stripe_len, secret, - totalStripes - nbStripes, accWidth); - nbStripesSoFar = (uint32_t)(totalStripes - nbStripes); - } else { - detail3::accumulate(acc, input, secret + (nbStripesSoFar * detail3::secret_consume_rate), - totalStripes, accWidth); - nbStripesSoFar += (uint32_t)totalStripes; - } - } - - void update_impl(const void* input_, size_t len) { - const uint8_t* input = static_cast(input_); - const uint8_t* const bEnd = input + len; - - totalLen += len; - - if (bufferedSize + len <= internal_buffer_size) { /* fill in tmp buffer */ - memcpy(buffer + bufferedSize, input, len); - bufferedSize += (uint32_t)len; - return; - } - /* input now > XXH3_INTERNALBUFFER_SIZE */ - - if (bufferedSize > 0) { /* some input within internal buffer: fill then consume it */ - size_t const loadSize = internal_buffer_size - bufferedSize; - - memcpy(buffer + bufferedSize, input, loadSize); - input += loadSize; - consume_stripes(acc, nbStripesSoFar, internal_buffer_stripes, buffer, accWidth); - bufferedSize = 0; - } - - /* consume input by full buffer quantities */ - if (input + internal_buffer_size <= bEnd) { - const uint8_t* const limit = bEnd - internal_buffer_size; - - do { - consume_stripes(acc, nbStripesSoFar, internal_buffer_stripes, input, accWidth); - input += internal_buffer_size; - } while (input <= limit); - } - - if (input < bEnd) { /* some remaining input input : buffer it */ - memcpy(buffer, input, (size_t)(bEnd - input)); - bufferedSize = (uint32_t)(bEnd - input); - } - } - - void digest_long(uint64_t* acc_, detail3::acc_width accWidth) { - memcpy(acc_, acc, sizeof(acc)); /* digest locally, state remains unaltered, and can continue - ingesting more input afterwards */ - - if (bufferedSize >= detail3::stripe_len) { - size_t const totalNbStripes = bufferedSize / detail3::stripe_len; - uint32_t nbStripesSoFar = this->nbStripesSoFar; - - consume_stripes(acc_, nbStripesSoFar, totalNbStripes, buffer, accWidth); - - if (bufferedSize % detail3::stripe_len) { /* one last partial stripe */ - detail3::accumulate_512( - acc_, buffer + bufferedSize - detail3::stripe_len, - secret + secretLimit - detail3::secret_lastacc_start, accWidth); - } - } else { /* bufferedSize < STRIPE_LEN */ - if (bufferedSize > 0) { /* one last stripe */ - uint8_t lastStripe[detail3::stripe_len]; - size_t const catchupSize = detail3::stripe_len - bufferedSize; - memcpy(lastStripe, buffer + sizeof(buffer) - catchupSize, catchupSize); - memcpy(lastStripe + catchupSize, buffer, bufferedSize); - detail3::accumulate_512( - acc_, lastStripe, secret + secretLimit - detail3::secret_lastacc_start, accWidth); - } - } - } - - public: - hash3_state_t operator=(hash3_state_t& other) { memcpy(this, &other, sizeof(hash3_state_t)); } - - hash3_state_t(uint64_t seed = 0) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 streaming can only be used in 64 and 128 bit modes."); - reset(seed); - } - - hash3_state_t(const void* secret, size_t secretSize) { - static_assert(!(bit_mode != 128 && bit_mode != 64), - "xxhash3 streaming can only be used in 64 and 128 bit modes."); - reset(secret, secretSize); - } - - void reset(uint64_t seed = 0) { - memset(this, 0, sizeof(*this)); - memcpy(acc, detail3::init_acc.data(), sizeof(detail3::init_acc)); - (*this).seed = seed; - - if (seed == 0) { - secret = detail3::default_secret; - } else { - detail3::init_custom_secret(customSecret, seed); - secret = customSecret; - } - - secretLimit = (uint32_t)(detail3::secret_default_size - detail3::stripe_len); - nbStripesPerBlock = secretLimit / detail3::secret_consume_rate; - } - - void reset(const void* secret, size_t secretSize) { - memset(this, 0, sizeof(*this)); - memcpy(acc, detail3::init_acc.data(), sizeof(detail3::init_acc)); - seed = 0; - - (*this).secret = (const uint8_t*)secret; - secretLimit = (uint32_t)(secretSize - detail3::stripe_len); - nbStripesPerBlock = secretLimit / detail3::secret_consume_rate; - } - - void update(const void* input, size_t len) { - return update_impl(static_cast(input), len); - } - - template - void update(const std::basic_string& input) { - return update_impl(static_cast(input.data()), input.length() * sizeof(T)); - } - - template - void update(ContiguousIterator begin, ContiguousIterator end) { - using T = typename std::decay_t; - return update_impl(static_cast(&*begin), (end - begin) * sizeof(T)); - } - - template - void update(const std::vector& input) { - return update_impl(static_cast(input.data()), input.size() * sizeof(T)); - } - - template - void update(const std::array& input) { - return update_impl(static_cast(input.data()), AN * sizeof(T)); - } - - template - void update(const std::initializer_list& input) { - return update_impl(static_cast(input.begin()), input.size() * sizeof(T)); - } - - hash_t digest() { - if (totalLen > detail3::midsize_max) { - alignas(detail3::acc_align) hash64_t acc[detail3::acc_nb]; - - digest_long(acc, accWidth); - - if constexpr (bit_mode == 64) { - return detail3::merge_accs(acc, secret + detail3::secret_mergeaccs_start, - (uint64_t)totalLen * detail::PRIME<64>(1)); - } else { - uint64_t const low64 = detail3::merge_accs(acc, secret + detail3::secret_mergeaccs_start, - (uint64_t)totalLen * detail::PRIME<64>(1)); - uint64_t const high64 = - detail3::merge_accs(acc, - secret + secretLimit + detail3::stripe_len - sizeof(acc) - - detail3::secret_mergeaccs_start, - ~((uint64_t)totalLen * detail::PRIME<64>(2))); - - return {low64, high64}; - } - } else { - return detail3::xxhash3_impl(buffer, totalLen, seed, secret, - secretLimit + detail3::stripe_len); - } - } -}; - -using hash3_state64_t = hash3_state_t<64>; -using hash3_state128_t = hash3_state_t<128>; - -/* ************************************* - * Canonical represenation - ***************************************/ - -template -struct canonical_t { - std::array digest{0}; - - canonical_t(hash_t hash) { - if constexpr (bit_mode < 128) { - if (mem_ops::is_little_endian()) { - hash = bit_ops::swap(hash); - } - - memcpy(digest.data(), &hash, sizeof(canonical_t)); - } else { - if (mem_ops::is_little_endian()) { - hash.low64 = bit_ops::swap<64>(hash.low64); - hash.high64 = bit_ops::swap<64>(hash.high64); - } - - memcpy(digest.data(), &hash.high64, sizeof(hash.high64)); - memcpy(digest.data() + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); - } - } - - hash_t get_hash() const { - if constexpr (bit_mode < 128) { - return mem_ops::readBE(&digest); - } else { - return {mem_ops::readBE<64>(&digest[8]), mem_ops::readBE<64>(&digest)}; - } - } -}; - -using canonical32_t = canonical_t<32>; -using canonical64_t = canonical_t<64>; -using canonical128_t = canonical_t<128>; -} // namespace xxh -#pragma clang diagnostic pop \ No newline at end of file