You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e87dd41
Browse filesBrowse the repository at this point in the historyBrowse files
* chore(misc): language discrimination; CI branch(es)
* chore(misc): ensuring `\file` designators are correct
* chore(mist): removed unused `CSTRING_VECTOR_ASSERT()`
* chore(misc): tidying
* fix(cstring): discriminate cstring_hash_t and use it for hashing
Gate <stdint.h> on C99, on C++ with that header or C++11, and on MSVC 7.1
or later, and typedef cstring_hash_t to uint64_t when it is included; use
cstring_hash_t for the djb2 and FNV-1a API and for the hash unit tests.
* chore(performance tests): prefer `uint64_t` to `std::uint64_t`
* test(cstring): exercise the hashing API from a C unit test
Move the eight C hashing functions into **test.unit.hash** (`entry.c`) so
the suite builds when `NO_CSTRING_CPP_API` is on. Keep the C++ shim checks
in **test.unit.hash.cxx**, which stays behind that option.
* test(cstring): lock high-byte and embedded-NUL hash results
Cover octet 0xFF and an interior NUL in test.unit.hash. Exact narrow
vectors stay off the wide build so a later wchar_t fix is not frozen.
* feat(cstring): publish the djb2 and FNV-1a basis macros
Add CSTRING_HASH_DJB2_SEED, CSTRING_HASH_FNV1A_OFFSET, and
CSTRING_HASH_FNV1A_PRIME beside cstring_hash_t, and use them as the only
copies of those constants in the hash implementation. Cite Yigit's djb2
page and the Fowler, Noll, and Vo notes and RFC 9923, and lock each macro
to its historic literal in the C unit test.
* fix
* refactor(cstring): rename the case-folded hash suffix to _case
Rename the case-folded hash functions from the `_ci` suffix to `_case`
(`cstring_hash_djb2_case`, `cstring_hash_djb2_len_case`, and the FNV-1a
twins), including the C++ shims and the unit tests.
* refactor(cstring): rename the counted hash suffix from _len to _buf
Rename the pointer-and-length hash functions from `_len` to `_buf`
(`cstring_hash_djb2_buf`, `cstring_hash_djb2_buf_case`, and the FNV-1a
twins), including the C++ shims and the unit tests.
* refactor(cstring): .DEF file renames of hash functions
* feat(cstring): add always-available multibyte and wide hash API
Move the hash declarations into hash.h and the stdint.h discrimination into
common.h. cstring.h includes both. Add mbs, wcs, mbuf, and wbuf entry
points, including the case forms, for djb2 and FNV-1a. Each code unit
contributes its low 8 bits, so ASCII text has one hash in both encodings.
C++ shims overload on char const*, wchar_t const*, and both buffer forms.
* docs(cstring): document hash groups, contract, and consumers
- Document the hash contract, the djb2 and FNV-1a steps, and the published
vectors in hash.h, README.md, and doc/mainpage.md;
- Define group__cstring_api__hashing__djb2 and
group__cstring_api__hashing__fnv1a, and keep the published references
on those groups;
- Place the C++ hash shims in namespace cstring, and import them in
test.unit.hash.cxx;
- Name the projects that call or link cstring, including the sistools
programs;
- Parenthesise the hash basis macros and note the FNV-1a prime in decimal;
- Record the header-split and auto-buffer provenance items in TODO.md;
- Spell NUL in the hash and status-code comments;
* Added multibyte and wide hash entry points `cstring_hash_djb2_mbs()`, `cstring_hash_djb2_wcs()`, `cstring_hash_djb2_mbuf()`, `cstring_hash_djb2_wbuf()`, and the `_case` forms, and the same set for `cstring_hash_fnv1a()`;
8
9
* Added `cstring_hash_t` typedef (`uint64_t`);
9
-
* Added C++ hash access shims for `cstring_t` (reference and pointer) and buffer/slice forms;
10
+
* Added **common.h** for shared `<stdint.h>` discrimination, and **hash.h** for the hash API, included from **cstring.h**;
11
+
* Added C++ hash access shims `hash_djb2()`, `hash_djb2_case()`, `hash_fnv1a()`, and `hash_fnv1a_case()` for `cstring_t` (reference and pointer), `char const*`, `wchar_t const*`, and both buffer forms;
10
12
* Added unit test **test.unit.hash** (C hashing API, built with and without the C++ API) and **test.unit.hash.cxx** (C++ hash shims);
11
13
* Published `CSTRING_HASH_DJB2_SEED`, `CSTRING_HASH_FNV1A_OFFSET`, and `CSTRING_HASH_FNV1A_PRIME` as the djb2 and FNV-1a basis constants;
12
14
* Documented `CSTRING_HASH_DJB2_SEED`, `CSTRING_HASH_FNV1A_OFFSET`, and `CSTRING_HASH_FNV1A_PRIME` with references to the published djb2 and FNV-1a algorithms;
15
+
* Documented the hash contract (forms, low octet, case fold, published vectors) and grouped the algorithms as `group__cstring_api__hashing__djb2` and `group__cstring_api__hashing__fnv1a`;
@@ -215,16 +217,48 @@ Defined in **cstring/cstring.h**:
215
217
216
218
#### Hashing functions
217
219
218
-
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`:
220
+
Declared in **cstring/hash.h**, which **cstring.h** includes. Both algorithms return `cstring_hash_t` (`uint64_t`). Multibyte and wide entry points exist in every build, whatever ambient `cstring_char_t` is. Each code unit contributes its low 8 bits, so ASCII text has one hash in both encodings. A wide code unit of value `0x161` hashes as the octet `0x61` (`'a'`). A `NULL` pointer, or a zero length, yields that algorithm's empty-input value and does not read the pointer.
219
221
220
-
* `cstring_hash_djb2()` — calculates a 64-bit djb2 hash of a `cstring_t` instance;
221
-
* `cstring_hash_djb2_ci()` — calculates a case-insensitive 64-bit djb2 hash of a `cstring_t` instance;
222
-
* `cstring_hash_djb2_len()` — calculates a 64-bit djb2 hash of a character buffer or slice;
223
-
* `cstring_hash_djb2_len_ci()` — calculates a case-insensitive 64-bit djb2 hash of a character buffer or slice;
224
-
* `cstring_hash_fnv1a()` — calculates a 64-bit FNV-1a hash of a `cstring_t` instance;
225
-
* `cstring_hash_fnv1a_ci()` — calculates a case-insensitive 64-bit FNV-1a hash of a `cstring_t` instance;
226
-
* `cstring_hash_fnv1a_len()` — calculates a 64-bit FNV-1a hash of a character buffer or slice;
227
-
* `cstring_hash_fnv1a_len_ci()` — calculates a case-insensitive 64-bit FNV-1a hash of a character buffer or slice;
222
+
| Suffix | Input | What is hashed |
223
+
| ------ | ----- | -------------- |
224
+
| (none) | `cstring_t const*` | `ptr` for `len` code units, including embedded NULs |
225
+
| `_mbs` | `char const*` | stops at the first NUL |
226
+
| `_wcs` | `wchar_t const*` | stops at the first NUL |
`_case` is the last suffix of each name (`cstring_hash_djb2_mbs_case()`, `cstring_hash_fnv1a_wbuf_case()`, and so on). Case folding uses `tolower` or `towlower`, which follow the process locale, and then the low 8 bits.
232
+
233
+
Names follow `cstring_hash_<algorithm><suffix>`, for example `cstring_hash_djb2()`, `cstring_hash_djb2_mbuf()`, and `cstring_hash_fnv1a_wbuf_case()`.
234
+
235
+
236
+
##### djb2
237
+
238
+
The hash starts at `CSTRING_HASH_DJB2_SEED` (`5381`). For each octet `b` the step is `hash = ((hash << 5) + hash) + b`, which is `hash * 33 + b`. Daniel J. Bernstein's djb2, as published by Ozan Yigit.
239
+
240
+
| Input | Hash |
241
+
| ----- | ---- |
242
+
| empty, or `NULL` | `5381` |
243
+
| `"a"` | `177670` |
244
+
| `"foobar"` | `6953516687550` |
245
+
| `{ 'a', 0, 'b' }` length 3 | `193482728` |
246
+
| octet `0xFF` | `177828` |
247
+
248
+
The length-3 buffer differs from `"ab"`, because the embedded NUL is hashed.
249
+
250
+
251
+
##### FNV-1a
252
+
253
+
The hash starts at `CSTRING_HASH_FNV1A_OFFSET` (`0xcbf29ce484222325`). For each octet `b` the step is `hash ^= b` and then `hash *= CSTRING_HASH_FNV1A_PRIME` (`0x100000001b3`). Fowler, Noll, and Vo FNV-1a, 64-bit.
@@ -244,7 +278,7 @@ Defined in **cstring/cstring.vector.h**:
244
278
245
279
When included in C++ compilation units, **cstring/cstring.h** provides inline access shims:
246
280
* **String access shims** — `c_str_data()`, `c_str_len()`, and `c_str_ptr()`, allowing `cstring_t` instances to be used directly with **STLSoft** and generic C++ templates;
247
-
* **Hash access shims** — `hash_djb2()`, `hash_djb2_ci()`, `hash_fnv1a()`, and `hash_fnv1a_ci()`, overloaded for `struct cstring_t const&`, `struct cstring_t const*`, and slice / buffer forms `(cstring_char_t const* s, size_t cch)`;
281
+
* **Hash access shims** — `cstring::hash_djb2()`, `cstring::hash_djb2_case()`, `cstring::hash_fnv1a()`, and `cstring::hash_fnv1a_case()`, overloaded for `struct cstring_t const&`, `struct cstring_t const*`, `char const*`, `wchar_t const*`, and the buffer forms `(char const* s, size_t cch)` and `(wchar_t const* s, size_t cch)`. A `NULL` argument must be cast, because `char const*` and `wchar_t const*` are both viable;
248
282
249
283
250
284
## Examples
@@ -299,11 +333,15 @@ When supplying `'--no-shwild'` — sets `NO_SHWILD=ON` — **shwild** is not rec
299
333
300
334
### Related projects
301
335
302
-
Projects in which **cstring** is used include:
336
+
Projects that call the **cstring** API, or that require the **CMake** package `cstring`:
| [**errni**](https://github.com/sistools/errni) | Builds each result line and writes it with `cstring_writeline()` |
341
+
| [**lnunique**](https://github.com/sistools/lnunique) | Requires `cstring` 4.0 and links `cstring::core` for line strings |
342
+
| [**rstrip**](https://github.com/sistools/rstrip) | Accumulates each output line and writes it with `cstring_write()` |
343
+
| [**shwild.fnmatch**](https://github.com/synesissoftware/shwild.fnmatch) | Holds patterns and subject strings as `cstring_t` |
344
+
| [**STLSoft**](https://github.com/synesissoftware/STLSoft) | Optional; the C unit test `output_debug_line.C` uses `cstring_t` when the package is found |
0 commit comments