diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9967548..a83a9e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: - rc1 - rc2 - rc3 - - directories + - hash-review pull_request: concurrency: diff --git a/CHANGES.md b/CHANGES.md index 079a6dc..a3003d2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,7 +7,9 @@ * Added 64-bit `FNV-1a` hash functions: `cstring_hash_fnv1a()`, `cstring_hash_fnv1a_ci()`, `cstring_hash_fnv1a_len()`, and `cstring_hash_fnv1a_len_ci()`; * Added `cstring_hash_t` typedef (`uint64_t`); * Added C++ hash access shims for `cstring_t` (reference and pointer) and buffer/slice forms; -* Added unit test suite **test.unit.hash**; +* Added unit test **test.unit.hash** (C hashing API, built with and without the C++ API) and **test.unit.hash.cxx** (C++ hash shims); +* Published `CSTRING_HASH_DJB2_SEED`, `CSTRING_HASH_FNV1A_OFFSET`, and `CSTRING_HASH_FNV1A_PRIME` as the djb2 and FNV-1a basis constants; +* Documented `CSTRING_HASH_DJB2_SEED`, `CSTRING_HASH_FNV1A_OFFSET`, and `CSTRING_HASH_FNV1A_PRIME` with references to the published djb2 and FNV-1a algorithms; ## 4.0.19 - 4th October 2026 diff --git a/README.md b/README.md index f002166..d45652f 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,9 @@ Supporting scalar typedefs: * `cstring_vector_t_DEFAULT` — the same shape for a `cstring_vector_t`; * `cstring_vector_DEFAULT_CAPACITY` — sentinel (`~(size_t)0`) passed to creators so the implementation chooses the capacity; * `CSTRING_FROM_END(x)` — reverse index for `cstring_insert()`, `cstring_insertLen()`, `cstring_replace()`, and `cstring_replaceLen()`; +* `CSTRING_HASH_DJB2_SEED` — djb2 initial seed (`5381`); also the hash of an empty input; +* `CSTRING_HASH_FNV1A_OFFSET` — FNV-1a 64-bit offset basis (`0xcbf29ce484222325ULL`); also the hash of an empty input; +* `CSTRING_HASH_FNV1A_PRIME` — FNV-1a 64-bit prime (`0x100000001b3ULL`); ### String API @@ -212,7 +215,7 @@ Defined in **cstring/cstring.h**: #### Hashing functions -Both 64-bit **djb2** (initial seed `5381`) and **FNV-1a** (offset basis `0xcbf29ce484222325ULL`, prime `0x100000001b3ULL`) hash functions are provided, returning `cstring_hash_t` (`uint64_t`). Buffer/slice variants (`_len`) allow hashing character sequences without constructing a `cstring_t` instance. Case-insensitive variants (`_ci`) fold characters to lower case, facilitating case-folded lookups and comparisons. All functions safely tolerate `NULL` pointers and zero lengths, returning the respective algorithm's initial basis / seed value: +Both 64-bit **djb2** (initial seed `5381`, `CSTRING_HASH_DJB2_SEED`) and **FNV-1a** (offset basis `0xcbf29ce484222325ULL`, `CSTRING_HASH_FNV1A_OFFSET`; prime `0x100000001b3ULL`, `CSTRING_HASH_FNV1A_PRIME`) hash functions are provided, returning `cstring_hash_t` (`uint64_t`). Buffer/slice variants (`_len`) allow hashing character sequences without constructing a `cstring_t` instance. Case-insensitive variants (`_ci`) fold characters to lower case, facilitating case-folded lookups and comparisons. All functions safely tolerate `NULL` pointers and zero lengths. An empty or `NULL` input hashes to `CSTRING_HASH_DJB2_SEED` or `CSTRING_HASH_FNV1A_OFFSET`: * `cstring_hash_djb2()` — calculates a 64-bit djb2 hash of a `cstring_t` instance; * `cstring_hash_djb2_ci()` — calculates a case-insensitive 64-bit djb2 hash of a `cstring_t` instance; diff --git a/include/cstring/cstring.h b/include/cstring/cstring.h index 9d974b3..a72b8f0 100644 --- a/include/cstring/cstring.h +++ b/include/cstring/cstring.h @@ -4,7 +4,7 @@ * Purpose: Definition of the cstring.core API. * * Created: 16th June 1994 - * Updated: 4th October 2026 + * Updated: 5th October 2026 * * Home: http://synesis.com.au/software/ * @@ -54,9 +54,9 @@ #ifndef CSTRING_DOCUMENTATION_SKIP_SECTION # define CSTRING_VER_CSTRING_H_CSTRING_MAJOR 3 -# define CSTRING_VER_CSTRING_H_CSTRING_MINOR 12 +# define CSTRING_VER_CSTRING_H_CSTRING_MINOR 13 # define CSTRING_VER_CSTRING_H_CSTRING_REVISION 2 -# define CSTRING_VER_CSTRING_H_CSTRING_EDIT 94 +# define CSTRING_VER_CSTRING_H_CSTRING_EDIT 98 #endif /* !CSTRING_DOCUMENTATION_SKIP_SECTION */ @@ -142,14 +142,46 @@ /* ///////////////////////////////////////////////////////////////////////// - * includes + * includes - 1 */ #include -#if defined(_MSC_VER) && \ - _MSC_VER < 1600 -typedef unsigned __int64 uint64_t; + + +/* ///////////////////////////////////////////////////////////////////////// + * compatibility + */ + +#if 0 +#elif defined(__STDC_VERSION__) &&\ + __STDC_VERSION__ >= 199901L + +# define CSTRING_HAS_h_stdint_ +#elif defined(__cplusplus) &&\ + defined(__has_include) &&\ + __has_include() + +# define CSTRING_HAS_h_stdint_ +#elif defined(__cplusplus) &&\ + __cplusplus >= 201103L + +# define CSTRING_HAS_h_stdint_ +#elif 0 ||\ + ( defined(_MSC_VER) &&\ + _MSC_VER >= 1310) ||\ + 0 + +# define CSTRING_HAS_h_stdint_ #else + +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * includes - 2 + */ + +#ifdef CSTRING_HAS_h_stdint_ # include #endif #include @@ -260,7 +292,52 @@ typedef int cstring_flags_t; /** \brief Hash value type * \ingroup group__cstring_api */ +#if 0 +#elif defined(CSTRING_HAS_h_stdint_) ||\ + defined(CSTRING_DOCUMENTATION_SKIP_SECTION) + typedef uint64_t cstring_hash_t; +#elif defined(_MSC_VER) + +typedef unsigned __int64_t cstring_hash_t; +#else + +# error 64-bit unsigned integer type not discriminated +#endif + +/** \def CSTRING_HASH_DJB2_SEED + * \ingroup group__cstring_api + * \brief djb2 initial seed (also the hash of an empty input) + * + * Daniel J. Bernstein's djb2, as published by Ozan Yigit. + * \sa http://www.cse.yorku.ca/~oz/hash.html#djb2 + */ +#define CSTRING_HASH_DJB2_SEED 5381ULL + +/** \def CSTRING_HASH_FNV1A_OFFSET + * \ingroup group__cstring_api + * \brief FNV-1a 64-bit offset basis (also the hash of an empty input) + * + * FNV-1a offset basis published by Fowler, Noll, and Vo, and in RFC 9923. + * \sa https://www.isthe.com/chongo/tech/comp/fnv/#FNV-1a + * \sa https://www.isthe.com/chongo/tech/comp/fnv/#FNV-param + * \sa https://www.rfc-editor.org/rfc/rfc9923.html#section-2.2 + * \sa https://www.rfc-editor.org/rfc/rfc9923.html#section-5 + */ +#define CSTRING_HASH_FNV1A_OFFSET 0xcbf29ce484222325ULL + +/** \def CSTRING_HASH_FNV1A_PRIME + * \ingroup group__cstring_api + * \brief FNV-1a 64-bit prime + * + * FNV-1a prime published by Fowler, Noll, and Vo, and in RFC 9923. + * \sa https://www.isthe.com/chongo/tech/comp/fnv/#FNV-1a + * \sa https://www.isthe.com/chongo/tech/comp/fnv/#FNV-param + * \sa https://www.isthe.com/chongo/tech/comp/fnv/#fnv-prime + * \sa https://www.rfc-editor.org/rfc/rfc9923.html#section-2.1 + * \sa https://www.rfc-editor.org/rfc/rfc9923.html#section-5 + */ +#define CSTRING_HASH_FNV1A_PRIME 0x100000001b3ULL /** \brief The cstring structure * \ingroup group__cstring_api @@ -1108,7 +1185,7 @@ cstring_appendLenFn( * \return A 64-bit djb2 hash value. */ CSTRING_EXTERN_C -uint64_t +cstring_hash_t cstring_hash_djb2( struct cstring_t const* pcs ); @@ -1122,8 +1199,8 @@ cstring_hash_djb2( * \return A case-insensitive 64-bit djb2 hash value. */ CSTRING_EXTERN_C -uint64_t -cstring_hash_djb2_ci( +cstring_hash_t +cstring_hash_djb2_case( struct cstring_t const* pcs ); @@ -1137,8 +1214,8 @@ cstring_hash_djb2_ci( * \return A 64-bit djb2 hash value. */ CSTRING_EXTERN_C -uint64_t -cstring_hash_djb2_len( +cstring_hash_t +cstring_hash_djb2_buf( cstring_char_t const* s , size_t cch ); @@ -1153,8 +1230,8 @@ cstring_hash_djb2_len( * \return A case-insensitive 64-bit djb2 hash value. */ CSTRING_EXTERN_C -uint64_t -cstring_hash_djb2_len_ci( +cstring_hash_t +cstring_hash_djb2_buf_case( cstring_char_t const* s , size_t cch ); @@ -1167,7 +1244,7 @@ cstring_hash_djb2_len_ci( * \return A 64-bit FNV-1a hash value. */ CSTRING_EXTERN_C -uint64_t +cstring_hash_t cstring_hash_fnv1a( struct cstring_t const* pcs ); @@ -1181,8 +1258,8 @@ cstring_hash_fnv1a( * \return A case-insensitive 64-bit FNV-1a hash value. */ CSTRING_EXTERN_C -uint64_t -cstring_hash_fnv1a_ci( +cstring_hash_t +cstring_hash_fnv1a_case( struct cstring_t const* pcs ); @@ -1196,8 +1273,8 @@ cstring_hash_fnv1a_ci( * \return A 64-bit FNV-1a hash value. */ CSTRING_EXTERN_C -uint64_t -cstring_hash_fnv1a_len( +cstring_hash_t +cstring_hash_fnv1a_buf( cstring_char_t const* s , size_t cch ); @@ -1212,8 +1289,8 @@ cstring_hash_fnv1a_len( * \return A case-insensitive 64-bit FNV-1a hash value. */ CSTRING_EXTERN_C -uint64_t -cstring_hash_fnv1a_len_ci( +cstring_hash_t +cstring_hash_fnv1a_buf_case( cstring_char_t const* s , size_t cch ); @@ -1234,11 +1311,16 @@ cstring_hash_fnv1a_len_ci( /* ///////////////////////////////////////////////////////////////////////// - * string access shims + * language */ #ifdef __cplusplus + +/* ///////////////////////////////////////////////////////////////////////// + * string access shims + */ + inline cstring_char_t const* c_str_data( @@ -1429,7 +1511,7 @@ c_str_ptr( */ inline -uint64_t +cstring_hash_t hash_djb2( struct cstring_t const* pcs ) @@ -1438,7 +1520,7 @@ hash_djb2( } inline -uint64_t +cstring_hash_t hash_djb2( struct cstring_t const& cs ) @@ -1447,45 +1529,45 @@ hash_djb2( } inline -uint64_t +cstring_hash_t hash_djb2( cstring_char_t const* s , size_t cch ) { - return cstring_hash_djb2_len(s, cch); + return cstring_hash_djb2_buf(s, cch); } inline -uint64_t -hash_djb2_ci( +cstring_hash_t +hash_djb2_case( struct cstring_t const* pcs ) { - return cstring_hash_djb2_ci(pcs); + return cstring_hash_djb2_case(pcs); } inline -uint64_t -hash_djb2_ci( +cstring_hash_t +hash_djb2_case( struct cstring_t const& cs ) { - return cstring_hash_djb2_ci(&cs); + return cstring_hash_djb2_case(&cs); } inline -uint64_t -hash_djb2_ci( +cstring_hash_t +hash_djb2_case( cstring_char_t const* s , size_t cch ) { - return cstring_hash_djb2_len_ci(s, cch); + return cstring_hash_djb2_buf_case(s, cch); } inline -uint64_t +cstring_hash_t hash_fnv1a( struct cstring_t const* pcs ) @@ -1494,7 +1576,7 @@ hash_fnv1a( } inline -uint64_t +cstring_hash_t hash_fnv1a( struct cstring_t const& cs ) @@ -1503,41 +1585,41 @@ hash_fnv1a( } inline -uint64_t +cstring_hash_t hash_fnv1a( cstring_char_t const* s , size_t cch ) { - return cstring_hash_fnv1a_len(s, cch); + return cstring_hash_fnv1a_buf(s, cch); } inline -uint64_t -hash_fnv1a_ci( +cstring_hash_t +hash_fnv1a_case( struct cstring_t const* pcs ) { - return cstring_hash_fnv1a_ci(pcs); + return cstring_hash_fnv1a_case(pcs); } inline -uint64_t -hash_fnv1a_ci( +cstring_hash_t +hash_fnv1a_case( struct cstring_t const& cs ) { - return cstring_hash_fnv1a_ci(&cs); + return cstring_hash_fnv1a_case(&cs); } inline -uint64_t -hash_fnv1a_ci( +cstring_hash_t +hash_fnv1a_case( cstring_char_t const* s , size_t cch ) { - return cstring_hash_fnv1a_len_ci(s, cch); + return cstring_hash_fnv1a_buf_case(s, cch); } # ifndef _STLSOFT_NO_NAMESPACE @@ -1557,6 +1639,12 @@ namespace stlsoft } /* namespace stlsoft */ # endif /* !_STLSOFT_NO_NAMESPACE */ + + +/* ///////////////////////////////////////////////////////////////////////// + * language + */ + #endif /* __cplusplus */ diff --git a/src/cstring.core.c b/src/cstring.core.c index bbd6245..4b42ef7 100644 --- a/src/cstring.core.c +++ b/src/cstring.core.c @@ -4,7 +4,7 @@ * Purpose: The implementation of the cstring core API * * Created: 16th June 1994 - * Updated: 3rd October 2026 + * Updated: 5th October 2026 * * Home: http://synesis.com.au/software/ * diff --git a/src/cstring.hash.c b/src/cstring.hash.c index 3ec9259..7ecbe71 100644 --- a/src/cstring.hash.c +++ b/src/cstring.hash.c @@ -1,15 +1,14 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: cstring.core.c + * File: cstring.hash.c * - * Purpose: The implementation of the cstring core API + * Purpose: The implementation of the cstring hash API * - * Created: 16th June 1994 - * Updated: 29th September 2026 + * Created: 5th September 2026 + * Updated: 5th October 2026 * * Home: http://synesis.com.au/software/ * - * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems - * Copyright (c) 1994-2019, Matthew Wilson and Synesis Software + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,7 +40,7 @@ * ////////////////////////////////////////////////////////////////////// */ -/** \file cstring.core.c The implementation of the cstring core API +/** \file cstring.hash.c The implementation of the cstring hash API */ /* ///////////////////////////////////////////////////////////////////////// @@ -78,39 +77,39 @@ * hashing functions */ -uint64_t +cstring_hash_t cstring_hash_djb2( struct cstring_t const* pcs ) { if (NULL == pcs) { - return 5381; + return CSTRING_HASH_DJB2_SEED; } - return cstring_hash_djb2_len(pcs->ptr, pcs->len); + return cstring_hash_djb2_buf(pcs->ptr, pcs->len); } -uint64_t -cstring_hash_djb2_ci( +cstring_hash_t +cstring_hash_djb2_case( struct cstring_t const* pcs ) { if (NULL == pcs) { - return 5381; + return CSTRING_HASH_DJB2_SEED; } - return cstring_hash_djb2_len_ci(pcs->ptr, pcs->len); + return cstring_hash_djb2_buf_case(pcs->ptr, pcs->len); } -uint64_t -cstring_hash_djb2_len( +cstring_hash_t +cstring_hash_djb2_buf( cstring_char_t const* s , size_t cch ) { - uint64_t hash = 5381; + cstring_hash_t hash = CSTRING_HASH_DJB2_SEED; if (NULL != s) { @@ -127,13 +126,13 @@ cstring_hash_djb2_len( return hash; } -uint64_t -cstring_hash_djb2_len_ci( +cstring_hash_t +cstring_hash_djb2_buf_case( cstring_char_t const* s , size_t cch ) { - uint64_t hash = 5381; + cstring_hash_t hash = CSTRING_HASH_DJB2_SEED; if (NULL != s) { @@ -154,40 +153,39 @@ cstring_hash_djb2_len_ci( return hash; } -uint64_t +cstring_hash_t cstring_hash_fnv1a( struct cstring_t const* pcs ) { if (NULL == pcs) { - return 0xcbf29ce484222325ULL; + return CSTRING_HASH_FNV1A_OFFSET; } - return cstring_hash_fnv1a_len(pcs->ptr, pcs->len); + return cstring_hash_fnv1a_buf(pcs->ptr, pcs->len); } -uint64_t -cstring_hash_fnv1a_ci( +cstring_hash_t +cstring_hash_fnv1a_case( struct cstring_t const* pcs ) { if (NULL == pcs) { - return 0xcbf29ce484222325ULL; + return CSTRING_HASH_FNV1A_OFFSET; } - return cstring_hash_fnv1a_len_ci(pcs->ptr, pcs->len); + return cstring_hash_fnv1a_buf_case(pcs->ptr, pcs->len); } -uint64_t -cstring_hash_fnv1a_len( +cstring_hash_t +cstring_hash_fnv1a_buf( cstring_char_t const* s , size_t cch ) { - uint64_t const fnv_prime = 0x100000001b3ULL; - uint64_t hash = 0xcbf29ce484222325ULL; + cstring_hash_t hash = CSTRING_HASH_FNV1A_OFFSET; if (NULL != s) { @@ -198,21 +196,20 @@ cstring_hash_fnv1a_len( uint8_t const c = (uint8_t)s[i]; hash ^= c; - hash *= fnv_prime; + hash *= CSTRING_HASH_FNV1A_PRIME; } } return hash; } -uint64_t -cstring_hash_fnv1a_len_ci( +cstring_hash_t +cstring_hash_fnv1a_buf_case( cstring_char_t const* s , size_t cch ) { - uint64_t const fnv_prime = 0x100000001b3ULL; - uint64_t hash = 0xcbf29ce484222325ULL; + cstring_hash_t hash = CSTRING_HASH_FNV1A_OFFSET; if (NULL != s) { @@ -227,7 +224,7 @@ cstring_hash_fnv1a_len_ci( #endif hash ^= c; - hash *= fnv_prime; + hash *= CSTRING_HASH_FNV1A_PRIME; } } diff --git a/src/cstring.vector.c b/src/cstring.vector.c index 81f43ed..cef19b6 100644 --- a/src/cstring.vector.c +++ b/src/cstring.vector.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// * File: cstring.vector.c * - * Purpose: The implementation of the cstring.vector API + * Purpose: The implementation of the cstring vector API * * Created: 16th June 1994 - * Updated: 29th September 2026 + * Updated: 5th October 2026 * * Home: http://synesis.com.au/software/ * @@ -71,13 +71,6 @@ #define CSTRING_VECTOR_DEF_CAPACITY_ (8) -/* ///////////////////////////////////////////////////////////////////////// - * debugging - */ - -#define CSTRING_VECTOR_ASSERT(expr) assert(expr) - - /* ///////////////////////////////////////////////////////////////////////// * compiler compatibility */ diff --git a/src/win.c b/src/win.c index 1d07a52..91e43b3 100644 --- a/src/win.c +++ b/src/win.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// * File: win.c * - * Purpose: Windows memory arenas for the cstring core API. + * Purpose: Windows memory arenas for cstring API. * * Created: 28th September 2026 - * Updated: 29th September 2026 + * Updated: 5th October 2026 * * Home: http://synesis.com.au/software/ * @@ -41,7 +41,7 @@ * ////////////////////////////////////////////////////////////////////// */ -/** \file win.c Windows memory arenas for the cstring core API +/** \file win.c Windows memory arenas for cstring API */ /* ///////////////////////////////////////////////////////////////////////// @@ -53,26 +53,28 @@ /* ///////////////////////////////////////////////////////////////////////// - * Win32 functions + * Windows functions */ #ifndef CSTRING_DOCUMENTATION_SKIP_SECTION -# if defined(__MWERKS__) -# define GMEM_FIXED 0 -# define GMEM_MOVEABLE 2 -typedef int BOOL; -typedef void* HANDLE; -typedef void* HGLOBAL; -__declspec(dllimport) HANDLE __stdcall GetProcessHeap(void); -__declspec(dllimport) HGLOBAL __stdcall GlobalAlloc(unsigned int, unsigned long); -__declspec(dllimport) HGLOBAL __stdcall GlobalFree(HGLOBAL); -__declspec(dllimport) HGLOBAL __stdcall GlobalReAlloc(HGLOBAL, unsigned long, unsigned int); -__declspec(dllimport) void* __stdcall HeapAlloc(HANDLE, unsigned long, unsigned int); -__declspec(dllimport) BOOL __stdcall HeapFree(HANDLE, unsigned long, void* ); -__declspec(dllimport) void* __stdcall HeapReAlloc(HANDLE, unsigned long, void*, unsigned int); -__declspec(dllimport) void* __stdcall CoTaskMemAlloc(unsigned long); -__declspec(dllimport) void __stdcall CoTaskMemFree(void* ); -__declspec(dllimport) void* __stdcall CoTaskMemRealloc(void* , unsigned long); +# if 0 +# elif defined(__MWERKS__) + +# define GMEM_FIXED 0 +# define GMEM_MOVEABLE 2 +typedef int BOOL; +typedef void* HANDLE; +typedef void* HGLOBAL; +__declspec(dllimport) HANDLE __stdcall GetProcessHeap(void); +__declspec(dllimport) HGLOBAL __stdcall GlobalAlloc(unsigned int, unsigned long); +__declspec(dllimport) HGLOBAL __stdcall GlobalFree(HGLOBAL); +__declspec(dllimport) HGLOBAL __stdcall GlobalReAlloc(HGLOBAL, unsigned long, unsigned int); +__declspec(dllimport) void* __stdcall HeapAlloc(HANDLE, unsigned long, unsigned int); +__declspec(dllimport) BOOL __stdcall HeapFree(HANDLE, unsigned long, void* ); +__declspec(dllimport) void* __stdcall HeapReAlloc(HANDLE, unsigned long, void*, unsigned int); +__declspec(dllimport) void* __stdcall CoTaskMemAlloc(unsigned long); +__declspec(dllimport) void __stdcall CoTaskMemFree(void* ); +__declspec(dllimport) void* __stdcall CoTaskMemRealloc(void* , unsigned long); # else /* ? compiler */ # include @@ -80,7 +82,10 @@ __declspec(dllimport) void* __stdcall CoTaskMemRealloc(void* , unsigne # endif /* compiler */ #endif /* !CSTRING_DOCUMENTATION_SKIP_SECTION */ -/* ////////////////////////////////////////////////////////////////////// */ + +/* ///////////////////////////////////////////////////////////////////////// + * internal API functions + */ void* win32_global_realloc( diff --git a/test/performance/cstring_readline/main.cpp b/test/performance/cstring_readline/main.cpp index e6eb9fa..164de2e 100644 --- a/test/performance/cstring_readline/main.cpp +++ b/test/performance/cstring_readline/main.cpp @@ -119,13 +119,13 @@ emit_row( ); } -std::uint64_t +uint64_t line_anchor( size_t len , unsigned char head ) { - return static_cast(len) + 1u + static_cast(head); + return static_cast(len) + 1u + static_cast(head); } unsigned char @@ -142,7 +142,7 @@ content_head( return static_cast(p[0]); } -std::uint64_t +uint64_t read_all_cstring( char const* path , size_t line_len @@ -156,8 +156,8 @@ read_all_cstring( return 0; } - cstring_t cs = cstring_t_DEFAULT; - std::uint64_t anchor = 0; + cstring_t cs = cstring_t_DEFAULT; + uint64_t anchor = 0; if (INSTANCE_PRERESERVED == mode && 0 != line_len) { @@ -203,7 +203,7 @@ read_all_cstring( return anchor; } -std::uint64_t +uint64_t read_all_getline( char const* path , size_t line_len @@ -218,7 +218,7 @@ read_all_getline( } std::string line; - std::uint64_t anchor = 0; + uint64_t anchor = 0; if (INSTANCE_PRERESERVED == mode && 0 != line_len) { @@ -252,7 +252,7 @@ read_all_getline( */ size_t const FGETS_REUSE_BUF = 4096u; -std::uint64_t +uint64_t read_all_fgets( char const* path , size_t line_len @@ -271,7 +271,7 @@ read_all_fgets( ; std::vector buf; - std::uint64_t anchor = 0; + uint64_t anchor = 0; size_t content_len = 0; unsigned char head = 0; bool pending_cr = false; @@ -380,7 +380,7 @@ read_all_fgets( return anchor; } -std::uint64_t +uint64_t read_all_raw_fgetc( char const* path , size_t line_len @@ -408,7 +408,7 @@ read_all_raw_fgetc( } } - std::uint64_t anchor = 0; + uint64_t anchor = 0; int previous = '\0'; for (;;) @@ -534,19 +534,19 @@ scenario_readline( size_t const line_len = spec.line_len; instance_mode_t const mode = spec.mode; - run_result const cs = time_iterations(num_trials, num_warm_loops, [path, line_len, mode]() -> std::uint64_t { + run_result const cs = time_iterations(num_trials, num_warm_loops, [path, line_len, mode]() -> uint64_t { return read_all_cstring(path, line_len, mode); }); - run_result const gl = time_iterations(num_trials, num_warm_loops, [path, line_len, mode]() -> std::uint64_t { + run_result const gl = time_iterations(num_trials, num_warm_loops, [path, line_len, mode]() -> uint64_t { return read_all_getline(path, line_len, mode); }); - run_result const fg = time_iterations(num_trials, num_warm_loops, [path, line_len, mode]() -> std::uint64_t { + run_result const fg = time_iterations(num_trials, num_warm_loops, [path, line_len, mode]() -> uint64_t { return read_all_fgets(path, line_len, mode); }); - run_result const raw = time_iterations(num_trials, num_warm_loops, [path, line_len, mode]() -> std::uint64_t { + run_result const raw = time_iterations(num_trials, num_warm_loops, [path, line_len, mode]() -> uint64_t { return read_all_raw_fgetc(path, line_len, mode); }); diff --git a/test/performance/cstring_vector/main.cpp b/test/performance/cstring_vector/main.cpp index 70b73c3..91234ef 100644 --- a/test/performance/cstring_vector/main.cpp +++ b/test/performance/cstring_vector/main.cpp @@ -121,20 +121,20 @@ scenario_create_destroy( , size_t num_warm_loops ) { - run_result const cs = time_iterations(num_iterations, num_warm_loops, [n]() -> std::uint64_t { + run_result const cs = time_iterations(num_iterations, num_warm_loops, [n]() -> uint64_t { cstring_vector_t v = cstring_vector_t_DEFAULT; cstring_vector_create(&v, n); - std::uint64_t const a = v.len + v.capacity; + uint64_t const a = v.len + v.capacity; cstring_vector_destroy(&v); return a; }); - run_result const st = time_iterations(num_iterations, num_warm_loops, [n]() -> std::uint64_t { + run_result const st = time_iterations(num_iterations, num_warm_loops, [n]() -> uint64_t { std::vector v(n); return v.size() + v.capacity(); }); - run_result const raw = time_iterations(num_iterations, num_warm_loops, [n]() -> std::uint64_t { + run_result const raw = time_iterations(num_iterations, num_warm_loops, [n]() -> uint64_t { raw_string_vector v; raw_vec_init(&v); raw_vec_reserve(&v, n); @@ -143,7 +143,7 @@ scenario_create_destroy( { v.ptr[i] = NULL; } - std::uint64_t const a = v.len + v.capacity; + uint64_t const a = v.len + v.capacity; raw_vec_destroy(&v); return a; }); @@ -164,7 +164,7 @@ scenario_append_one_by_one( cstring_t payload = make_cstring_payload(payload_len); std::string const payload_s = make_payload(payload_len); - run_result const cs = time_iterations(num_iterations, num_warm_loops, [&payload, k]() -> std::uint64_t { + run_result const cs = time_iterations(num_iterations, num_warm_loops, [&payload, k]() -> uint64_t { cstring_vector_t v = cstring_vector_t_DEFAULT; cstring_vector_init(&v, 0); for (size_t i = 0; k != i; ++i) @@ -181,7 +181,7 @@ scenario_append_one_by_one( ? v.ptr[v.len - 1u].ptr : NULL ; - std::uint64_t const a = + uint64_t const a = v.len + (NULL != head ? static_cast(head[0]) : 0u) + (NULL != tail ? static_cast(tail[0]) : 0u) @@ -190,7 +190,7 @@ scenario_append_one_by_one( return a; }); - run_result const st = time_iterations(num_iterations, num_warm_loops, [&payload_s, k]() -> std::uint64_t { + run_result const st = time_iterations(num_iterations, num_warm_loops, [&payload_s, k]() -> uint64_t { std::vector v; for (size_t i = 0; k != i; ++i) { @@ -204,7 +204,7 @@ scenario_append_one_by_one( ; }); - run_result const raw = time_iterations(num_iterations, num_warm_loops, [&payload_s, payload_len, k]() -> std::uint64_t { + run_result const raw = time_iterations(num_iterations, num_warm_loops, [&payload_s, payload_len, k]() -> uint64_t { raw_string_vector v; raw_vec_init(&v); for (size_t i = 0; k != i; ++i) @@ -217,7 +217,7 @@ scenario_append_one_by_one( char const* volatile tail = (0 != v.len && NULL != v.ptr) ? v.ptr[v.len - 1u] : NULL ; - std::uint64_t const a = + uint64_t const a = v.len + (NULL != head ? static_cast(head[0]) : 0u) + (NULL != tail ? static_cast(tail[0]) : 0u) @@ -252,7 +252,7 @@ scenario_append_batch( payloads_s[i] = proto; } - run_result const cs = time_iterations(num_iterations, num_warm_loops, [&payloads, k]() -> std::uint64_t { + run_result const cs = time_iterations(num_iterations, num_warm_loops, [&payloads, k]() -> uint64_t { cstring_vector_t v = cstring_vector_t_DEFAULT; cstring_vector_init(&v, 0); cstring_vector_append(&v, &payloads[0], k); @@ -266,7 +266,7 @@ scenario_append_batch( ? v.ptr[v.len - 1u].ptr : NULL ; - std::uint64_t const a = + uint64_t const a = v.len + (NULL != head ? static_cast(head[0]) : 0u) + (NULL != tail ? static_cast(tail[0]) : 0u) @@ -275,7 +275,7 @@ scenario_append_batch( return a; }); - run_result const st = time_iterations(num_iterations, num_warm_loops, [&payloads_s]() -> std::uint64_t { + run_result const st = time_iterations(num_iterations, num_warm_loops, [&payloads_s]() -> uint64_t { std::vector v; v.insert(v.end(), payloads_s.begin(), payloads_s.end()); char const* volatile head = v.empty() ? NULL : v.front().data(); @@ -286,7 +286,7 @@ scenario_append_batch( ; }); - run_result const raw = time_iterations(num_iterations, num_warm_loops, [&payloads_s, payload_len, k]() -> std::uint64_t { + run_result const raw = time_iterations(num_iterations, num_warm_loops, [&payloads_s, payload_len, k]() -> uint64_t { raw_string_vector v; raw_vec_init(&v); raw_vec_reserve(&v, k); @@ -300,7 +300,7 @@ scenario_append_batch( char const* volatile tail = (0 != v.len && NULL != v.ptr) ? v.ptr[v.len - 1u] : NULL ; - std::uint64_t const a = + uint64_t const a = v.len + (NULL != head ? static_cast(head[0]) : 0u) + (NULL != tail ? static_cast(tail[0]) : 0u) @@ -330,7 +330,7 @@ scenario_prepend_one_by_one( cstring_t payload = make_cstring_payload(payload_len); std::string const payload_s = make_payload(payload_len); - run_result const cs = time_iterations(num_iterations, num_warm_loops, [&payload, k]() -> std::uint64_t { + run_result const cs = time_iterations(num_iterations, num_warm_loops, [&payload, k]() -> uint64_t { cstring_vector_t v = cstring_vector_t_DEFAULT; cstring_vector_init(&v, 0); for (size_t i = 0; k != i; ++i) @@ -347,7 +347,7 @@ scenario_prepend_one_by_one( ? v.ptr[v.len - 1u].ptr : NULL ; - std::uint64_t const a = + uint64_t const a = v.len + (NULL != head ? static_cast(head[0]) : 0u) + (NULL != tail ? static_cast(tail[0]) : 0u) @@ -356,7 +356,7 @@ scenario_prepend_one_by_one( return a; }); - run_result const st = time_iterations(num_iterations, num_warm_loops, [&payload_s, k]() -> std::uint64_t { + run_result const st = time_iterations(num_iterations, num_warm_loops, [&payload_s, k]() -> uint64_t { std::vector v; for (size_t i = 0; k != i; ++i) { @@ -370,7 +370,7 @@ scenario_prepend_one_by_one( ; }); - run_result const raw = time_iterations(num_iterations, num_warm_loops, [&payload_s, payload_len, k]() -> std::uint64_t { + run_result const raw = time_iterations(num_iterations, num_warm_loops, [&payload_s, payload_len, k]() -> uint64_t { raw_string_vector v; raw_vec_init(&v); for (size_t i = 0; k != i; ++i) @@ -383,7 +383,7 @@ scenario_prepend_one_by_one( char const* volatile tail = (0 != v.len && NULL != v.ptr) ? v.ptr[v.len - 1u] : NULL ; - std::uint64_t const a = + uint64_t const a = v.len + (NULL != head ? static_cast(head[0]) : 0u) + (NULL != tail ? static_cast(tail[0]) : 0u) @@ -401,13 +401,13 @@ scenario_prepend_one_by_one( #ifdef HAS_P99 template -std::uint64_t +uint64_t sum_line_lengths( size_t count , F length_at ) { - std::uint64_t a = count; + uint64_t a = count; for (size_t i = 0; count != i; ++i) { @@ -474,7 +474,7 @@ scenario_file_lines_vs_readlines( << std::endl ; - run_result const cs = time_iterations(num_trials, num_warm_loops, []() -> std::uint64_t { + run_result const cs = time_iterations(num_trials, num_warm_loops, []() -> uint64_t { FILE* f = std::fopen(TEST_FILE_NAME, "rb"); if (NULL == f) { @@ -484,7 +484,7 @@ scenario_file_lines_vs_readlines( cstring_vector_t v = cstring_vector_t_DEFAULT; cstring_vector_init(&v, 0); cstring_vector_readLines(f, &v, NULL); - std::uint64_t const a = sum_line_lengths( + uint64_t const a = sum_line_lengths( v.len , [&v](size_t i) -> size_t { @@ -496,7 +496,7 @@ scenario_file_lines_vs_readlines( return a; }); - run_result const gl = time_iterations(num_trials, num_warm_loops, []() -> std::uint64_t { + run_result const gl = time_iterations(num_trials, num_warm_loops, []() -> uint64_t { std::ifstream in(TEST_FILE_NAME, std::ios::in | std::ios::binary); if (!in) @@ -522,7 +522,7 @@ scenario_file_lines_vs_readlines( ); }); - run_result const fl = time_iterations(num_trials, num_warm_loops, []() -> std::uint64_t { + run_result const fl = time_iterations(num_trials, num_warm_loops, []() -> uint64_t { platformstl::file_lines_a lines(TEST_FILE_NAME); return sum_line_lengths( lines.size() diff --git a/test/performance/perf_harness.hpp b/test/performance/perf_harness.hpp index 103d390..a3fef6e 100644 --- a/test/performance/perf_harness.hpp +++ b/test/performance/perf_harness.hpp @@ -203,7 +203,7 @@ write_lines_file( struct run_result { interval_t tm_ns; - std::uint64_t anchor; + uint64_t anchor; #ifdef HAS_P99 p99::histogram hist; @@ -248,7 +248,7 @@ time_iterations( if (1 == w) { - std::uint64_t volatile hist_anchor = 0; + uint64_t volatile hist_anchor = 0; for (size_t i = 0; num_iterations != i; ++i) { @@ -258,7 +258,7 @@ time_iterations( interval_t const sample = sw.get_nanoseconds(); - (void)result.hist.push_ns(static_cast(sample)); + (void)result.hist.push_ns(static_cast(sample)); } (void)hist_anchor; diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index ccc1aab..6685e09 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -1,11 +1,15 @@ add_subdirectory(auto-buffer) -add_subdirectory(cstring) add_subdirectory(cstring_vector) if(NOT NO_CSTRING_CPP_API) add_subdirectory(cstring.cxx) - add_subdirectory(hash) +endif() +add_subdirectory(cstring) +add_subdirectory(hash) +if(NOT NO_CSTRING_CPP_API) + + add_subdirectory(hash.cxx) endif() add_subdirectory(insert-replace) add_subdirectory(status-codes) diff --git a/test/unit/hash.cxx/CMakeLists.txt b/test/unit/hash.cxx/CMakeLists.txt new file mode 100644 index 0000000..8fa9d69 --- /dev/null +++ b/test/unit/hash.cxx/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.hash.cxx entry.cpp) diff --git a/test/unit/hash.cxx/entry.cpp b/test/unit/hash.cxx/entry.cpp new file mode 100644 index 0000000..ac423fb --- /dev/null +++ b/test/unit/hash.cxx/entry.cpp @@ -0,0 +1,162 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test/unit/hash.cxx/entry.cpp + * + * Purpose: Unit-tests for the C++ cstring hash access shims. + * + * Created: 5th September 2026 + * Updated: 5th October 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include + +/* STLSoft header files */ +#include + +/* Standard C header files */ +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * character encoding + */ + +#ifdef CSTRING_USE_WIDE_STRINGS +# define CSTRING_T_(x) L ## x +#else /* ? CSTRING_USE_WIDE_STRINGS */ +# define CSTRING_T_(x) x +#endif /* CSTRING_USE_WIDE_STRINGS */ + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace +{ + + static void TEST_hash_djb2_AND_hash_fnv1a_NULL_AND_EMPTY(void); + static void TEST_hash_djb2_AND_hash_fnv1a_KNOWN_VECTORS(void); + static void TEST_hash_djb2_AND_hash_djb2_ci_AND_hash_fnv1a_AND_hash_fnv1a_case(void); +} /* anonymous namespace */ + + +/* ///////////////////////////////////////////////////////////////////////// + * main + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.hash.cxx", verbosity)) + { + XTESTS_RUN_CASE(TEST_hash_djb2_AND_hash_fnv1a_NULL_AND_EMPTY); + XTESTS_RUN_CASE(TEST_hash_djb2_AND_hash_fnv1a_KNOWN_VECTORS); + XTESTS_RUN_CASE(TEST_hash_djb2_AND_hash_djb2_ci_AND_hash_fnv1a_AND_hash_fnv1a_case); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace +{ + +static void TEST_hash_djb2_AND_hash_fnv1a_NULL_AND_EMPTY(void) +{ + cstring_t const default_cs = cstring_t_DEFAULT; + + TEST_INT_EQ(5381ULL, hash_djb2(static_cast(NULL))); + TEST_INT_EQ(5381ULL, hash_djb2_case(static_cast(NULL))); + TEST_INT_EQ(5381ULL, hash_djb2(default_cs)); + TEST_INT_EQ(5381ULL, hash_djb2_case(default_cs)); + TEST_INT_EQ(5381ULL, hash_djb2(NULL, 0)); + TEST_INT_EQ(5381ULL, hash_djb2_case(NULL, 0)); + + TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a(static_cast(NULL))); + TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a_case(static_cast(NULL))); + TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a(default_cs)); + TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a_case(default_cs)); + TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a(NULL, 0)); + TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a_case(NULL, 0)); +} + +static void TEST_hash_djb2_AND_hash_fnv1a_KNOWN_VECTORS(void) +{ + cstring_t cs_a; + cstring_t cs_foobar; + CSTRING_RC rc; + + rc = cstring_create(&cs_a, CSTRING_T_("a")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + TEST_INT_EQ(177670ULL, hash_djb2(cs_a)); + TEST_INT_EQ(0xaf63dc4c8601ec8cULL, hash_fnv1a(cs_a)); + cstring_destroy(&cs_a); + + rc = cstring_create(&cs_foobar, CSTRING_T_("foobar")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + TEST_INT_EQ(6953516687550ULL, hash_djb2(cs_foobar)); + TEST_INT_EQ(0x85944171f73967e8ULL, hash_fnv1a(cs_foobar)); + cstring_destroy(&cs_foobar); +} + +static void TEST_hash_djb2_AND_hash_djb2_ci_AND_hash_fnv1a_AND_hash_fnv1a_case(void) +{ + cstring_t cs; + CSTRING_RC rc = cstring_create(&cs, CSTRING_T_("Hello World")); + + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + + /* Overload by reference */ + TEST_INT_EQ(cstring_hash_djb2(&cs), hash_djb2(cs)); + TEST_INT_EQ(cstring_hash_djb2_case(&cs), hash_djb2_case(cs)); + TEST_INT_EQ(cstring_hash_fnv1a(&cs), hash_fnv1a(cs)); + TEST_INT_EQ(cstring_hash_fnv1a_case(&cs), hash_fnv1a_case(cs)); + + /* Overload by pointer */ + TEST_INT_EQ(cstring_hash_djb2(&cs), hash_djb2(&cs)); + TEST_INT_EQ(cstring_hash_djb2_case(&cs), hash_djb2_case(&cs)); + TEST_INT_EQ(cstring_hash_fnv1a(&cs), hash_fnv1a(&cs)); + TEST_INT_EQ(cstring_hash_fnv1a_case(&cs), hash_fnv1a_case(&cs)); + + /* Overload by slice/buffer */ + TEST_INT_EQ(cstring_hash_djb2_buf(cs.ptr, cs.len), hash_djb2(cs.ptr, cs.len)); + TEST_INT_EQ(cstring_hash_djb2_buf_case(cs.ptr, cs.len), hash_djb2_case(cs.ptr, cs.len)); + TEST_INT_EQ(cstring_hash_fnv1a_buf(cs.ptr, cs.len), hash_fnv1a(cs.ptr, cs.len)); + TEST_INT_EQ(cstring_hash_fnv1a_buf_case(cs.ptr, cs.len), hash_fnv1a_case(cs.ptr, cs.len)); + + cstring_destroy(&cs); +} +} /* anonymous namespace */ + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/hash/CMakeLists.txt b/test/unit/hash/CMakeLists.txt index 0e47709..47c1f69 100644 --- a/test/unit/hash/CMakeLists.txt +++ b/test/unit/hash/CMakeLists.txt @@ -1 +1,7 @@ -define_automated_test_program(test.unit.hash entry.cpp) +# MSVC C4310: (cstring_char_t)0xFF truncates when char is signed. The test +# stores that octet on purpose, including the signed-char case. +list(APPEND X_MSVC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED + 4310 +) + +define_automated_test_program(test.unit.hash entry.c) diff --git a/test/unit/hash/entry.c b/test/unit/hash/entry.c new file mode 100644 index 0000000..1308e2b --- /dev/null +++ b/test/unit/hash/entry.c @@ -0,0 +1,431 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test/unit/hash/entry.c + * + * Purpose: Unit-tests for the cstring hashing API. + * + * Created: 5th September 2026 + * Updated: 5th October 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include + +/* STLSoft header files */ +#include + +/* Standard C header files */ +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_NULL_AND_EMPTY(void); +static void TEST_cstring_hash_fnv1a_KNOWN_VECTORS(void); +static void TEST_cstring_hash_djb2_KNOWN_VECTORS(void); +static void TEST_cstring_hash_djb2_ci_AND_cstring_hash_fnv1a_case(void); +static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_SINGLE_CHARACTER(void); +static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_LONG_STRING(void); +static void TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_SLICES(void); +static void TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_OCTET_ABOVE_7F(void); +static void TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_EMBEDDED_NUL(void); + + +/* ///////////////////////////////////////////////////////////////////////// + * character encoding + */ + +#ifdef CSTRING_USE_WIDE_STRINGS +# define CSTRING_T_(x) L ## x +#else /* ? CSTRING_USE_WIDE_STRINGS */ +# define CSTRING_T_(x) x +#endif /* CSTRING_USE_WIDE_STRINGS */ + + +/* ///////////////////////////////////////////////////////////////////////// + * main + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.hash", verbosity)) + { + XTESTS_RUN_CASE(TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_NULL_AND_EMPTY); + XTESTS_RUN_CASE(TEST_cstring_hash_fnv1a_KNOWN_VECTORS); + XTESTS_RUN_CASE(TEST_cstring_hash_djb2_KNOWN_VECTORS); + XTESTS_RUN_CASE(TEST_cstring_hash_djb2_ci_AND_cstring_hash_fnv1a_case); + XTESTS_RUN_CASE(TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_SINGLE_CHARACTER); + XTESTS_RUN_CASE(TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_LONG_STRING); + XTESTS_RUN_CASE(TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_SLICES); + XTESTS_RUN_CASE(TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_OCTET_ABOVE_7F); + XTESTS_RUN_CASE(TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_EMBEDDED_NUL); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_NULL_AND_EMPTY(void) +{ + struct cstring_t const* pcs_null = NULL; + cstring_t null_cs = { 0, NULL, 0, 0 }; + cstring_t default_cs = cstring_t_DEFAULT; + cstring_t created_empty; + CSTRING_RC rc; + + TEST_INT_EQ(5381ULL, CSTRING_HASH_DJB2_SEED); + TEST_INT_EQ(0xcbf29ce484222325ULL, CSTRING_HASH_FNV1A_OFFSET); + TEST_INT_EQ(0x100000001b3ULL, CSTRING_HASH_FNV1A_PRIME); + + rc = cstring_create(&created_empty, CSTRING_T_("")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + + /* djb2: initial seed is 5381 */ + TEST_INT_EQ(5381ULL, cstring_hash_djb2(pcs_null)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2_case(pcs_null)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2(&null_cs)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2_case(&null_cs)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2(&default_cs)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2_case(&default_cs)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2(&created_empty)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2_case(&created_empty)); + + TEST_INT_EQ(5381ULL, cstring_hash_djb2_buf(NULL, 0)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2_buf_case(NULL, 0)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2_buf(NULL, 10)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2_buf_case(NULL, 10)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2_buf(CSTRING_T_(""), 0)); + TEST_INT_EQ(5381ULL, cstring_hash_djb2_buf_case(CSTRING_T_(""), 0)); + + /* FNV-1a: offset basis is 0xcbf29ce484222325ULL */ + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a(pcs_null)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_case(pcs_null)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a(&null_cs)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_case(&null_cs)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a(&default_cs)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_case(&default_cs)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a(&created_empty)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_case(&created_empty)); + + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_buf(NULL, 0)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_buf_case(NULL, 0)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_buf(NULL, 10)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_buf_case(NULL, 10)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_buf(CSTRING_T_(""), 0)); + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_buf_case(CSTRING_T_(""), 0)); + + cstring_destroy(&created_empty); +} + +static void TEST_cstring_hash_fnv1a_KNOWN_VECTORS(void) +{ + /* Known FNV-1a 64-bit test vectors: + * "" -> 0xcbf29ce484222325ULL + * "a" -> 0xaf63dc4c8601ec8cULL + * "foobar" -> 0x85944171f73967e8ULL + */ + cstring_t cs_a; + cstring_t cs_foobar; + CSTRING_RC rc; + + TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_buf(CSTRING_T_(""), 0)); + TEST_INT_EQ(0xaf63dc4c8601ec8cULL, cstring_hash_fnv1a_buf(CSTRING_T_("a"), 1)); + TEST_INT_EQ(0x85944171f73967e8ULL, cstring_hash_fnv1a_buf(CSTRING_T_("foobar"), 6)); + + rc = cstring_create(&cs_a, CSTRING_T_("a")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + TEST_INT_EQ(0xaf63dc4c8601ec8cULL, cstring_hash_fnv1a(&cs_a)); + cstring_destroy(&cs_a); + + rc = cstring_create(&cs_foobar, CSTRING_T_("foobar")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + TEST_INT_EQ(0x85944171f73967e8ULL, cstring_hash_fnv1a(&cs_foobar)); + cstring_destroy(&cs_foobar); +} + +static void TEST_cstring_hash_djb2_KNOWN_VECTORS(void) +{ + /* Known djb2 test vectors: + * "" -> 5381ULL + * "a" -> 5381 * 33 + 97 = 177670ULL (0x2b606ULL) + * "foobar" -> 6953516687550ULL (0x652fde460beULL) + */ + cstring_t cs_a; + cstring_t cs_foobar; + CSTRING_RC rc; + + TEST_INT_EQ(5381ULL, cstring_hash_djb2_buf(CSTRING_T_(""), 0)); + TEST_INT_EQ(177670ULL, cstring_hash_djb2_buf(CSTRING_T_("a"), 1)); + TEST_INT_EQ(6953516687550ULL, cstring_hash_djb2_buf(CSTRING_T_("foobar"), 6)); + + rc = cstring_create(&cs_a, CSTRING_T_("a")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + TEST_INT_EQ(177670ULL, cstring_hash_djb2(&cs_a)); + cstring_destroy(&cs_a); + + rc = cstring_create(&cs_foobar, CSTRING_T_("foobar")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + TEST_INT_EQ(6953516687550ULL, cstring_hash_djb2(&cs_foobar)); + cstring_destroy(&cs_foobar); +} + +static void TEST_cstring_hash_djb2_ci_AND_cstring_hash_fnv1a_case(void) +{ + cstring_hash_t djb2_ci_base; + cstring_hash_t fnv1a_ci_base; + cstring_t cs1; + cstring_t cs2; + cstring_t cs3; + cstring_t cs4; + CSTRING_RC rc; + + /* Buffer checks */ + djb2_ci_base = cstring_hash_djb2_buf_case(CSTRING_T_("Test"), 4); + TEST_INT_EQ(djb2_ci_base, cstring_hash_djb2_buf_case(CSTRING_T_("tEst"), 4)); + TEST_INT_EQ(djb2_ci_base, cstring_hash_djb2_buf_case(CSTRING_T_("TEST"), 4)); + TEST_INT_EQ(djb2_ci_base, cstring_hash_djb2_buf_case(CSTRING_T_("test"), 4)); + TEST_INT_EQ(djb2_ci_base, cstring_hash_djb2_buf_case(CSTRING_T_("teSt"), 4)); + + fnv1a_ci_base = cstring_hash_fnv1a_buf_case(CSTRING_T_("Test"), 4); + TEST_INT_EQ(fnv1a_ci_base, cstring_hash_fnv1a_buf_case(CSTRING_T_("tEst"), 4)); + TEST_INT_EQ(fnv1a_ci_base, cstring_hash_fnv1a_buf_case(CSTRING_T_("TEST"), 4)); + TEST_INT_EQ(fnv1a_ci_base, cstring_hash_fnv1a_buf_case(CSTRING_T_("test"), 4)); + TEST_INT_EQ(fnv1a_ci_base, cstring_hash_fnv1a_buf_case(CSTRING_T_("teSt"), 4)); + + /* Case-sensitive inequality */ + TEST_INT_NE(cstring_hash_djb2_buf(CSTRING_T_("Test"), 4), cstring_hash_djb2_buf(CSTRING_T_("tEst"), 4)); + TEST_INT_NE(cstring_hash_fnv1a_buf(CSTRING_T_("Test"), 4), cstring_hash_fnv1a_buf(CSTRING_T_("tEst"), 4)); + + /* Instance checks */ + rc = cstring_create(&cs1, CSTRING_T_("Test")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + rc = cstring_create(&cs2, CSTRING_T_("tEst")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + rc = cstring_create(&cs3, CSTRING_T_("TEST")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + rc = cstring_create(&cs4, CSTRING_T_("test")); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + + TEST_INT_EQ(cstring_hash_djb2_case(&cs1), cstring_hash_djb2_case(&cs2)); + TEST_INT_EQ(cstring_hash_djb2_case(&cs1), cstring_hash_djb2_case(&cs3)); + TEST_INT_EQ(cstring_hash_djb2_case(&cs1), cstring_hash_djb2_case(&cs4)); + + TEST_INT_EQ(cstring_hash_fnv1a_case(&cs1), cstring_hash_fnv1a_case(&cs2)); + TEST_INT_EQ(cstring_hash_fnv1a_case(&cs1), cstring_hash_fnv1a_case(&cs3)); + TEST_INT_EQ(cstring_hash_fnv1a_case(&cs1), cstring_hash_fnv1a_case(&cs4)); + + TEST_INT_NE(cstring_hash_djb2(&cs1), cstring_hash_djb2(&cs2)); + TEST_INT_NE(cstring_hash_fnv1a(&cs1), cstring_hash_fnv1a(&cs2)); + + cstring_destroy(&cs1); + cstring_destroy(&cs2); + cstring_destroy(&cs3); + cstring_destroy(&cs4); +} + +static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_SINGLE_CHARACTER(void) +{ + /* Letters */ + TEST_INT_EQ(cstring_hash_djb2_buf_case(CSTRING_T_("a"), 1), cstring_hash_djb2_buf_case(CSTRING_T_("A"), 1)); + TEST_INT_EQ(cstring_hash_fnv1a_buf_case(CSTRING_T_("a"), 1), cstring_hash_fnv1a_buf_case(CSTRING_T_("A"), 1)); + TEST_INT_NE(cstring_hash_djb2_buf(CSTRING_T_("a"), 1), cstring_hash_djb2_buf(CSTRING_T_("A"), 1)); + TEST_INT_NE(cstring_hash_fnv1a_buf(CSTRING_T_("a"), 1), cstring_hash_fnv1a_buf(CSTRING_T_("A"), 1)); + + TEST_INT_EQ(cstring_hash_djb2_buf_case(CSTRING_T_("z"), 1), cstring_hash_djb2_buf_case(CSTRING_T_("Z"), 1)); + TEST_INT_EQ(cstring_hash_fnv1a_buf_case(CSTRING_T_("z"), 1), cstring_hash_fnv1a_buf_case(CSTRING_T_("Z"), 1)); + TEST_INT_NE(cstring_hash_djb2_buf(CSTRING_T_("z"), 1), cstring_hash_djb2_buf(CSTRING_T_("Z"), 1)); + TEST_INT_NE(cstring_hash_fnv1a_buf(CSTRING_T_("z"), 1), cstring_hash_fnv1a_buf(CSTRING_T_("Z"), 1)); + + /* Non-letters have identical case-sensitive and case-insensitive hashes */ + TEST_INT_EQ(cstring_hash_djb2_buf(CSTRING_T_("0"), 1), cstring_hash_djb2_buf_case(CSTRING_T_("0"), 1)); + TEST_INT_EQ(cstring_hash_fnv1a_buf(CSTRING_T_("0"), 1), cstring_hash_fnv1a_buf_case(CSTRING_T_("0"), 1)); + + TEST_INT_EQ(cstring_hash_djb2_buf(CSTRING_T_("!"), 1), cstring_hash_djb2_buf_case(CSTRING_T_("!"), 1)); + TEST_INT_EQ(cstring_hash_fnv1a_buf(CSTRING_T_("!"), 1), cstring_hash_fnv1a_buf_case(CSTRING_T_("!"), 1)); + + TEST_INT_EQ(cstring_hash_djb2_buf(CSTRING_T_(" "), 1), cstring_hash_djb2_buf_case(CSTRING_T_(" "), 1)); + TEST_INT_EQ(cstring_hash_fnv1a_buf(CSTRING_T_(" "), 1), cstring_hash_fnv1a_buf_case(CSTRING_T_(" "), 1)); +} + +static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_LONG_STRING(void) +{ + cstring_char_t long_pattern_mixed[1025]; + cstring_char_t long_pattern_lower[1025]; + size_t const pattern_len = 1024; + size_t i; + cstring_t cs_mixed; + cstring_t cs_lower; + CSTRING_RC rc; + + for (i = 0; i < pattern_len; ++i) + { + int const m = (int)(i % 52); + + if (m < 26) + { + long_pattern_mixed[i] = (cstring_char_t)(CSTRING_T_('A') + m); + long_pattern_lower[i] = (cstring_char_t)(CSTRING_T_('a') + m); + } + else + { + long_pattern_mixed[i] = (cstring_char_t)(CSTRING_T_('a') + (m - 26)); + long_pattern_lower[i] = (cstring_char_t)(CSTRING_T_('a') + (m - 26)); + } + } + long_pattern_mixed[pattern_len] = 0; + long_pattern_lower[pattern_len] = 0; + + rc = cstring_createLen(&cs_mixed, long_pattern_mixed, pattern_len); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + rc = cstring_createLen(&cs_lower, long_pattern_lower, pattern_len); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + + /* Verify consistency between struct and buffer APIs */ + TEST_INT_EQ(cstring_hash_djb2(&cs_mixed), cstring_hash_djb2_buf(cs_mixed.ptr, cs_mixed.len)); + TEST_INT_EQ(cstring_hash_djb2_case(&cs_mixed), cstring_hash_djb2_buf_case(cs_mixed.ptr, cs_mixed.len)); + TEST_INT_EQ(cstring_hash_fnv1a(&cs_mixed), cstring_hash_fnv1a_buf(cs_mixed.ptr, cs_mixed.len)); + TEST_INT_EQ(cstring_hash_fnv1a_case(&cs_mixed), cstring_hash_fnv1a_buf_case(cs_mixed.ptr, cs_mixed.len)); + + /* Case-insensitive hashes must match */ + TEST_INT_EQ(cstring_hash_djb2_case(&cs_mixed), cstring_hash_djb2_case(&cs_lower)); + TEST_INT_EQ(cstring_hash_fnv1a_case(&cs_mixed), cstring_hash_fnv1a_case(&cs_lower)); + + /* Case-sensitive hashes must not match */ + TEST_INT_NE(cstring_hash_djb2(&cs_mixed), cstring_hash_djb2(&cs_lower)); + TEST_INT_NE(cstring_hash_fnv1a(&cs_mixed), cstring_hash_fnv1a(&cs_lower)); + + cstring_destroy(&cs_mixed); + cstring_destroy(&cs_lower); +} + +static void TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_SLICES(void) +{ + cstring_char_t const text[] = CSTRING_T_("The quick brown Fox jumps over the lazy Dog."); + size_t const total_len = sizeof(text) / sizeof(text[0]) - 1; + cstring_hash_t djb2_quick_slice; + cstring_hash_t djb2_quick_direct; + cstring_hash_t fnv1a_quick_slice; + cstring_hash_t fnv1a_quick_direct; + cstring_t cs; + CSTRING_RC rc; + + /* Slices without constructing cstring_t */ + /* "quick" starts at index 4, length 5 */ + djb2_quick_slice = cstring_hash_djb2_buf(text + 4, 5); + djb2_quick_direct = cstring_hash_djb2_buf(CSTRING_T_("quick"), 5); + TEST_INT_EQ(djb2_quick_direct, djb2_quick_slice); + + fnv1a_quick_slice = cstring_hash_fnv1a_buf(text + 4, 5); + fnv1a_quick_direct = cstring_hash_fnv1a_buf(CSTRING_T_("quick"), 5); + TEST_INT_EQ(fnv1a_quick_direct, fnv1a_quick_slice); + + /* "Fox" starts at index 16, length 3 */ + TEST_INT_EQ(cstring_hash_djb2_buf_case(text + 16, 3), cstring_hash_djb2_buf_case(CSTRING_T_("fox"), 3)); + TEST_INT_EQ(cstring_hash_fnv1a_buf_case(text + 16, 3), cstring_hash_fnv1a_buf_case(CSTRING_T_("fox"), 3)); + TEST_INT_NE(cstring_hash_djb2_buf(text + 16, 3), cstring_hash_djb2_buf(CSTRING_T_("fox"), 3)); + TEST_INT_NE(cstring_hash_fnv1a_buf(text + 16, 3), cstring_hash_fnv1a_buf(CSTRING_T_("fox"), 3)); + + /* Hashing full text via buffer API */ + rc = cstring_createLen(&cs, text, total_len); + TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); + TEST_INT_EQ(cstring_hash_djb2_buf(text, total_len), cstring_hash_djb2(&cs)); + TEST_INT_EQ(cstring_hash_fnv1a_buf(text, total_len), cstring_hash_fnv1a(&cs)); + cstring_destroy(&cs); +} + +static void TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_OCTET_ABOVE_7F(void) +{ + cstring_char_t const hi[1] = { (cstring_char_t)0xFF }; + cstring_char_t const mid[1] = { (cstring_char_t)0x7F }; + +#ifndef CSTRING_USE_WIDE_STRINGS + /* djb2: 5381 * 33 + octet. FNV-1a: one-byte 64-bit vectors. */ + TEST_INT_EQ(177828ULL, cstring_hash_djb2_buf(hi, 1)); + TEST_INT_EQ(0xaf64724c8602eb6eULL, cstring_hash_fnv1a_buf(hi, 1)); + TEST_INT_EQ(177700ULL, cstring_hash_djb2_buf(mid, 1)); + TEST_INT_EQ(0xaf63f24c860211eeULL, cstring_hash_fnv1a_buf(mid, 1)); + + TEST_INT_NE(5381ULL, cstring_hash_djb2_buf(hi, 1)); + TEST_INT_NE(0xcbf29ce484222325ULL, cstring_hash_fnv1a_buf(hi, 1)); + + /* tolower of octets above 0x7F follows the process locale. */ + TEST_INT_NE(cstring_hash_djb2_buf_case(mid, 1), cstring_hash_djb2_buf_case(hi, 1)); + TEST_INT_NE(5381ULL, cstring_hash_djb2_buf_case(hi, 1)); + TEST_INT_NE(cstring_hash_fnv1a_buf_case(mid, 1), cstring_hash_fnv1a_buf_case(hi, 1)); + TEST_INT_NE(0xcbf29ce484222325ULL, cstring_hash_fnv1a_buf_case(hi, 1)); +#else /* ? CSTRING_USE_WIDE_STRINGS */ + /* Distinct code units only; exact octets would freeze truncation. */ + TEST_INT_NE(cstring_hash_djb2_buf(mid, 1), cstring_hash_djb2_buf(hi, 1)); + TEST_INT_NE(cstring_hash_djb2_buf(hi, 0), cstring_hash_djb2_buf(hi, 1)); + TEST_INT_NE(cstring_hash_djb2_buf_case(mid, 1), cstring_hash_djb2_buf_case(hi, 1)); + TEST_INT_NE(cstring_hash_djb2_buf_case(hi, 0), cstring_hash_djb2_buf_case(hi, 1)); + TEST_INT_NE(cstring_hash_fnv1a_buf(mid, 1), cstring_hash_fnv1a_buf(hi, 1)); + TEST_INT_NE(cstring_hash_fnv1a_buf(hi, 0), cstring_hash_fnv1a_buf(hi, 1)); + TEST_INT_NE(cstring_hash_fnv1a_buf_case(mid, 1), cstring_hash_fnv1a_buf_case(hi, 1)); + TEST_INT_NE(cstring_hash_fnv1a_buf_case(hi, 0), cstring_hash_fnv1a_buf_case(hi, 1)); +#endif /* CSTRING_USE_WIDE_STRINGS */ +} + +static void TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_EMBEDDED_NUL(void) +{ + cstring_char_t const a_nul_b[3] = { CSTRING_T_('a'), (cstring_char_t)0, CSTRING_T_('b') }; + cstring_char_t const a_only[1] = { CSTRING_T_('a') }; + cstring_char_t const ab[2] = { CSTRING_T_('a'), CSTRING_T_('b') }; + cstring_char_t const a_nul_c[3] = { CSTRING_T_('a'), (cstring_char_t)0, CSTRING_T_('c') }; + + /* Explicit length, so an interior NUL does not end the slice. */ + TEST_INT_NE(cstring_hash_djb2_buf(a_only, 1), cstring_hash_djb2_buf(a_nul_b, 3)); + TEST_INT_NE(cstring_hash_djb2_buf(ab, 2), cstring_hash_djb2_buf(a_nul_b, 3)); + TEST_INT_NE(cstring_hash_djb2_buf(a_nul_c, 3), cstring_hash_djb2_buf(a_nul_b, 3)); + + TEST_INT_NE(cstring_hash_djb2_buf_case(a_only, 1), cstring_hash_djb2_buf_case(a_nul_b, 3)); + TEST_INT_NE(cstring_hash_djb2_buf_case(ab, 2), cstring_hash_djb2_buf_case(a_nul_b, 3)); + TEST_INT_NE(cstring_hash_djb2_buf_case(a_nul_c, 3), cstring_hash_djb2_buf_case(a_nul_b, 3)); + + TEST_INT_NE(cstring_hash_fnv1a_buf(a_only, 1), cstring_hash_fnv1a_buf(a_nul_b, 3)); + TEST_INT_NE(cstring_hash_fnv1a_buf(ab, 2), cstring_hash_fnv1a_buf(a_nul_b, 3)); + TEST_INT_NE(cstring_hash_fnv1a_buf(a_nul_c, 3), cstring_hash_fnv1a_buf(a_nul_b, 3)); + + TEST_INT_NE(cstring_hash_fnv1a_buf_case(a_only, 1), cstring_hash_fnv1a_buf_case(a_nul_b, 3)); + TEST_INT_NE(cstring_hash_fnv1a_buf_case(ab, 2), cstring_hash_fnv1a_buf_case(a_nul_b, 3)); + TEST_INT_NE(cstring_hash_fnv1a_buf_case(a_nul_c, 3), cstring_hash_fnv1a_buf_case(a_nul_b, 3)); + +#ifndef CSTRING_USE_WIDE_STRINGS + TEST_INT_EQ(193482728ULL, cstring_hash_djb2_buf(a_nul_b, 3)); + TEST_INT_EQ(0xe5d29919042666b2ULL, cstring_hash_fnv1a_buf(a_nul_b, 3)); +#endif /* CSTRING_USE_WIDE_STRINGS */ +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/hash/entry.cpp b/test/unit/hash/entry.cpp deleted file mode 100644 index de224db..0000000 --- a/test/unit/hash/entry.cpp +++ /dev/null @@ -1,402 +0,0 @@ -/* ///////////////////////////////////////////////////////////////////////// - * File: test/unit/hash/entry.cpp - * - * Purpose: Unit-tests for cstring hashing extensions. - * - * Created: 5th September 2026 - * Updated: 5th September 2026 - * - * ////////////////////////////////////////////////////////////////////// */ - - -/* ///////////////////////////////////////////////////////////////////////// - * test component header file include(s) - */ - -#include - -/* ///////////////////////////////////////////////////////////////////////// - * includes - */ - -/* xTests header files */ -#include - -/* STLSoft header files */ -#include - -/* Standard C header files */ -#include -#include -#include - - -/* ///////////////////////////////////////////////////////////////////////// - * character encoding - */ - -#ifdef CSTRING_USE_WIDE_STRINGS -# define CSTRING_T_(x) L ## x -#else /* ? CSTRING_USE_WIDE_STRINGS */ -# define CSTRING_T_(x) x -#endif /* CSTRING_USE_WIDE_STRINGS */ - - -/* ///////////////////////////////////////////////////////////////////////// - * forward declarations - */ - -namespace -{ - - static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_NULL_AND_EMPTY(void); - static void TEST_cstring_hash_fnv1a_KNOWN_VECTORS(void); - static void TEST_cstring_hash_djb2_KNOWN_VECTORS(void); - static void TEST_cstring_hash_djb2_ci_AND_cstring_hash_fnv1a_ci(void); - static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_SINGLE_CHARACTER(void); - static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_LONG_STRING(void); - static void TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_SLICES(void); - static void TEST_hash_djb2_AND_hash_djb2_ci_AND_hash_fnv1a_AND_hash_fnv1a_ci(void); -} // anonymous namespace - - -/* ///////////////////////////////////////////////////////////////////////// - * main - */ - -int main(int argc, char* argv[]) -{ - int retCode = EXIT_SUCCESS; - int verbosity = 2; - - XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); - - if (XTESTS_START_RUNNER("test.unit.cstring.hash", verbosity)) - { - XTESTS_RUN_CASE(TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_NULL_AND_EMPTY); - XTESTS_RUN_CASE(TEST_cstring_hash_fnv1a_KNOWN_VECTORS); - XTESTS_RUN_CASE(TEST_cstring_hash_djb2_KNOWN_VECTORS); - XTESTS_RUN_CASE(TEST_cstring_hash_djb2_ci_AND_cstring_hash_fnv1a_ci); - XTESTS_RUN_CASE(TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_SINGLE_CHARACTER); - XTESTS_RUN_CASE(TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_LONG_STRING); - XTESTS_RUN_CASE(TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_SLICES); - XTESTS_RUN_CASE(TEST_hash_djb2_AND_hash_djb2_ci_AND_hash_fnv1a_AND_hash_fnv1a_ci); - - XTESTS_PRINT_RESULTS(); - - XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); - } - - return retCode; -} - - -/* ///////////////////////////////////////////////////////////////////////// - * test function implementations - */ - -namespace -{ - -static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_NULL_AND_EMPTY(void) -{ - struct cstring_t const* pcs_null = NULL; - cstring_t null_cs = { 0, NULL, 0, 0 }; - cstring_t default_cs = cstring_t_DEFAULT; - cstring_t created_empty; - - CSTRING_RC rc = cstring_create(&created_empty, CSTRING_T_("")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - - /* djb2: initial seed is 5381 */ - TEST_INT_EQ(5381ULL, cstring_hash_djb2(pcs_null)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2_ci(pcs_null)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2(&null_cs)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2_ci(&null_cs)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2(&default_cs)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2_ci(&default_cs)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2(&created_empty)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2_ci(&created_empty)); - - TEST_INT_EQ(5381ULL, cstring_hash_djb2_len(NULL, 0)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2_len_ci(NULL, 0)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2_len(NULL, 10)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2_len_ci(NULL, 10)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2_len(CSTRING_T_(""), 0)); - TEST_INT_EQ(5381ULL, cstring_hash_djb2_len_ci(CSTRING_T_(""), 0)); - - TEST_INT_EQ(5381ULL, hash_djb2(static_cast(NULL))); - TEST_INT_EQ(5381ULL, hash_djb2_ci(static_cast(NULL))); - TEST_INT_EQ(5381ULL, hash_djb2(default_cs)); - TEST_INT_EQ(5381ULL, hash_djb2_ci(default_cs)); - TEST_INT_EQ(5381ULL, hash_djb2(NULL, 0)); - TEST_INT_EQ(5381ULL, hash_djb2_ci(NULL, 0)); - - /* FNV-1a: offset basis is 0xcbf29ce484222325ULL */ - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a(pcs_null)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_ci(pcs_null)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a(&null_cs)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_ci(&null_cs)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a(&default_cs)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_ci(&default_cs)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a(&created_empty)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_ci(&created_empty)); - - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_len(NULL, 0)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_len_ci(NULL, 0)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_len(NULL, 10)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_len_ci(NULL, 10)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_len(CSTRING_T_(""), 0)); - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_len_ci(CSTRING_T_(""), 0)); - - TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a(static_cast(NULL))); - TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a_ci(static_cast(NULL))); - TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a(default_cs)); - TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a_ci(default_cs)); - TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a(NULL, 0)); - TEST_INT_EQ(0xcbf29ce484222325ULL, hash_fnv1a_ci(NULL, 0)); - - cstring_destroy(&created_empty); -} - -static void TEST_cstring_hash_fnv1a_KNOWN_VECTORS(void) -{ - /* Known FNV-1a 64-bit test vectors: - * "" -> 0xcbf29ce484222325ULL - * "a" -> 0xaf63dc4c8601ec8cULL - * "foobar" -> 0x85944171f73967e8ULL - */ - TEST_INT_EQ(0xcbf29ce484222325ULL, cstring_hash_fnv1a_len(CSTRING_T_(""), 0)); - TEST_INT_EQ(0xaf63dc4c8601ec8cULL, cstring_hash_fnv1a_len(CSTRING_T_("a"), 1)); - TEST_INT_EQ(0x85944171f73967e8ULL, cstring_hash_fnv1a_len(CSTRING_T_("foobar"), 6)); - - cstring_t cs_a; - CSTRING_RC rc = cstring_create(&cs_a, CSTRING_T_("a")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - TEST_INT_EQ(0xaf63dc4c8601ec8cULL, cstring_hash_fnv1a(&cs_a)); - TEST_INT_EQ(0xaf63dc4c8601ec8cULL, hash_fnv1a(cs_a)); - cstring_destroy(&cs_a); - - cstring_t cs_foobar; - rc = cstring_create(&cs_foobar, CSTRING_T_("foobar")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - TEST_INT_EQ(0x85944171f73967e8ULL, cstring_hash_fnv1a(&cs_foobar)); - TEST_INT_EQ(0x85944171f73967e8ULL, hash_fnv1a(cs_foobar)); - cstring_destroy(&cs_foobar); -} - -static void TEST_cstring_hash_djb2_KNOWN_VECTORS(void) -{ - /* Known djb2 test vectors: - * "" -> 5381ULL - * "a" -> 5381 * 33 + 97 = 177670ULL (0x2b606ULL) - * "foobar" -> 6953516687550ULL (0x652fde460beULL) - */ - TEST_INT_EQ(5381ULL, cstring_hash_djb2_len(CSTRING_T_(""), 0)); - TEST_INT_EQ(177670ULL, cstring_hash_djb2_len(CSTRING_T_("a"), 1)); - TEST_INT_EQ(6953516687550ULL, cstring_hash_djb2_len(CSTRING_T_("foobar"), 6)); - - cstring_t cs_a; - CSTRING_RC rc = cstring_create(&cs_a, CSTRING_T_("a")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - TEST_INT_EQ(177670ULL, cstring_hash_djb2(&cs_a)); - TEST_INT_EQ(177670ULL, hash_djb2(cs_a)); - cstring_destroy(&cs_a); - - cstring_t cs_foobar; - rc = cstring_create(&cs_foobar, CSTRING_T_("foobar")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - TEST_INT_EQ(6953516687550ULL, cstring_hash_djb2(&cs_foobar)); - TEST_INT_EQ(6953516687550ULL, hash_djb2(cs_foobar)); - cstring_destroy(&cs_foobar); -} - -static void TEST_cstring_hash_djb2_ci_AND_cstring_hash_fnv1a_ci(void) -{ - /* Buffer checks */ - uint64_t djb2_ci_base = cstring_hash_djb2_len_ci(CSTRING_T_("Test"), 4); - TEST_INT_EQ(djb2_ci_base, cstring_hash_djb2_len_ci(CSTRING_T_("tEst"), 4)); - TEST_INT_EQ(djb2_ci_base, cstring_hash_djb2_len_ci(CSTRING_T_("TEST"), 4)); - TEST_INT_EQ(djb2_ci_base, cstring_hash_djb2_len_ci(CSTRING_T_("test"), 4)); - TEST_INT_EQ(djb2_ci_base, cstring_hash_djb2_len_ci(CSTRING_T_("teSt"), 4)); - - uint64_t fnv1a_ci_base = cstring_hash_fnv1a_len_ci(CSTRING_T_("Test"), 4); - TEST_INT_EQ(fnv1a_ci_base, cstring_hash_fnv1a_len_ci(CSTRING_T_("tEst"), 4)); - TEST_INT_EQ(fnv1a_ci_base, cstring_hash_fnv1a_len_ci(CSTRING_T_("TEST"), 4)); - TEST_INT_EQ(fnv1a_ci_base, cstring_hash_fnv1a_len_ci(CSTRING_T_("test"), 4)); - TEST_INT_EQ(fnv1a_ci_base, cstring_hash_fnv1a_len_ci(CSTRING_T_("teSt"), 4)); - - /* Case-sensitive inequality */ - TEST_INT_NE(cstring_hash_djb2_len(CSTRING_T_("Test"), 4), cstring_hash_djb2_len(CSTRING_T_("tEst"), 4)); - TEST_INT_NE(cstring_hash_fnv1a_len(CSTRING_T_("Test"), 4), cstring_hash_fnv1a_len(CSTRING_T_("tEst"), 4)); - - /* Instance checks */ - cstring_t cs1; - cstring_t cs2; - cstring_t cs3; - cstring_t cs4; - - CSTRING_RC rc; - rc = cstring_create(&cs1, CSTRING_T_("Test")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - rc = cstring_create(&cs2, CSTRING_T_("tEst")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - rc = cstring_create(&cs3, CSTRING_T_("TEST")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - rc = cstring_create(&cs4, CSTRING_T_("test")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - - TEST_INT_EQ(cstring_hash_djb2_ci(&cs1), cstring_hash_djb2_ci(&cs2)); - TEST_INT_EQ(cstring_hash_djb2_ci(&cs1), cstring_hash_djb2_ci(&cs3)); - TEST_INT_EQ(cstring_hash_djb2_ci(&cs1), cstring_hash_djb2_ci(&cs4)); - - TEST_INT_EQ(cstring_hash_fnv1a_ci(&cs1), cstring_hash_fnv1a_ci(&cs2)); - TEST_INT_EQ(cstring_hash_fnv1a_ci(&cs1), cstring_hash_fnv1a_ci(&cs3)); - TEST_INT_EQ(cstring_hash_fnv1a_ci(&cs1), cstring_hash_fnv1a_ci(&cs4)); - - TEST_INT_NE(cstring_hash_djb2(&cs1), cstring_hash_djb2(&cs2)); - TEST_INT_NE(cstring_hash_fnv1a(&cs1), cstring_hash_fnv1a(&cs2)); - - cstring_destroy(&cs1); - cstring_destroy(&cs2); - cstring_destroy(&cs3); - cstring_destroy(&cs4); -} - -static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_SINGLE_CHARACTER(void) -{ - /* Letters */ - TEST_INT_EQ(cstring_hash_djb2_len_ci(CSTRING_T_("a"), 1), cstring_hash_djb2_len_ci(CSTRING_T_("A"), 1)); - TEST_INT_EQ(cstring_hash_fnv1a_len_ci(CSTRING_T_("a"), 1), cstring_hash_fnv1a_len_ci(CSTRING_T_("A"), 1)); - TEST_INT_NE(cstring_hash_djb2_len(CSTRING_T_("a"), 1), cstring_hash_djb2_len(CSTRING_T_("A"), 1)); - TEST_INT_NE(cstring_hash_fnv1a_len(CSTRING_T_("a"), 1), cstring_hash_fnv1a_len(CSTRING_T_("A"), 1)); - - TEST_INT_EQ(cstring_hash_djb2_len_ci(CSTRING_T_("z"), 1), cstring_hash_djb2_len_ci(CSTRING_T_("Z"), 1)); - TEST_INT_EQ(cstring_hash_fnv1a_len_ci(CSTRING_T_("z"), 1), cstring_hash_fnv1a_len_ci(CSTRING_T_("Z"), 1)); - TEST_INT_NE(cstring_hash_djb2_len(CSTRING_T_("z"), 1), cstring_hash_djb2_len(CSTRING_T_("Z"), 1)); - TEST_INT_NE(cstring_hash_fnv1a_len(CSTRING_T_("z"), 1), cstring_hash_fnv1a_len(CSTRING_T_("Z"), 1)); - - /* Non-letters have identical case-sensitive and case-insensitive hashes */ - TEST_INT_EQ(cstring_hash_djb2_len(CSTRING_T_("0"), 1), cstring_hash_djb2_len_ci(CSTRING_T_("0"), 1)); - TEST_INT_EQ(cstring_hash_fnv1a_len(CSTRING_T_("0"), 1), cstring_hash_fnv1a_len_ci(CSTRING_T_("0"), 1)); - - TEST_INT_EQ(cstring_hash_djb2_len(CSTRING_T_("!"), 1), cstring_hash_djb2_len_ci(CSTRING_T_("!"), 1)); - TEST_INT_EQ(cstring_hash_fnv1a_len(CSTRING_T_("!"), 1), cstring_hash_fnv1a_len_ci(CSTRING_T_("!"), 1)); - - TEST_INT_EQ(cstring_hash_djb2_len(CSTRING_T_(" "), 1), cstring_hash_djb2_len_ci(CSTRING_T_(" "), 1)); - TEST_INT_EQ(cstring_hash_fnv1a_len(CSTRING_T_(" "), 1), cstring_hash_fnv1a_len_ci(CSTRING_T_(" "), 1)); -} - -static void TEST_cstring_hash_djb2_AND_cstring_hash_fnv1a_LONG_STRING(void) -{ - cstring_char_t long_pattern_mixed[1025]; - cstring_char_t long_pattern_lower[1025]; - size_t const pattern_len = 1024; - size_t i; - - for (i = 0; i < pattern_len; ++i) - { - int const m = (int)(i % 52); - - if (m < 26) - { - long_pattern_mixed[i] = (cstring_char_t)(CSTRING_T_('A') + m); - long_pattern_lower[i] = (cstring_char_t)(CSTRING_T_('a') + m); - } - else - { - long_pattern_mixed[i] = (cstring_char_t)(CSTRING_T_('a') + (m - 26)); - long_pattern_lower[i] = (cstring_char_t)(CSTRING_T_('a') + (m - 26)); - } - } - long_pattern_mixed[pattern_len] = 0; - long_pattern_lower[pattern_len] = 0; - - cstring_t cs_mixed; - cstring_t cs_lower; - - CSTRING_RC rc; - rc = cstring_createLen(&cs_mixed, long_pattern_mixed, pattern_len); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - rc = cstring_createLen(&cs_lower, long_pattern_lower, pattern_len); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - - /* Verify consistency between struct and buffer APIs */ - TEST_INT_EQ(cstring_hash_djb2(&cs_mixed), cstring_hash_djb2_len(cs_mixed.ptr, cs_mixed.len)); - TEST_INT_EQ(cstring_hash_djb2_ci(&cs_mixed), cstring_hash_djb2_len_ci(cs_mixed.ptr, cs_mixed.len)); - TEST_INT_EQ(cstring_hash_fnv1a(&cs_mixed), cstring_hash_fnv1a_len(cs_mixed.ptr, cs_mixed.len)); - TEST_INT_EQ(cstring_hash_fnv1a_ci(&cs_mixed), cstring_hash_fnv1a_len_ci(cs_mixed.ptr, cs_mixed.len)); - - /* Case-insensitive hashes must match */ - TEST_INT_EQ(cstring_hash_djb2_ci(&cs_mixed), cstring_hash_djb2_ci(&cs_lower)); - TEST_INT_EQ(cstring_hash_fnv1a_ci(&cs_mixed), cstring_hash_fnv1a_ci(&cs_lower)); - - /* Case-sensitive hashes must not match */ - TEST_INT_NE(cstring_hash_djb2(&cs_mixed), cstring_hash_djb2(&cs_lower)); - TEST_INT_NE(cstring_hash_fnv1a(&cs_mixed), cstring_hash_fnv1a(&cs_lower)); - - cstring_destroy(&cs_mixed); - cstring_destroy(&cs_lower); -} - -static void TEST_cstring_hash_djb2_len_AND_cstring_hash_fnv1a_len_SLICES(void) -{ - cstring_char_t const text[] = CSTRING_T_("The quick brown Fox jumps over the lazy Dog."); - size_t const total_len = sizeof(text) / sizeof(text[0]) - 1; - - /* Slices without constructing cstring_t */ - /* "quick" starts at index 4, length 5 */ - uint64_t djb2_quick_slice = cstring_hash_djb2_len(text + 4, 5); - uint64_t djb2_quick_direct = cstring_hash_djb2_len(CSTRING_T_("quick"), 5); - TEST_INT_EQ(djb2_quick_direct, djb2_quick_slice); - - uint64_t fnv1a_quick_slice = cstring_hash_fnv1a_len(text + 4, 5); - uint64_t fnv1a_quick_direct = cstring_hash_fnv1a_len(CSTRING_T_("quick"), 5); - TEST_INT_EQ(fnv1a_quick_direct, fnv1a_quick_slice); - - /* "Fox" starts at index 16, length 3 */ - TEST_INT_EQ(cstring_hash_djb2_len_ci(text + 16, 3), cstring_hash_djb2_len_ci(CSTRING_T_("fox"), 3)); - TEST_INT_EQ(cstring_hash_fnv1a_len_ci(text + 16, 3), cstring_hash_fnv1a_len_ci(CSTRING_T_("fox"), 3)); - TEST_INT_NE(cstring_hash_djb2_len(text + 16, 3), cstring_hash_djb2_len(CSTRING_T_("fox"), 3)); - TEST_INT_NE(cstring_hash_fnv1a_len(text + 16, 3), cstring_hash_fnv1a_len(CSTRING_T_("fox"), 3)); - - /* Hashing full text via buffer API */ - cstring_t cs; - CSTRING_RC rc = cstring_createLen(&cs, text, total_len); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - TEST_INT_EQ(cstring_hash_djb2_len(text, total_len), cstring_hash_djb2(&cs)); - TEST_INT_EQ(cstring_hash_fnv1a_len(text, total_len), cstring_hash_fnv1a(&cs)); - cstring_destroy(&cs); -} - -static void TEST_hash_djb2_AND_hash_djb2_ci_AND_hash_fnv1a_AND_hash_fnv1a_ci(void) -{ - cstring_t cs; - CSTRING_RC rc = cstring_create(&cs, CSTRING_T_("Hello World")); - TEST_ENUM_EQ(CSTRING_RC_SUCCESS, rc); - - /* Overload by reference */ - TEST_INT_EQ(cstring_hash_djb2(&cs), hash_djb2(cs)); - TEST_INT_EQ(cstring_hash_djb2_ci(&cs), hash_djb2_ci(cs)); - TEST_INT_EQ(cstring_hash_fnv1a(&cs), hash_fnv1a(cs)); - TEST_INT_EQ(cstring_hash_fnv1a_ci(&cs), hash_fnv1a_ci(cs)); - - /* Overload by pointer */ - TEST_INT_EQ(cstring_hash_djb2(&cs), hash_djb2(&cs)); - TEST_INT_EQ(cstring_hash_djb2_ci(&cs), hash_djb2_ci(&cs)); - TEST_INT_EQ(cstring_hash_fnv1a(&cs), hash_fnv1a(&cs)); - TEST_INT_EQ(cstring_hash_fnv1a_ci(&cs), hash_fnv1a_ci(&cs)); - - /* Overload by slice/buffer */ - TEST_INT_EQ(cstring_hash_djb2_len(cs.ptr, cs.len), hash_djb2(cs.ptr, cs.len)); - TEST_INT_EQ(cstring_hash_djb2_len_ci(cs.ptr, cs.len), hash_djb2_ci(cs.ptr, cs.len)); - TEST_INT_EQ(cstring_hash_fnv1a_len(cs.ptr, cs.len), hash_fnv1a(cs.ptr, cs.len)); - TEST_INT_EQ(cstring_hash_fnv1a_len_ci(cs.ptr, cs.len), hash_fnv1a_ci(cs.ptr, cs.len)); - - cstring_destroy(&cs); -} -} // anonymous namespace - - -/* ///////////////////////////// end of file //////////////////////////// */ -