Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 66acbaad9e | |||
| 180292289d | |||
| 68640dc5e2 | |||
| 20e890964f | |||
| c215486442 | |||
| 9881c0ac9a | |||
| 17be4841e6 | |||
| 421728c137 | |||
| b014ffa3b1 | |||
| 8da18774f0 | |||
| ac5baef3b8 | |||
| e90229db7a | |||
| 4a92f55f17 | |||
| 3c81feedbb | |||
| 9029e21a4f | |||
| 605c1ddfae | |||
| f73a870a34 | |||
| 8b3b1816b3 | |||
| f46c3ab38a | |||
| 9226891bb9 | |||
| 6fdda743fb | |||
| 575e0a52b1 | |||
| 5df1a105c7 | |||
| 34a1b2c1db | |||
| f3a8045ecc | |||
| 6a3326e9a5 | |||
| 222eb006e6 | |||
| 5e67c596b9 | |||
| 9055c5c825 | |||
| c83f9333de | |||
| 07e0034783 | |||
| e015dfceda | |||
| 60467d56b9 | |||
| 2e943affb7 | |||
| aa48942d91 | |||
| 5ae4d7d6d1 | |||
| 900c16415b | |||
| bca2e720ad | |||
| 850f709a10 | |||
| 55ff77c4ea |
@@ -10,5 +10,6 @@ test.*
|
|||||||
compile_commands.json
|
compile_commands.json
|
||||||
libwapp-build
|
libwapp-build
|
||||||
dist
|
dist
|
||||||
|
scratchpad
|
||||||
*.vs
|
*.vs
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|||||||
@@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2.5.0] - 2026-09-24
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `wpMiscUtilsRotl64` utility
|
||||||
|
- `WpHasher` interface
|
||||||
|
- `wpCustomHasher` constructor for custom hasher with user-defined context
|
||||||
|
- `wpHasherGetHash128` and `wpHasherGetHash64` utilities
|
||||||
|
- `wpX64Mur3Hasher` and `wpX64Mur3HasherWithSeed` constructors for the hasher interface
|
||||||
|
- `wpX64Mur3GetHash128` implementation for the x64 128-bit variant of the MurmurHash3 algorithm
|
||||||
|
- `wpSip24Hasher`, `wpSip48Hasher`, `wpSip24HasherWithKey` and `wpSip48HasherWithKey` constructors for the hasher interface
|
||||||
|
- `wpSipGetHash128` implementation for the 128 variant of siphash
|
||||||
|
- `wpHashSet`, `wpHashSetCustomHasher`, `wpHashSetAlloc` and `wpHashSetCustomHasherAlloc` constructors
|
||||||
|
- `wpHashSetFind`, `wpHashSetInsertCapped`, `wpHashSetInsertAlloc`, `wpHashSetRemove`, `wpHashSetItems`, `wpHashSetCapacity`, `wpHashSetCount`, `wpHashSetItemSize`, `wpHashSetClear` and `wpHashSetDealloc` utilities
|
||||||
|
- `wpHashMap`, `wpHashMapCustomHasher`, `wpHashMapAlloc` and `wpHashMapCustomHasherAlloc` constructors
|
||||||
|
- `wpHashMapKeys`, `wpHashMapValues`, `wpHashMapCapacity`, `wpHashMapCount`, `wpHashMapKeySize`, `wpHashMapValueSize`, `wpHashMapFind`, `wpHashMapInsertCapped`, `wpHashMapInsertOrUpdateCapped`, `wpHashMapUpdate`, `wpHashMapInsertAlloc`, `wpHashMapInsertOrUpdateAlloc`, `wpHashMapRemove`, `wpHashMapClear` and `wpHashMapDealloc` utilities
|
||||||
|
- `wpU8Const`, `wpU16Const`, `wpU32Const`, `wpU64Const`, `wpI8Const`, `wpI16Const`, `wpI32Const`, and `wpI64Const` aliases
|
||||||
|
- `wpPrngXorshiftInitWithSeed` to allow for user control with PRNG
|
||||||
|
- `wpPrngXorshift256InRange`, `wpPrngXorshift256ssInRange`, `wpPrngXorshift256pInRange`, `wpPrngXorshift256Choice`, `wpPrngXorshift256ssChoice` and `wpPrngXorshift256pChoice` utilities
|
||||||
|
- `WpSplitmix64State`
|
||||||
|
- `wpPrngSplitmix64Init`, `wpPrngSplitmix64InitWithSeed`, `wpPrngSplitmix64`, `wpPrngSplitmix64InRange`, `wpPrngSplitmix64Choice`
|
||||||
|
- `wpStr8Clear`
|
||||||
|
- `wpArrayZero` to zero all elements in an array without setting the count to 0
|
||||||
|
- `wpArrayRemoveSwapEnd` to remove an array element using its index and swap the last element in
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Switched to using `wpMiscUtilsRotl64` in `xorshift`
|
||||||
|
- Remove all uses of names starting with underscore
|
||||||
|
- Ensure `wpArrayClear` memsets members to 0
|
||||||
|
- Removed '%' from `WP_STR8_SPEC`
|
||||||
|
|
||||||
## [2.4.0] - 2026-08-30
|
## [2.4.0] - 2026-08-30
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# Hash Tables References
|
||||||
|
|
||||||
|
## SwissTable
|
||||||
|
|
||||||
|
- [Designing a Fast, Efficient, Cache-friendly Hash Table, Step by Step](https://www.youtube.com/watch?v=ncHmEUmJZf4)
|
||||||
|
- [Abseil blog announcement](https://abseil.io/blog/20180927-swisstables)
|
||||||
|
- [Abseil design notes](https://abseil.io/about/design/swisstables)
|
||||||
|
- [Faultlore hashbrown-TLDR](https://faultlore.com/blah/hashbrown-tldr)
|
||||||
|
- [hashbrown source](https://github.com/rust-lang/hashbrown/tree/master/src/raw)
|
||||||
|
- [Faster Go maps with Swiss Tables](https://go.dev/blog/swisstable)
|
||||||
|
|
||||||
|
### 64-bit hash from 128-bit hash
|
||||||
|
MurmurHash3 and SipHash return 128 bits. SwissTable expects 64 bits. XOR folding is the approach to use:
|
||||||
|
|
||||||
|
```c
|
||||||
|
uint64_t fold_128_to_64(uint128_t hash) {
|
||||||
|
return (uint64_t)(hash >> 64) ^ (uint64_t)(hash & 0xFFFFFFFFFFFFFFFF);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Robin Hood
|
||||||
|
|
||||||
|
- [Celis (1986) — original paper proving O(1) variance, Θ(log n) max probe](https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf)
|
||||||
|
- [Gankra/Faultlore — clearest walkthrough from first principles](https://faultlore.com/blah/robinhood-part-1)
|
||||||
|
- [On Worst Case Robin Hood Hashing](https://cglab.ca/~morin/publications/hashing/robinhood-siamjc.pdf)
|
||||||
|
- [Sebastian Sylvan — popularized Robin Hood in systems programming](https://www.sebastiansylvan.com/post/robin-hood-hashing-should-be-your-default-hash-table-implementation/)
|
||||||
|
- [Emmanuel Goossaert — detailed C++ implementation + backward-shift deletion](http://codecapsule.com/2013/11/11/robin-hood-hashing/)
|
||||||
|
- [Martinus (Ankerl) — most widely used C++ implementation](https://github.com/martinus/unordered_dense)
|
||||||
|
- [Tessil — clean header-only C++ implementation](https://github.com/Tessil/robin-map)
|
||||||
|
- [Malte Skarupke — Robin Hood with probe count limit](https://github.com/skarupke/flat_hash_map)
|
||||||
|
- [Robin Hood Hashing – Fairness in Collision Resolution](https://blog.hieunt.me/blog/robinhood-hashing)
|
||||||
|
|
||||||
|
## Robin Hood vs SwissTable
|
||||||
|
|
||||||
|
- [Rust migration PR](https://github.com/rust-lang/rust/pull/56241)
|
||||||
|
- [hashbrown deletion discussion](https://github.com/rust-lang/hashbrown/issues/503)
|
||||||
|
- [Jackson Allan benchmark](https://jacksonallan.github.io/c_cpp_hash_tables_benchmark/)
|
||||||
|
- [Richter et al. (VLDB 2015)](https://bigdata.uni-saarland.de/publications/p249-richter.pdf)
|
||||||
|
- [Poblete & Viola (2018)](https://www.cambridge.org/core/journals/combinatorics-probability-and-computing/article/abs/analysis-of-robin-hood-and-other-hashing-algorithms-under-the-random-probing-model/933D4F203E3C70EF15053287412242E0)
|
||||||
|
|
||||||
|
## Hybrid Open-Addressing/Separate-Chaining
|
||||||
|
|
||||||
|
- [Verstable](https://github.com/JacksonAllan/Verstable)
|
||||||
|
|
||||||
|
## Double Hashing
|
||||||
|
|
||||||
|
- Knuth, TAOCP Vol. 3 §6.4 — definitive analysis of double hashing probe counts
|
||||||
|
- Guibas & Szemerédi (1978) — proved double hashing is asymptotically equivalent to uniform probing
|
||||||
|
- [Heileman & Luo (2005) — "How Caching Affects Hashing" — cache-aware experimental comparison](http://siam.org/meetings/alenex05/papers/13gheileman.pdf)
|
||||||
|
- [VT Hashing Tutorial — excellent pedagogical walkthrough](https://research.cs.vt.edu/AVresearch/hashing/double.php)
|
||||||
|
- [Paul Khuong — "The Other Robin Hood Hashing" (original Celis double-hashing variant)](https://www.pvk.ca/Blog/2013/11/26/the-other-robin-hood-hashing/)
|
||||||
+120
-86
@@ -7,81 +7,82 @@
|
|||||||
#include "../../common/aliases/aliases.h"
|
#include "../../common/aliases/aliases.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define _arrayHeader(ARRAY) (WpArrayHeader *)(wpMiscUtilsOffsetPointer(ARRAY, (i64)sizeof(WpArrayHeader) * -1))
|
#define arrayHeader(ARRAY) (WpArrayHeader *)(wpMiscUtilsOffsetPointer(ARRAY, (i64)sizeof(WpArrayHeader) * -1))
|
||||||
|
|
||||||
wp_persist inline void _arrayValidate(const WpArray array, u64 item_size);
|
wp_persist inline void arrayValidate(const WpArray array, u64 item_size);
|
||||||
|
wp_persist inline void *arrayGetItemWithOffset(const WpArray array, u64 offset);
|
||||||
|
|
||||||
u64 _arrayCount(WpArray array) {
|
u64 arrayCount(WpArray array) {
|
||||||
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
||||||
|
|
||||||
return header->count;
|
return header->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 _arrayCapacity(WpArray array) {
|
u64 arrayCapacity(WpArray array) {
|
||||||
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
||||||
|
|
||||||
return header->capacity;
|
return header->capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 _arrayItemSize(WpArray array) {
|
u64 arrayItemSize(WpArray array) {
|
||||||
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
||||||
|
|
||||||
return header->item_size;
|
return header->item_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _arraySetCount(WpArray array, u64 count) {
|
void arraySetCount(WpArray array, u64 count) {
|
||||||
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
||||||
|
|
||||||
header->count = count;
|
header->count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *_arrayGet(WpArray array, u64 index, u64 item_size) {
|
void *arrayGet(WpArray array, u64 index, u64 item_size) {
|
||||||
wpRuntimeAssert(array != NULL, "`array` should not be NULL");
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
_arrayValidate(array, item_size);
|
arrayValidate(array, item_size);
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
wpRuntimeAssert(index < header->count, "`index` is out of bounds");
|
wpRuntimeAssert(index < header->count, "`index` is out of bounds");
|
||||||
|
|
||||||
return wpMiscUtilsOffsetPointer(array, header->item_size * index);
|
return arrayGetItemWithOffset(array, header->item_size * index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _arraySet(WpArray array, u64 index, void *value, u64 item_size) {
|
void arraySet(WpArray array, u64 index, void *value, u64 item_size) {
|
||||||
void *item = _arrayGet(array, index, item_size);
|
void *item = arrayGet(array, index, item_size);
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
memcpy(item, value, header->item_size);
|
memcpy(item, value, header->item_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _arrayAppendCapped(WpArray array, void *value, u64 item_size) {
|
void arrayAppendCapped(WpArray array, void *value, u64 item_size) {
|
||||||
wpRuntimeAssert(array != NULL, "`array` should not be NULL");
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
_arrayValidate(array, item_size);
|
arrayValidate(array, item_size);
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
if (header->count >= header->capacity) { return; }
|
if (header->count >= header->capacity) { return; }
|
||||||
|
|
||||||
u64 index = (header->count)++;
|
u64 index = (header->count)++;
|
||||||
_arraySet(array, index, value, item_size);
|
arraySet(array, index, value, item_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _arrayExtendCappend(WpArray dst, const WpArray src, u64 item_size) {
|
void arrayExtendCappend(WpArray dst, const WpArray src, u64 item_size) {
|
||||||
wpRuntimeAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
||||||
_arrayValidate(dst, item_size);
|
arrayValidate(dst, item_size);
|
||||||
_arrayValidate(src, item_size);
|
arrayValidate(src, item_size);
|
||||||
|
|
||||||
WpArrayHeader *src_header = _arrayHeader(src);
|
WpArrayHeader *src_header = arrayHeader(src);
|
||||||
WpArrayHeader *dst_header = _arrayHeader(dst);
|
WpArrayHeader *dst_header = arrayHeader(dst);
|
||||||
u64 remaining_capacity = dst_header->capacity - dst_header->count;
|
u64 remaining_capacity = dst_header->capacity - dst_header->count;
|
||||||
|
|
||||||
u64 copy_count = src_header->count < remaining_capacity ? src_header->count : remaining_capacity;
|
u64 copy_count = src_header->count < remaining_capacity ? src_header->count : remaining_capacity;
|
||||||
@@ -90,94 +91,94 @@ void _arrayExtendCappend(WpArray dst, const WpArray src, u64 item_size) {
|
|||||||
dst_header->count += copy_count;
|
dst_header->count += copy_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _arrayCopyCapped(WpArray dst, const WpArray src, u64 item_size) {
|
void arrayCopyCapped(WpArray dst, const WpArray src, u64 item_size) {
|
||||||
wpRuntimeAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
||||||
_arrayValidate(dst, item_size);
|
arrayValidate(dst, item_size);
|
||||||
_arrayValidate(src, item_size);
|
arrayValidate(src, item_size);
|
||||||
|
|
||||||
_arrayClear(dst, item_size);
|
arrayClear(dst, item_size);
|
||||||
|
|
||||||
WpArrayHeader *src_header = _arrayHeader(src);
|
WpArrayHeader *src_header = arrayHeader(src);
|
||||||
WpArrayHeader *dst_header = _arrayHeader(dst);
|
WpArrayHeader *dst_header = arrayHeader(dst);
|
||||||
u64 copy_count = src_header->count < dst_header->capacity ? src_header->count : dst_header->capacity;
|
u64 copy_count = src_header->count < dst_header->capacity ? src_header->count : dst_header->capacity;
|
||||||
memcpy((void *)dst, (void *)src, copy_count * src_header->item_size);
|
memcpy((void *)dst, (void *)src, copy_count * src_header->item_size);
|
||||||
dst_header->count = copy_count;
|
dst_header->count = copy_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpArray _arrayAppendAlloc(const WpAllocator *allocator, WpArray array, void *value,
|
WpArray arrayAppendAlloc(const WpAllocator *allocator, WpArray array, void *value,
|
||||||
WpArrayInitFlags flags, u64 item_size) {
|
WpArrayInitFlags flags, u64 item_size) {
|
||||||
wpRuntimeAssert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL");
|
wpDebugAssert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL");
|
||||||
_arrayValidate(array, item_size);
|
arrayValidate(array, item_size);
|
||||||
|
|
||||||
WpArray output = array;
|
WpArray output = array;
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
if (header->count >= header->capacity) {
|
if (header->count >= header->capacity) {
|
||||||
u64 new_capacity = wpMiscUtilsU64RoundUpPow2(header->capacity * 2);
|
u64 new_capacity = wpMiscUtilsU64RoundUpPow2(header->capacity * 2);
|
||||||
output = (WpArray )_arrayAllocCapacity(allocator, new_capacity, flags,
|
output = (WpArray )arrayAllocCapacity(allocator, new_capacity, flags,
|
||||||
header->item_size);
|
header->item_size);
|
||||||
if (!output) {
|
if (!output) {
|
||||||
output = array;
|
output = array;
|
||||||
goto RETURN_ARRAY_APPEND_ALLOC;
|
goto RETURN_ARRAY_APPEND_ALLOC;
|
||||||
}
|
}
|
||||||
_arrayCopyCapped(output, array, item_size);
|
arrayCopyCapped(output, array, item_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
_arrayAppendCapped(output, value, item_size);
|
arrayAppendCapped(output, value, item_size);
|
||||||
|
|
||||||
if ((flags & WP_ARRAY_INIT_FILLED) == WP_ARRAY_INIT_FILLED) {
|
if ((flags & WP_ARRAY_INIT_FILLED) == WP_ARRAY_INIT_FILLED) {
|
||||||
_arraySetCount(output, _arrayCapacity(output));
|
arraySetCount(output, arrayCapacity(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_ARRAY_APPEND_ALLOC:
|
RETURN_ARRAY_APPEND_ALLOC:
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpArray _arrayExtendAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src,
|
WpArray arrayExtendAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src,
|
||||||
WpArrayInitFlags flags, u64 item_size) {
|
WpArrayInitFlags flags, u64 item_size) {
|
||||||
wpRuntimeAssert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
|
wpDebugAssert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
|
||||||
_arrayValidate(dst, item_size);
|
arrayValidate(dst, item_size);
|
||||||
_arrayValidate(src, item_size);
|
arrayValidate(src, item_size);
|
||||||
|
|
||||||
WpArray output = dst;
|
WpArray output = dst;
|
||||||
|
|
||||||
WpArrayHeader *src_header = _arrayHeader(src);
|
WpArrayHeader *src_header = arrayHeader(src);
|
||||||
WpArrayHeader *dst_header = _arrayHeader(dst);
|
WpArrayHeader *dst_header = arrayHeader(dst);
|
||||||
u64 remaining_capacity = dst_header->capacity - dst_header->count;
|
u64 remaining_capacity = dst_header->capacity - dst_header->count;
|
||||||
if (src_header->count >= remaining_capacity) {
|
if (src_header->count >= remaining_capacity) {
|
||||||
u64 new_capacity = wpMiscUtilsU64RoundUpPow2(dst_header->capacity * 2);
|
u64 new_capacity = wpMiscUtilsU64RoundUpPow2(dst_header->capacity * 2);
|
||||||
output = (WpArray )_arrayAllocCapacity(allocator, new_capacity,
|
output = (WpArray )arrayAllocCapacity(allocator, new_capacity,
|
||||||
flags, dst_header->item_size);
|
flags, dst_header->item_size);
|
||||||
if (!output) {
|
if (!output) {
|
||||||
output = dst;
|
output = dst;
|
||||||
goto RETURN_ARRAY_EXTEND_ALLOC;
|
goto RETURN_ARRAY_EXTEND_ALLOC;
|
||||||
}
|
}
|
||||||
_arrayCopyCapped(output, dst, item_size);
|
arrayCopyCapped(output, dst, item_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
_arrayExtendCappend(output, src, item_size);
|
arrayExtendCappend(output, src, item_size);
|
||||||
|
|
||||||
if ((flags & WP_ARRAY_INIT_FILLED) == WP_ARRAY_INIT_FILLED) {
|
if ((flags & WP_ARRAY_INIT_FILLED) == WP_ARRAY_INIT_FILLED) {
|
||||||
_arraySetCount(output, _arrayCapacity(output));
|
arraySetCount(output, arrayCapacity(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_ARRAY_EXTEND_ALLOC:
|
RETURN_ARRAY_EXTEND_ALLOC:
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpArray _arrayCopyAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src,
|
WpArray arrayCopyAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src,
|
||||||
WpArrayInitFlags flags, u64 item_size) {
|
WpArrayInitFlags flags, u64 item_size) {
|
||||||
wpRuntimeAssert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
|
wpDebugAssert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
|
||||||
_arrayValidate(dst, item_size);
|
arrayValidate(dst, item_size);
|
||||||
_arrayValidate(src, item_size);
|
arrayValidate(src, item_size);
|
||||||
|
|
||||||
WpArray output = dst;
|
WpArray output = dst;
|
||||||
|
|
||||||
WpArrayHeader *src_header = _arrayHeader(src);
|
WpArrayHeader *src_header = arrayHeader(src);
|
||||||
WpArrayHeader *dst_header = _arrayHeader(dst);
|
WpArrayHeader *dst_header = arrayHeader(dst);
|
||||||
if (src_header->count >= dst_header->capacity) {
|
if (src_header->count >= dst_header->capacity) {
|
||||||
u64 new_capacity = wpMiscUtilsU64RoundUpPow2(dst_header->capacity * 2);
|
u64 new_capacity = wpMiscUtilsU64RoundUpPow2(dst_header->capacity * 2);
|
||||||
output = (WpArray )_arrayAllocCapacity(allocator, new_capacity,
|
output = (WpArray )arrayAllocCapacity(allocator, new_capacity,
|
||||||
flags, src_header->item_size);
|
flags, src_header->item_size);
|
||||||
if (!output) {
|
if (!output) {
|
||||||
output = dst;
|
output = dst;
|
||||||
@@ -185,63 +186,92 @@ WpArray _arrayCopyAlloc(const WpAllocator *allocator, WpArray dst, const WpArray
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_arrayCopyCapped(output, src, item_size);
|
arrayCopyCapped(output, src, item_size);
|
||||||
|
|
||||||
if ((flags & WP_ARRAY_INIT_FILLED) == WP_ARRAY_INIT_FILLED) {
|
if ((flags & WP_ARRAY_INIT_FILLED) == WP_ARRAY_INIT_FILLED) {
|
||||||
_arraySetCount(output, _arrayCapacity(output));
|
arraySetCount(output, arrayCapacity(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_ARRAY_COPY_ALLOC:
|
RETURN_ARRAY_COPY_ALLOC:
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *_arrayPop(WpArray array, u64 item_size) {
|
void arrayRemoveSwapEnd(WpArray array, u64 index, u64 item_size) {
|
||||||
wpRuntimeAssert(array != NULL, "`array` should not be NULL");
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
_arrayValidate(array, item_size);
|
arrayValidate(array, item_size);
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
|
if (header->count == 0 || index > header->count) { return; }
|
||||||
|
|
||||||
|
u64 last_item_index = header->count - 1;
|
||||||
|
|
||||||
|
if (index < last_item_index) {
|
||||||
|
void *cur_item = arrayGetItemWithOffset(array, header->item_size * index);
|
||||||
|
void *last_item = arrayGetItemWithOffset(array, header->item_size * last_item_index);
|
||||||
|
|
||||||
|
memcpy(cur_item, last_item, header->item_size);
|
||||||
|
memset(last_item, 0, header->item_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
--(header->count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *arrayPop(WpArray array, u64 item_size) {
|
||||||
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
|
arrayValidate(array, item_size);
|
||||||
|
|
||||||
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
if (header->count == 0) { return NULL; }
|
if (header->count == 0) { return NULL; }
|
||||||
|
|
||||||
u64 index = header->count - 1;
|
u64 index = header->count - 1;
|
||||||
void *out = _arrayGet(array, index, item_size);
|
void *out = arrayGetItemWithOffset(array, header->item_size * index);
|
||||||
--(header->count);
|
--(header->count);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _arrayClear(WpArray array, u64 item_size) {
|
void arrayZero(WpArray array, u64 item_size) {
|
||||||
wpRuntimeAssert(array != NULL, "`array` should not be NULL");
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
_arrayValidate(array, item_size);
|
arrayValidate(array, item_size);
|
||||||
|
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
header->count = 0;
|
memset(array, 0, header->capacity * header->item_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 _arrayCalcAllocSize(u64 capacity, u64 item_size) {
|
void arrayClear(WpArray array, u64 item_size) {
|
||||||
|
wpDebugAssert(array != NULL, "`array` should not be NULL");
|
||||||
|
arrayValidate(array, item_size);
|
||||||
|
|
||||||
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
|
header->count = 0;
|
||||||
|
memset(array, 0, header->capacity * header->item_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 arrayCalcAllocSize(u64 capacity, u64 item_size) {
|
||||||
return sizeof(WpArrayHeader) + item_size * capacity;
|
return sizeof(WpArrayHeader) + item_size * capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpArray _arrayAllocCapacity(const WpAllocator *allocator, u64 capacity, WpArrayInitFlags flags,
|
WpArray arrayAllocCapacity(const WpAllocator *allocator, u64 capacity, WpArrayInitFlags flags,
|
||||||
u64 item_size) {
|
u64 item_size) {
|
||||||
wpRuntimeAssert(allocator != NULL, "`allocator` should not be NULL");
|
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
|
||||||
|
|
||||||
WpArray output = NULL;
|
WpArray output = NULL;
|
||||||
|
|
||||||
u64 allocation_size = _arrayCalcAllocSize(capacity, item_size);
|
u64 allocation_size = arrayCalcAllocSize(capacity, item_size);
|
||||||
void *buffer = wpMemAllocatorAlloc(allocator, allocation_size);
|
void *buffer = wpMemAllocatorAlloc(allocator, allocation_size);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
goto RETURN_ARRAY_ALLOC;
|
goto RETURN_ARRAY_ALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
output = _arrayFromPreallocatedBuffer(buffer, allocation_size, flags, item_size);
|
output = arrayFromPreallocatedBuffer(buffer, allocation_size, flags, item_size);
|
||||||
|
|
||||||
RETURN_ARRAY_ALLOC:
|
RETURN_ARRAY_ALLOC:
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WpArray _arrayFromPreallocatedBuffer(void *buffer, u64 buffer_size, WpArrayInitFlags flags,
|
WpArray arrayFromPreallocatedBuffer(void *buffer, u64 buffer_size, WpArrayInitFlags flags,
|
||||||
u64 item_size) {
|
u64 item_size) {
|
||||||
wpRuntimeAssert(buffer != NULL, "`buffer` should not be NULL");
|
wpDebugAssert(buffer != NULL, "`buffer` should not be NULL");
|
||||||
|
|
||||||
i64 data_buffer_size = (i64)buffer_size - (i64)(sizeof(WpArrayHeader));
|
i64 data_buffer_size = (i64)buffer_size - (i64)(sizeof(WpArrayHeader));
|
||||||
if (data_buffer_size <= 0) {
|
if (data_buffer_size <= 0) {
|
||||||
@@ -259,18 +289,22 @@ WpArray _arrayFromPreallocatedBuffer(void *buffer, u64 buffer_size, WpArrayInitF
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _arrayDealloc(const WpAllocator *allocator, WpArray *array, u64 item_size) {
|
void arrayDealloc(const WpAllocator *allocator, WpArray *array, u64 item_size) {
|
||||||
wpRuntimeAssert(allocator != NULL, "`allocator` should not be NULL");
|
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
|
||||||
|
|
||||||
u64 capacity = wpArrayCapacity(*array);
|
u64 capacity = wpArrayCapacity(*array);
|
||||||
u64 allocation_size = _arrayCalcAllocSize(capacity, item_size);
|
u64 allocation_size = arrayCalcAllocSize(capacity, item_size);
|
||||||
void *header = (void *)_arrayHeader(*array);
|
void *header = (void *)arrayHeader(*array);
|
||||||
wpMemAllocatorFree(allocator, &header, allocation_size);
|
wpMemAllocatorFree(allocator, &header, allocation_size);
|
||||||
*array = NULL;
|
*array = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_persist inline void _arrayValidate(const WpArray array, u64 item_size) {
|
wp_persist inline void arrayValidate(const WpArray array, u64 item_size) {
|
||||||
WpArrayHeader *header = _arrayHeader(array);
|
WpArrayHeader *header = arrayHeader(array);
|
||||||
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
|
||||||
wpRuntimeAssert(item_size == header->item_size, "Invalid item type provided");
|
wpRuntimeAssert(item_size == header->item_size, "Invalid item type provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wp_persist inline void *arrayGetItemWithOffset(const WpArray array, u64 offset) {
|
||||||
|
return wpMiscUtilsOffsetPointer(array, offset);
|
||||||
|
}
|
||||||
|
|||||||
+57
-55
@@ -12,10 +12,10 @@
|
|||||||
BEGIN_C_LINKAGE
|
BEGIN_C_LINKAGE
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
#define WP_ARRAY_MAGIC (u64)0x57415f415252
|
#define WP_ARRAY_MAGIC wpU64Const(0x57415f415252)
|
||||||
|
|
||||||
#define _calcArrayCount(TYPE, ...) wpMiscUtilsVaArgsCount(TYPE, __VA_ARGS__)
|
#define calcArrayCount(TYPE, ...) wpMiscUtilsVaArgsCount(TYPE, __VA_ARGS__)
|
||||||
#define _calcArrayCapacity(TYPE, ...) wpMiscUtilsU64RoundUpPow2(_calcArrayCount(TYPE, __VA_ARGS__) * 2)
|
#define calcArrayCapacity(TYPE, ...) wpMiscUtilsU64RoundUpPow2(calcArrayCount(TYPE, __VA_ARGS__) * 2)
|
||||||
|
|
||||||
typedef struct WpStr8 WpStr8;
|
typedef struct WpStr8 WpStr8;
|
||||||
|
|
||||||
@@ -41,24 +41,24 @@ typedef uptr *WpUptrArray;
|
|||||||
typedef iptr *WpIptrArray;
|
typedef iptr *WpIptrArray;
|
||||||
typedef WpStr8 *WpStr8Array;
|
typedef WpStr8 *WpStr8Array;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpArrayInitFlags {
|
||||||
WP_ARRAY_INIT_NONE = 0,
|
WP_ARRAY_INIT_NONE = 0,
|
||||||
WP_ARRAY_INIT_FILLED = 1 << 1,
|
WP_ARRAY_INIT_FILLED = 1 << 1,
|
||||||
} WpArrayInitFlags;
|
} WpArrayInitFlags;
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
#define wpArray(TYPE, ...) ([&]() { \
|
#define wpArray(TYPE, ...) ([&]() { \
|
||||||
u64 capacity = _calcArrayCapacity(TYPE, __VA_ARGS__); \
|
u64 capacity = calcArrayCapacity(TYPE, __VA_ARGS__); \
|
||||||
\
|
\
|
||||||
TYPE items[_calcArrayCapacity(TYPE, __VA_ARGS__)] = {__VA_ARGS__}; \
|
TYPE items[calcArrayCapacity(TYPE, __VA_ARGS__)] = {__VA_ARGS__}; \
|
||||||
\
|
\
|
||||||
wp_persist u8 array[ \
|
wp_persist u8 array[ \
|
||||||
sizeof(WpArrayHeader) + _calcArrayCapacity(TYPE, __VA_ARGS__) * sizeof(TYPE) \
|
sizeof(WpArrayHeader) + calcArrayCapacity(TYPE, __VA_ARGS__) * sizeof(TYPE) \
|
||||||
] = {0}; \
|
] = {0}; \
|
||||||
WpArrayHeader *header = (WpArrayHeader *)array; \
|
WpArrayHeader *header = (WpArrayHeader *)array; \
|
||||||
header->magic = WP_ARRAY_MAGIC; \
|
header->magic = WP_ARRAY_MAGIC; \
|
||||||
header->count = _calcArrayCount(TYPE, __VA_ARGS__); \
|
header->count = calcArrayCount(TYPE, __VA_ARGS__); \
|
||||||
header->capacity = _calcArrayCapacity(TYPE, __VA_ARGS__); \
|
header->capacity = calcArrayCapacity(TYPE, __VA_ARGS__); \
|
||||||
header->item_size = sizeof(TYPE); \
|
header->item_size = sizeof(TYPE); \
|
||||||
\
|
\
|
||||||
u8 *buf = (u8 *)(header + 1); \
|
u8 *buf = (u8 *)(header + 1); \
|
||||||
@@ -78,25 +78,25 @@ typedef enum {
|
|||||||
return (TYPE *)(header + 1); \
|
return (TYPE *)(header + 1); \
|
||||||
}())
|
}())
|
||||||
#define wpArrayPop(TYPE, ARRAY) ([&]() { \
|
#define wpArrayPop(TYPE, ARRAY) ([&]() { \
|
||||||
if (ARRAY == NULL || _arrayCount((WpArray)ARRAY) == 0) { \
|
if (ARRAY == NULL || arrayCount((WpArray)ARRAY) == 0) { \
|
||||||
TYPE result{}; \
|
TYPE result{}; \
|
||||||
return result; \
|
return result; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
return *((TYPE *)_arrayPop((WpArray)ARRAY, sizeof(TYPE))); \
|
return *((TYPE *)arrayPop((WpArray)ARRAY, sizeof(TYPE))); \
|
||||||
}())
|
}())
|
||||||
#else
|
#else
|
||||||
#define _stackArray(TYPE, SIZE) struct {WpArrayHeader header; \
|
#define stackArray(TYPE, SIZE) struct {WpArrayHeader header; \
|
||||||
TYPE items[SIZE]; \
|
TYPE items[SIZE]; \
|
||||||
wpMiscUtilsReservePadding(sizeof(WpArrayHeader) + \
|
wpMiscUtilsReservePadding(sizeof(WpArrayHeader) + \
|
||||||
sizeof(TYPE) * SIZE);}
|
sizeof(TYPE) * SIZE);}
|
||||||
#define wpArray(TYPE, ...) \
|
#define wpArray(TYPE, ...) \
|
||||||
((TYPE *)( \
|
((TYPE *)( \
|
||||||
(_stackArray(TYPE, _calcArrayCapacity(TYPE, __VA_ARGS__))){ \
|
(stackArray(TYPE, calcArrayCapacity(TYPE, __VA_ARGS__))){ \
|
||||||
.header = { \
|
.header = { \
|
||||||
.magic = WP_ARRAY_MAGIC, \
|
.magic = WP_ARRAY_MAGIC, \
|
||||||
.count = _calcArrayCount(TYPE, __VA_ARGS__), \
|
.count = calcArrayCount(TYPE, __VA_ARGS__), \
|
||||||
.capacity = _calcArrayCapacity(TYPE, __VA_ARGS__), \
|
.capacity = calcArrayCapacity(TYPE, __VA_ARGS__), \
|
||||||
.item_size = sizeof(TYPE), \
|
.item_size = sizeof(TYPE), \
|
||||||
}, \
|
}, \
|
||||||
.items = {__VA_ARGS__}, \
|
.items = {__VA_ARGS__}, \
|
||||||
@@ -104,7 +104,7 @@ typedef enum {
|
|||||||
))
|
))
|
||||||
#define wpArrayWithCapacity(TYPE, CAPACITY, FLAGS) \
|
#define wpArrayWithCapacity(TYPE, CAPACITY, FLAGS) \
|
||||||
((TYPE *)( \
|
((TYPE *)( \
|
||||||
(_stackArray(TYPE, CAPACITY)){ \
|
(stackArray(TYPE, CAPACITY)){ \
|
||||||
.header = { \
|
.header = { \
|
||||||
.magic = WP_ARRAY_MAGIC, \
|
.magic = WP_ARRAY_MAGIC, \
|
||||||
.count = (FLAGS & WP_ARRAY_INIT_FILLED) ? CAPACITY : 0, \
|
.count = (FLAGS & WP_ARRAY_INIT_FILLED) ? CAPACITY : 0, \
|
||||||
@@ -115,71 +115,71 @@ typedef enum {
|
|||||||
}.items \
|
}.items \
|
||||||
))
|
))
|
||||||
#define wpArrayPop(TYPE, ARRAY) \
|
#define wpArrayPop(TYPE, ARRAY) \
|
||||||
(ARRAY == NULL || _arrayCount((WpArray)ARRAY) == 0 ? \
|
(ARRAY == NULL || arrayCount((WpArray)ARRAY) == 0 ? \
|
||||||
(TYPE){0} : \
|
(TYPE){0} : \
|
||||||
*((TYPE *)_arrayPop((WpArray)ARRAY, sizeof(TYPE))) \
|
*((TYPE *)arrayPop((WpArray)ARRAY, sizeof(TYPE))) \
|
||||||
)
|
)
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
#define wpArrayCount(ARRAY) \
|
#define wpArrayCount(ARRAY) \
|
||||||
(_arrayCount((WpArray)ARRAY))
|
(arrayCount((WpArray)ARRAY))
|
||||||
#define wpArrayCapacity(ARRAY) \
|
#define wpArrayCapacity(ARRAY) \
|
||||||
(_arrayCapacity((WpArray)ARRAY))
|
(arrayCapacity((WpArray)ARRAY))
|
||||||
#define wpArrayItemSize(ARRAY) \
|
#define wpArrayItemSize(ARRAY) \
|
||||||
(_arrayItemSize((WpArray)ARRAY))
|
(arrayItemSize((WpArray)ARRAY))
|
||||||
#define wpArraySetCount(ARRAY, COUNT) \
|
#define wpArraySetCount(ARRAY, COUNT) \
|
||||||
(_arraySetCount((WpArray)ARRAY, COUNT))
|
(arraySetCount((WpArray)ARRAY, COUNT))
|
||||||
#define wpArrayGet(TYPE, ARRAY, INDEX) \
|
#define wpArrayGet(TYPE, ARRAY, INDEX) \
|
||||||
((TYPE *)_arrayGet((WpArray)ARRAY, \
|
((TYPE *)arrayGet((WpArray)ARRAY, \
|
||||||
INDEX, \
|
INDEX, \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpArraySet(TYPE, ARRAY, INDEX, VALUE_PTR) \
|
#define wpArraySet(TYPE, ARRAY, INDEX, VALUE_PTR) \
|
||||||
(_arraySet((WpArray)ARRAY, \
|
(arraySet((WpArray)ARRAY, \
|
||||||
INDEX, \
|
INDEX, \
|
||||||
(u8 *)VALUE_PTR, \
|
(u8 *)VALUE_PTR, \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpArrayAppendCapped(TYPE, ARRAY, VALUE_PTR) \
|
#define wpArrayAppendCapped(TYPE, ARRAY, VALUE_PTR) \
|
||||||
(_arrayAppendCapped((WpArray)ARRAY, \
|
(arrayAppendCapped((WpArray)ARRAY, \
|
||||||
(u8 *)VALUE_PTR, \
|
(u8 *)VALUE_PTR, \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpArrayExtendCapped(TYPE, DST_ARRAY, SRC_ARRAY) \
|
#define wpArrayExtendCapped(TYPE, DST_ARRAY, SRC_ARRAY) \
|
||||||
(_arrayExtendCappend((WpArray)DST_ARRAY, \
|
(arrayExtendCappend((WpArray)DST_ARRAY, \
|
||||||
(WpArray)SRC_ARRAY, \
|
(WpArray)SRC_ARRAY, \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpArrayCopyCapped(TYPE, DST_ARRAY, SRC_ARRAY) \
|
#define wpArrayCopyCapped(TYPE, DST_ARRAY, SRC_ARRAY) \
|
||||||
(_arrayCopyCapped((WpArray)DST_ARRAY, \
|
(arrayCopyCapped((WpArray)DST_ARRAY, \
|
||||||
(WpArray)SRC_ARRAY, \
|
(WpArray)SRC_ARRAY, \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpArrayAppendAlloc(TYPE, ALLOCATOR_PTR, ARRAY, VALUE_PTR, FLAGS) \
|
#define wpArrayAppendAlloc(TYPE, ALLOCATOR_PTR, ARRAY, VALUE_PTR, FLAGS) \
|
||||||
((TYPE *)_arrayAppendAlloc(ALLOCATOR_PTR, \
|
((TYPE *)arrayAppendAlloc(ALLOCATOR_PTR, \
|
||||||
(WpArray)ARRAY, \
|
(WpArray)ARRAY, \
|
||||||
(u8 *)VALUE_PTR, \
|
(u8 *)VALUE_PTR, \
|
||||||
FLAGS, \
|
FLAGS, \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpArrayExtendAlloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY, FLAGS) \
|
#define wpArrayExtendAlloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY, FLAGS) \
|
||||||
((TYPE *)_arrayExtendAlloc(ALLOCATOR_PTR, \
|
((TYPE *)arrayExtendAlloc(ALLOCATOR_PTR, \
|
||||||
(WpArray)DST_ARRAY, \
|
(WpArray)DST_ARRAY, \
|
||||||
(WpArray)SRC_ARRAY, \
|
(WpArray)SRC_ARRAY, \
|
||||||
FLAGS, \
|
FLAGS, \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpArrayCopyAlloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY, FLAGS) \
|
#define wpArrayCopyAlloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY, FLAGS) \
|
||||||
((TYPE *)_arrayCopyAlloc(ALLOCATOR_PTR, \
|
((TYPE *)arrayCopyAlloc(ALLOCATOR_PTR, \
|
||||||
(WpArray)DST_ARRAY, \
|
(WpArray)DST_ARRAY, \
|
||||||
(WpArray)SRC_ARRAY, \
|
(WpArray)SRC_ARRAY, \
|
||||||
FLAGS, \
|
FLAGS, \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpArrayClear(TYPE, ARRAY) \
|
#define wpArrayRemoveSwapEnd(TYPE, ARRAY, INDEX) arrayRemoveSwapEnd(ARRAY, INDEX, sizeof(TYPE))
|
||||||
(_arrayClear((WpArray)ARRAY, \
|
#define wpArrayZero(TYPE, ARRAY) (arrayZero((WpArray)ARRAY, sizeof(TYPE)))
|
||||||
sizeof(TYPE)))
|
#define wpArrayClear(TYPE, ARRAY) (arrayClear((WpArray)ARRAY, sizeof(TYPE)))
|
||||||
#define wpArrayCalcAllocSize(TYPE, CAPACITY) _arrayCalcAllocSize(CAPACITY, sizeof(TYPE))
|
#define wpArrayCalcAllocSize(TYPE, CAPACITY) arrayCalcAllocSize(CAPACITY, sizeof(TYPE))
|
||||||
#define wpArrayAllocCapacity(TYPE, ALLOCATOR_PTR, CAPACITY, FLAGS) \
|
#define wpArrayAllocCapacity(TYPE, ALLOCATOR_PTR, CAPACITY, FLAGS) \
|
||||||
((TYPE *)_arrayAllocCapacity(ALLOCATOR_PTR, CAPACITY, FLAGS, sizeof(TYPE)))
|
((TYPE *)arrayAllocCapacity(ALLOCATOR_PTR, CAPACITY, FLAGS, sizeof(TYPE)))
|
||||||
#define wpArrayFromPreallcatedBuffer(TYPE, BUFFER, BUFFER_SIZE) \
|
#define wpArrayFromPreallcatedBuffer(TYPE, BUFFER, BUFFER_SIZE) \
|
||||||
((TYPE *)_array_from_preallcated_buffer(BUFFER, BUFFER_SIZE, sizeof(TYPE)))
|
((TYPE *)array_from_preallcated_buffer(BUFFER, BUFFER_SIZE, sizeof(TYPE)))
|
||||||
// Only needed for allocators like malloc where each allocation has to be freed on its own.
|
// Only needed for allocators like malloc where each allocation has to be freed on its own.
|
||||||
// No need to use it for allocators like Arena.
|
// No need to use it for allocators like Arena.
|
||||||
#define wpArrayDealloc(TYPE, ALLOCATOR_PTR, ARRAY_DPTR) \
|
#define wpArrayDealloc(TYPE, ALLOCATOR_PTR, ARRAY_DPTR) \
|
||||||
(_arrayDealloc(ALLOCATOR_PTR, (WpArray *)ARRAY_DPTR, sizeof(TYPE)))
|
(arrayDealloc(ALLOCATOR_PTR, (WpArray *)ARRAY_DPTR, sizeof(TYPE)))
|
||||||
|
|
||||||
|
|
||||||
typedef struct WpArrayHeader WpArrayHeader;
|
typedef struct WpArrayHeader WpArrayHeader;
|
||||||
@@ -190,29 +190,31 @@ struct WpArrayHeader {
|
|||||||
u64 item_size;
|
u64 item_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
u64 _arrayCount(WpArray array);
|
u64 arrayCount(WpArray array);
|
||||||
u64 _arrayCapacity(WpArray array);
|
u64 arrayCapacity(WpArray array);
|
||||||
u64 _arrayItemSize(WpArray array);
|
u64 arrayItemSize(WpArray array);
|
||||||
void _arraySetCount(WpArray array, u64 count);
|
void arraySetCount(WpArray array, u64 count);
|
||||||
void *_arrayGet(WpArray array, u64 index, u64 item_size);
|
void *arrayGet(WpArray array, u64 index, u64 item_size);
|
||||||
void _arraySet(WpArray array, u64 index, void *value, u64 item_size);
|
void arraySet(WpArray array, u64 index, void *value, u64 item_size);
|
||||||
void _arrayAppendCapped(WpArray array, void *value, u64 item_size);
|
void arrayAppendCapped(WpArray array, void *value, u64 item_size);
|
||||||
void _arrayExtendCappend(WpArray dst, const WpArray src, u64 item_size);
|
void arrayExtendCappend(WpArray dst, const WpArray src, u64 item_size);
|
||||||
void _arrayCopyCapped(WpArray dst, const WpArray src, u64 item_size);
|
void arrayCopyCapped(WpArray dst, const WpArray src, u64 item_size);
|
||||||
WpArray _arrayAppendAlloc(const WpAllocator *allocator, WpArray array, void *value,
|
WpArray arrayAppendAlloc(const WpAllocator *allocator, WpArray array, void *value,
|
||||||
WpArrayInitFlags flags, u64 item_size);
|
WpArrayInitFlags flags, u64 item_size);
|
||||||
WpArray _arrayExtendAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src,
|
WpArray arrayExtendAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src,
|
||||||
WpArrayInitFlags flags, u64 item_size);
|
WpArrayInitFlags flags, u64 item_size);
|
||||||
WpArray _arrayCopyAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src,
|
WpArray arrayCopyAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src,
|
||||||
WpArrayInitFlags flags, u64 item_size);
|
WpArrayInitFlags flags, u64 item_size);
|
||||||
void *_arrayPop(WpArray array, u64 item_size);
|
void arrayRemoveSwapEnd(WpArray array, u64 index, u64 item_size);
|
||||||
void _arrayClear(WpArray array, u64 item_size);
|
void *arrayPop(WpArray array, u64 item_size);
|
||||||
u64 _arrayCalcAllocSize(u64 capacity, u64 item_size);
|
void arrayZero(WpArray array, u64 item_size);
|
||||||
WpArray _arrayAllocCapacity(const WpAllocator *allocator, u64 capacity, WpArrayInitFlags flags,
|
void arrayClear(WpArray array, u64 item_size);
|
||||||
|
u64 arrayCalcAllocSize(u64 capacity, u64 item_size);
|
||||||
|
WpArray arrayAllocCapacity(const WpAllocator *allocator, u64 capacity, WpArrayInitFlags flags,
|
||||||
u64 item_size);
|
u64 item_size);
|
||||||
WpArray _arrayFromPreallocatedBuffer(void *buffer, u64 buffer_size, WpArrayInitFlags flags,
|
WpArray arrayFromPreallocatedBuffer(void *buffer, u64 buffer_size, WpArrayInitFlags flags,
|
||||||
u64 item_size);
|
u64 item_size);
|
||||||
void _arrayDealloc(const WpAllocator *allocator, WpArray *array, u64 item_size);
|
void arrayDealloc(const WpAllocator *allocator, WpArray *array, u64 item_size);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
#include "../../common/platform/platform.h"
|
#include "../../common/platform/platform.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
wp_intern WpDblList _node_to_list(WpDblNode *node, u64 item_size);
|
wp_intern WpDblList nodeToList(WpDblNode *node, u64 item_size);
|
||||||
wp_intern inline void _dblListValidate(const WpDblList *list, u64 item_size);
|
wp_intern inline void dblListValidate(const WpDblList *list, u64 item_size);
|
||||||
wp_intern inline void _dblListNodeValidate(const WpDblList *list, const WpDblNode *node, u64 item_size);
|
wp_intern inline void dblListNodeValidate(const WpDblList *list, const WpDblNode *node, u64 item_size);
|
||||||
|
|
||||||
WpDblList *_dblListAlloc(const WpAllocator *allocator, u64 item_size) {
|
WpDblList *dblListAlloc(const WpAllocator *allocator, u64 item_size) {
|
||||||
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
|
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
|
||||||
|
|
||||||
WpDblList *list = wpMemAllocatorAlloc(allocator, sizeof(WpDblList));
|
WpDblList *list = wpMemAllocatorAlloc(allocator, sizeof(WpDblList));
|
||||||
@@ -25,7 +25,7 @@ DBL_LIST_ALLOC_RETURN:
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpDblNode *_dblListNodeAlloc(const WpAllocator *allocator, void *item, u64 item_size) {
|
WpDblNode *dblListNodeAlloc(const WpAllocator *allocator, void *item, u64 item_size) {
|
||||||
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
|
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
|
||||||
|
|
||||||
WpDblNode *node = wpMemAllocatorAlloc(allocator, sizeof(WpDblNode));
|
WpDblNode *node = wpMemAllocatorAlloc(allocator, sizeof(WpDblNode));
|
||||||
@@ -40,9 +40,9 @@ DBL_LIST_NODE_ALLOC_RETURN:
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpDblNode *_dblListGet(const WpDblList *list, u64 index, u64 item_size) {
|
WpDblNode *dblListGet(const WpDblList *list, u64 index, u64 item_size) {
|
||||||
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
||||||
_dblListValidate(list, item_size);
|
dblListValidate(list, item_size);
|
||||||
wpRuntimeAssert(index < list->node_count, "`index` is out of bounds");
|
wpRuntimeAssert(index < list->node_count, "`index` is out of bounds");
|
||||||
|
|
||||||
WpDblNode *output = NULL;
|
WpDblNode *output = NULL;
|
||||||
@@ -56,12 +56,12 @@ WpDblNode *_dblListGet(const WpDblList *list, u64 index, u64 item_size) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _dblListPushFront(WpDblList *list, WpDblNode *node, u64 item_size) {
|
void dblListPushFront(WpDblList *list, WpDblNode *node, u64 item_size) {
|
||||||
wpDebugAssert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
wpDebugAssert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
||||||
_dblListValidate(list, item_size);
|
dblListValidate(list, item_size);
|
||||||
_dblListNodeValidate(list, node, item_size);
|
dblListNodeValidate(list, node, item_size);
|
||||||
|
|
||||||
WpDblList node_list = _node_to_list(node, item_size);
|
WpDblList node_list = nodeToList(node, item_size);
|
||||||
|
|
||||||
if (list->node_count == 0) {
|
if (list->node_count == 0) {
|
||||||
*list = node_list;
|
*list = node_list;
|
||||||
@@ -79,12 +79,12 @@ void _dblListPushFront(WpDblList *list, WpDblNode *node, u64 item_size) {
|
|||||||
node_list.last->header.next = first;
|
node_list.last->header.next = first;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _dblListPushBack(WpDblList *list, WpDblNode *node, u64 item_size) {
|
void dblListPushBack(WpDblList *list, WpDblNode *node, u64 item_size) {
|
||||||
wpDebugAssert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
wpDebugAssert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
||||||
_dblListValidate(list, item_size);
|
dblListValidate(list, item_size);
|
||||||
_dblListNodeValidate(list, node, item_size);
|
dblListNodeValidate(list, node, item_size);
|
||||||
|
|
||||||
WpDblList node_list = _node_to_list(node, item_size);
|
WpDblList node_list = nodeToList(node, item_size);
|
||||||
|
|
||||||
if (list->node_count == 0) {
|
if (list->node_count == 0) {
|
||||||
*list = node_list;
|
*list = node_list;
|
||||||
@@ -102,25 +102,25 @@ void _dblListPushBack(WpDblList *list, WpDblNode *node, u64 item_size) {
|
|||||||
node_list.first->header.prev = last;
|
node_list.first->header.prev = last;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _dblListInsert(WpDblList *list, WpDblNode *node, u64 index, u64 item_size) {
|
void dblListInsert(WpDblList *list, WpDblNode *node, u64 index, u64 item_size) {
|
||||||
wpDebugAssert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
wpDebugAssert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
||||||
_dblListValidate(list, item_size);
|
dblListValidate(list, item_size);
|
||||||
_dblListNodeValidate(list, node, item_size);
|
dblListNodeValidate(list, node, item_size);
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
_dblListPushFront(list, node, item_size);
|
dblListPushFront(list, node, item_size);
|
||||||
return;
|
return;
|
||||||
} else if (index == list->node_count) {
|
} else if (index == list->node_count) {
|
||||||
_dblListPushBack(list, node, item_size);
|
dblListPushBack(list, node, item_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpDblNode *dst_node = _dblListGet(list, index, item_size);
|
WpDblNode *dst_node = dblListGet(list, index, item_size);
|
||||||
if (!dst_node) {
|
if (!dst_node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpDblList node_list = _node_to_list(node, item_size);
|
WpDblList node_list = nodeToList(node, item_size);
|
||||||
|
|
||||||
list->node_count += node_list.node_count;
|
list->node_count += node_list.node_count;
|
||||||
|
|
||||||
@@ -133,9 +133,9 @@ void _dblListInsert(WpDblList *list, WpDblNode *node, u64 index, u64 item_size)
|
|||||||
node_list.last->header.next = dst_node;
|
node_list.last->header.next = dst_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpDblNode *_dblListPopFront(WpDblList *list, u64 item_size) {
|
WpDblNode *dblListPopFront(WpDblList *list, u64 item_size) {
|
||||||
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
||||||
_dblListValidate(list, item_size);
|
dblListValidate(list, item_size);
|
||||||
|
|
||||||
WpDblNode *output = NULL;
|
WpDblNode *output = NULL;
|
||||||
|
|
||||||
@@ -159,9 +159,9 @@ RETURN_LIST_POP_FRONT:
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpDblNode *_dblListPopBack(WpDblList *list, u64 item_size) {
|
WpDblNode *dblListPopBack(WpDblList *list, u64 item_size) {
|
||||||
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
||||||
_dblListValidate(list, item_size);
|
dblListValidate(list, item_size);
|
||||||
|
|
||||||
WpDblNode *output = NULL;
|
WpDblNode *output = NULL;
|
||||||
|
|
||||||
@@ -185,21 +185,21 @@ RETURN_LIST_POP_BACK:
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpDblNode *_dblListRemove(WpDblList *list, u64 index, u64 item_size) {
|
WpDblNode *dblListRemove(WpDblList *list, u64 index, u64 item_size) {
|
||||||
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
||||||
_dblListValidate(list, item_size);
|
dblListValidate(list, item_size);
|
||||||
|
|
||||||
WpDblNode *output = NULL;
|
WpDblNode *output = NULL;
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
output = _dblListPopFront(list, item_size);
|
output = dblListPopFront(list, item_size);
|
||||||
goto RETURN_LIST_REMOVE;
|
goto RETURN_LIST_REMOVE;
|
||||||
} else if (index == list->node_count) {
|
} else if (index == list->node_count) {
|
||||||
output = _dblListPopBack(list, item_size);
|
output = dblListPopBack(list, item_size);
|
||||||
goto RETURN_LIST_REMOVE;
|
goto RETURN_LIST_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
output = _dblListGet(list, index, item_size);
|
output = dblListGet(list, index, item_size);
|
||||||
if (!output) {
|
if (!output) {
|
||||||
goto RETURN_LIST_REMOVE;
|
goto RETURN_LIST_REMOVE;
|
||||||
}
|
}
|
||||||
@@ -215,17 +215,17 @@ RETURN_LIST_REMOVE:
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _dblListEmpty(WpDblList *list, u64 item_size) {
|
void dblListEmpty(WpDblList *list, u64 item_size) {
|
||||||
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
wpDebugAssert(list != NULL, "`list` should not be NULL");
|
||||||
_dblListValidate(list, item_size);
|
dblListValidate(list, item_size);
|
||||||
|
|
||||||
u64 count = list->node_count;
|
u64 count = list->node_count;
|
||||||
for (u64 i = 0; i < count; ++i) {
|
for (u64 i = 0; i < count; ++i) {
|
||||||
_dblListPopBack(list, item_size);
|
dblListPopBack(list, item_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern WpDblList _node_to_list(WpDblNode *node, u64 item_size) {
|
wp_intern WpDblList nodeToList(WpDblNode *node, u64 item_size) {
|
||||||
WpDblList output = {
|
WpDblList output = {
|
||||||
.magic = WP_DBL_LIST_MAGIC,
|
.magic = WP_DBL_LIST_MAGIC,
|
||||||
.first = node,
|
.first = node,
|
||||||
@@ -247,12 +247,12 @@ wp_intern WpDblList _node_to_list(WpDblNode *node, u64 item_size) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern inline void _dblListValidate(const WpDblList *list, u64 item_size) {
|
wp_intern inline void dblListValidate(const WpDblList *list, u64 item_size) {
|
||||||
wpRuntimeAssert(list->magic == WP_DBL_LIST_MAGIC, "`list` isn't a valid wp list type");
|
wpRuntimeAssert(list->magic == WP_DBL_LIST_MAGIC, "`list` isn't a valid wp list type");
|
||||||
wpRuntimeAssert(list->item_size == item_size, "Invalid item provided");
|
wpRuntimeAssert(list->item_size == item_size, "Invalid item provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern inline void _dblListNodeValidate(const WpDblList *list, const WpDblNode *node, u64 item_size) {
|
wp_intern inline void dblListNodeValidate(const WpDblList *list, const WpDblNode *node, u64 item_size) {
|
||||||
wpRuntimeAssert(node->header.magic == WP_DBL_NODE_MAGIC, "`node` isn't a valid wp node type");
|
wpRuntimeAssert(node->header.magic == WP_DBL_NODE_MAGIC, "`node` isn't a valid wp node type");
|
||||||
wpRuntimeAssert(list->item_size == node->header.item_size, "Mismatched `list` and `node` types");
|
wpRuntimeAssert(list->item_size == node->header.item_size, "Mismatched `list` and `node` types");
|
||||||
wpRuntimeAssert(node->header.item_size == item_size, "Invalid item provided");
|
wpRuntimeAssert(node->header.item_size == item_size, "Invalid item provided");
|
||||||
|
|||||||
@@ -11,12 +11,12 @@
|
|||||||
BEGIN_C_LINKAGE
|
BEGIN_C_LINKAGE
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
#define WP_DBL_LIST_MAGIC (u64)0x57415f444c5354
|
#define WP_DBL_LIST_MAGIC wpU64Const(0x57415f444c5354)
|
||||||
#define WP_DBL_NODE_MAGIC (u64)0x57415f444e44
|
#define WP_DBL_NODE_MAGIC wpU64Const(0x57415f444e44)
|
||||||
|
|
||||||
typedef struct WpDblNode WpDblNode;
|
typedef struct WpDblNode WpDblNode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct WpDblNodeHeader {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
u64 item_size;
|
u64 item_size;
|
||||||
WpDblNode *prev;
|
WpDblNode *prev;
|
||||||
@@ -28,7 +28,7 @@ struct WpDblNode {
|
|||||||
void *item;
|
void *item;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct WpDblList {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
u64 node_count;
|
u64 node_count;
|
||||||
u64 item_size;
|
u64 item_size;
|
||||||
@@ -81,7 +81,7 @@ typedef WpDblNode WpStr8Node;
|
|||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
#define wpDblList(TYPE) \
|
#define wpDblList(TYPE) \
|
||||||
WpDblList{WP_DBL_LIST_MAGIC, 0, sizeof(TYPE), nullptr, nullptr}
|
WpDblList{WP_DBL_LIST_MAGIC, 0, sizeof(TYPE), nullptr, nullptr}
|
||||||
#define _dblListNode(TYPE, ITEM_PTR) ([&]() { \
|
#define dblListNode(TYPE, ITEM_PTR) ([&]() { \
|
||||||
wp_persist WpDblNode node = { \
|
wp_persist WpDblNode node = { \
|
||||||
WpDblNodeHeader{WP_DBL_NODE_MAGIC, sizeof(TYPE), nullptr, nullptr}, \
|
WpDblNodeHeader{WP_DBL_NODE_MAGIC, sizeof(TYPE), nullptr, nullptr}, \
|
||||||
ITEM_PTR, \
|
ITEM_PTR, \
|
||||||
@@ -93,18 +93,18 @@ typedef WpDblNode WpStr8Node;
|
|||||||
#define wpDblList(TYPE) ( \
|
#define wpDblList(TYPE) ( \
|
||||||
(WpDblList){.magic = WP_DBL_LIST_MAGIC, .item_size = sizeof(TYPE)} \
|
(WpDblList){.magic = WP_DBL_LIST_MAGIC, .item_size = sizeof(TYPE)} \
|
||||||
)
|
)
|
||||||
#define _dblListNode(TYPE, ITEM_PTR) ( \
|
#define dblListNode(TYPE, ITEM_PTR) ( \
|
||||||
&((WpDblNode){.header = {.magic = WP_DBL_NODE_MAGIC, .item_size = sizeof(TYPE)}, \
|
&((WpDblNode){.header = {.magic = WP_DBL_NODE_MAGIC, .item_size = sizeof(TYPE)}, \
|
||||||
.item = ITEM_PTR}) \
|
.item = ITEM_PTR}) \
|
||||||
)
|
)
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
#define wpDblListAlloc(TYPE, ALLOCATOR) \
|
#define wpDblListAlloc(TYPE, ALLOCATOR) \
|
||||||
(_dblListAlloc(ALLOCATOR, sizeof(TYPE)))
|
(dblListAlloc(ALLOCATOR, sizeof(TYPE)))
|
||||||
#define wpDblListGet(TYPE, LIST_PTR, ITEM_INDEX) \
|
#define wpDblListGet(TYPE, LIST_PTR, ITEM_INDEX) \
|
||||||
((TYPE *)(_dblListGet(LIST_PTR, ITEM_INDEX, sizeof(TYPE))->item))
|
((TYPE *)(dblListGet(LIST_PTR, ITEM_INDEX, sizeof(TYPE))->item))
|
||||||
#define wpDblListGetNode(TYPE, LIST_PTR, ITEM_INDEX) \
|
#define wpDblListGetNode(TYPE, LIST_PTR, ITEM_INDEX) \
|
||||||
(_dblListGet(LIST_PTR, ITEM_INDEX, sizeof(TYPE)))
|
(dblListGet(LIST_PTR, ITEM_INDEX, sizeof(TYPE)))
|
||||||
#define wpDblListGetNodeItem(TYPE, NODE_PTR) \
|
#define wpDblListGetNodeItem(TYPE, NODE_PTR) \
|
||||||
((TYPE *)( \
|
((TYPE *)( \
|
||||||
(NODE_PTR == NULL) ? \
|
(NODE_PTR == NULL) ? \
|
||||||
@@ -112,70 +112,70 @@ typedef WpDblNode WpStr8Node;
|
|||||||
(NODE_PTR)->item \
|
(NODE_PTR)->item \
|
||||||
))
|
))
|
||||||
#define wpDblListPushFront(TYPE, LIST_PTR, ITEM_PTR) \
|
#define wpDblListPushFront(TYPE, LIST_PTR, ITEM_PTR) \
|
||||||
(_dblListPushFront(LIST_PTR, _dblListNode(TYPE, ITEM_PTR), sizeof(TYPE)))
|
(dblListPushFront(LIST_PTR, dblListNode(TYPE, ITEM_PTR), sizeof(TYPE)))
|
||||||
#define wpDblListPushBack(TYPE, LIST_PTR, ITEM_PTR) \
|
#define wpDblListPushBack(TYPE, LIST_PTR, ITEM_PTR) \
|
||||||
(_dblListPushBack(LIST_PTR, _dblListNode(TYPE, ITEM_PTR), sizeof(TYPE)))
|
(dblListPushBack(LIST_PTR, dblListNode(TYPE, ITEM_PTR), sizeof(TYPE)))
|
||||||
#define wpDblListInsert(TYPE, LIST_PTR, ITEM_PTR, ITEM_INDEX) \
|
#define wpDblListInsert(TYPE, LIST_PTR, ITEM_PTR, ITEM_INDEX) \
|
||||||
(_dblListInsert(LIST_PTR, _dblListNode(TYPE, ITEM_PTR), \
|
(dblListInsert(LIST_PTR, dblListNode(TYPE, ITEM_PTR), \
|
||||||
ITEM_INDEX, sizeof(TYPE)))
|
ITEM_INDEX, sizeof(TYPE)))
|
||||||
#define wpDblListPushFrontAlloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR) \
|
#define wpDblListPushFrontAlloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR) \
|
||||||
(_dblListPushFront(LIST_PTR, _dblListNodeAlloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \
|
(dblListPushFront(LIST_PTR, dblListNodeAlloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpDblListPushBackAlloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR) \
|
#define wpDblListPushBackAlloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR) \
|
||||||
(_dblListPushBack(LIST_PTR, _dblListNodeAlloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \
|
(dblListPushBack(LIST_PTR, dblListNodeAlloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \
|
||||||
sizeof(TYPE)))
|
sizeof(TYPE)))
|
||||||
#define wpDblListInsertAlloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR, ITEM_INDEX) \
|
#define wpDblListInsertAlloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR, ITEM_INDEX) \
|
||||||
(_dblListInsert(LIST_PTR, _dblListNodeAlloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \
|
(dblListInsert(LIST_PTR, dblListNodeAlloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \
|
||||||
ITEM_INDEX, sizeof(TYPE)))
|
ITEM_INDEX, sizeof(TYPE)))
|
||||||
#define wpDblListPopFront(TYPE, LIST_PTR) \
|
#define wpDblListPopFront(TYPE, LIST_PTR) \
|
||||||
((TYPE *)( \
|
((TYPE *)( \
|
||||||
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
|
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
|
||||||
NULL : \
|
NULL : \
|
||||||
_dblListPopFront(LIST_PTR, sizeof(TYPE))->item \
|
dblListPopFront(LIST_PTR, sizeof(TYPE))->item \
|
||||||
))
|
))
|
||||||
#define wpDblListPopBack(TYPE, LIST_PTR) \
|
#define wpDblListPopBack(TYPE, LIST_PTR) \
|
||||||
((TYPE *)( \
|
((TYPE *)( \
|
||||||
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
|
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
|
||||||
NULL : \
|
NULL : \
|
||||||
_dblListPopBack(LIST_PTR, sizeof(TYPE))->item \
|
dblListPopBack(LIST_PTR, sizeof(TYPE))->item \
|
||||||
))
|
))
|
||||||
#define wpDblListRemove(TYPE, LIST_PTR, ITEM_INDEX) \
|
#define wpDblListRemove(TYPE, LIST_PTR, ITEM_INDEX) \
|
||||||
((TYPE *)( \
|
((TYPE *)( \
|
||||||
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0 || ITEM_INDEX >= (LIST_PTR)->node_count) ? \
|
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0 || ITEM_INDEX >= (LIST_PTR)->node_count) ? \
|
||||||
NULL : \
|
NULL : \
|
||||||
_dblListRemove(LIST_PTR, ITEM_INDEX, sizeof(TYPE))->item \
|
dblListRemove(LIST_PTR, ITEM_INDEX, sizeof(TYPE))->item \
|
||||||
))
|
))
|
||||||
#define wpDblListPopFrontNode(TYPE, LIST_PTR) \
|
#define wpDblListPopFrontNode(TYPE, LIST_PTR) \
|
||||||
( \
|
( \
|
||||||
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
|
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
|
||||||
NULL : \
|
NULL : \
|
||||||
_dblListPopFront(LIST_PTR, sizeof(TYPE)) \
|
dblListPopFront(LIST_PTR, sizeof(TYPE)) \
|
||||||
)
|
)
|
||||||
#define wpDblListPopBackNode(TYPE, LIST_PTR) \
|
#define wpDblListPopBackNode(TYPE, LIST_PTR) \
|
||||||
( \
|
( \
|
||||||
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
|
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
|
||||||
NULL : \
|
NULL : \
|
||||||
_dblListPopBack(LIST_PTR, sizeof(TYPE)) \
|
dblListPopBack(LIST_PTR, sizeof(TYPE)) \
|
||||||
)
|
)
|
||||||
#define wpDblListRemoveNode(TYPE, LIST_PTR, ITEM_INDEX) \
|
#define wpDblListRemoveNode(TYPE, LIST_PTR, ITEM_INDEX) \
|
||||||
( \
|
( \
|
||||||
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0 || ITEM_INDEX >= (LIST_PTR)->node_count) ? \
|
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0 || ITEM_INDEX >= (LIST_PTR)->node_count) ? \
|
||||||
NULL : \
|
NULL : \
|
||||||
_dblListRemove(LIST_PTR, ITEM_INDEX, sizeof(TYPE)) \
|
dblListRemove(LIST_PTR, ITEM_INDEX, sizeof(TYPE)) \
|
||||||
)
|
)
|
||||||
#define wpDblListEmpty(TYPE, LIST_PTR) \
|
#define wpDblListEmpty(TYPE, LIST_PTR) \
|
||||||
(_dblListEmpty(LIST_PTR, sizeof(TYPE)))
|
(dblListEmpty(LIST_PTR, sizeof(TYPE)))
|
||||||
|
|
||||||
WpDblList *_dblListAlloc(const WpAllocator *allocator, u64 item_size);
|
WpDblList *dblListAlloc(const WpAllocator *allocator, u64 item_size);
|
||||||
WpDblNode *_dblListNodeAlloc(const WpAllocator *allocator, void *item, u64 item_size);
|
WpDblNode *dblListNodeAlloc(const WpAllocator *allocator, void *item, u64 item_size);
|
||||||
WpDblNode *_dblListGet(const WpDblList *list, u64 index, u64 item_size);
|
WpDblNode *dblListGet(const WpDblList *list, u64 index, u64 item_size);
|
||||||
void _dblListPushFront(WpDblList *list, WpDblNode *node, u64 item_size);
|
void dblListPushFront(WpDblList *list, WpDblNode *node, u64 item_size);
|
||||||
void _dblListPushBack(WpDblList *list, WpDblNode *node, u64 item_size);
|
void dblListPushBack(WpDblList *list, WpDblNode *node, u64 item_size);
|
||||||
void _dblListInsert(WpDblList *list, WpDblNode *node, u64 index, u64 item_size);
|
void dblListInsert(WpDblList *list, WpDblNode *node, u64 index, u64 item_size);
|
||||||
WpDblNode *_dblListPopFront(WpDblList *list, u64 item_size);
|
WpDblNode *dblListPopFront(WpDblList *list, u64 item_size);
|
||||||
WpDblNode *_dblListPopBack(WpDblList *list, u64 item_size);
|
WpDblNode *dblListPopBack(WpDblList *list, u64 item_size);
|
||||||
WpDblNode *_dblListRemove(WpDblList *list, u64 index, u64 item_size);
|
WpDblNode *dblListRemove(WpDblList *list, u64 index, u64 item_size);
|
||||||
void _dblListEmpty(WpDblList *list, u64 item_size);
|
void dblListEmpty(WpDblList *list, u64 item_size);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "hasher.h"
|
||||||
|
#include "../../../common/assert/assert.h"
|
||||||
|
|
||||||
|
WpHasher wpCustomHasher(WpHashFunc func, void *ctx) {
|
||||||
|
return (WpHasher){
|
||||||
|
.func = func,
|
||||||
|
.ctx = (WpHasherCtx){
|
||||||
|
.type = WP_HASHER_CTX_USER_DEFINED,
|
||||||
|
.user = ctx,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
WpU128 wpHasherGetHash128(const WpHasher *hasher, WpU8Stream *stream) {
|
||||||
|
wpDebugAssert(hasher != NULL && stream != NULL, "hasher and stream shouldn't be NULL");
|
||||||
|
return hasher->func(stream, hasher->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 wpHasherGetHash64(const WpHasher *hasher, WpU8Stream *stream) {
|
||||||
|
wpDebugAssert(hasher != NULL && stream != NULL, "hasher and stream shouldn't be NULL");
|
||||||
|
WpU128 result = hasher->func(stream, hasher->ctx);
|
||||||
|
return result.value[0] ^ result.value[1];
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#ifndef HASHER_H
|
||||||
|
#define HASHER_H
|
||||||
|
|
||||||
|
#include "../../stream/stream.h"
|
||||||
|
#include "../../../common/aliases/aliases.h"
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
BEGIN_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
typedef struct WpU128 {
|
||||||
|
u64 value[2];
|
||||||
|
} WpU128;
|
||||||
|
|
||||||
|
typedef enum WpHasherCtxType {
|
||||||
|
WP_HASHER_CTX_MURMUR3,
|
||||||
|
WP_HASHER_CTX_SIPHASH,
|
||||||
|
WP_HASHER_CTX_USER_DEFINED,
|
||||||
|
|
||||||
|
COUNT_HASHER_CTX,
|
||||||
|
} WpHasherCtxType;
|
||||||
|
|
||||||
|
typedef struct WpSiphashCtx {
|
||||||
|
WpU128 key;
|
||||||
|
u64 compression;
|
||||||
|
u64 finalisation;
|
||||||
|
} WpSiphashCtx;
|
||||||
|
|
||||||
|
typedef struct WpHasherCtx {
|
||||||
|
WpHasherCtxType type;
|
||||||
|
union {
|
||||||
|
WpSiphashCtx siphash;
|
||||||
|
void *user;
|
||||||
|
u32 murmur3;
|
||||||
|
};
|
||||||
|
} WpHasherCtx;
|
||||||
|
|
||||||
|
typedef WpU128 (*WpHashFunc)(WpU8Stream *stream, WpHasherCtx ctx);
|
||||||
|
|
||||||
|
typedef struct WpHasher {
|
||||||
|
WpHashFunc func;
|
||||||
|
WpHasherCtx ctx;
|
||||||
|
} WpHasher;
|
||||||
|
|
||||||
|
WpHasher wpCustomHasher(WpHashFunc func, void *ctx);
|
||||||
|
WpU128 wpHasherGetHash128(const WpHasher *hasher, WpU8Stream *stream);
|
||||||
|
u64 wpHasherGetHash64(const WpHasher *hasher, WpU8Stream *stream);
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
END_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
#endif // !HASHER_H
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "murmur3.h"
|
||||||
|
#include "hasher.h"
|
||||||
|
#include "../../../common/aliases/aliases.h"
|
||||||
|
#include "../../../common/assert/assert.h"
|
||||||
|
#include "../../../common/misc/misc_utils.h"
|
||||||
|
#include "../../../prng/xorshift/xorshift.h"
|
||||||
|
|
||||||
|
wp_intern inline void validateMur3HasherCtx(const WpHasherCtx *ctx);
|
||||||
|
wp_intern inline u64 fmix64(u64 k);
|
||||||
|
|
||||||
|
WpHasher wpX64Mur3Hasher(void) {
|
||||||
|
WpXor256State state = wpPrngXorshiftInit();
|
||||||
|
u32 seed = (u32)wpPrngXorshift256(&state);
|
||||||
|
return wpX64Mur3HasherWithSeed(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHasher wpX64Mur3HasherWithSeed(u32 seed) {
|
||||||
|
return (WpHasher){
|
||||||
|
.func = wpX64Mur3GetHash128,
|
||||||
|
.ctx = (WpHasherCtx){
|
||||||
|
.type = WP_HASHER_CTX_MURMUR3,
|
||||||
|
.murmur3 = seed,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
WpU128 wpX64Mur3GetHash128(WpU8Stream *bytes, WpHasherCtx ctx) {
|
||||||
|
validateMur3HasherCtx(&ctx);
|
||||||
|
|
||||||
|
const i32 nblocks = (bytes->count * bytes->item_size) / 16;
|
||||||
|
|
||||||
|
u64 h1 = ctx.murmur3;
|
||||||
|
u64 h2 = ctx.murmur3;
|
||||||
|
|
||||||
|
const u64 c1 = wpU64Const(0x87c37b91114253d5);
|
||||||
|
const u64 c2 = wpU64Const(0x4cf5ad432745937f);
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// body
|
||||||
|
|
||||||
|
for(int i = 0; i < nblocks; ++i) {
|
||||||
|
u64 k1 = *((u64 *)wpStreamConsumeCount(u8, bytes, sizeof(u64)));
|
||||||
|
u64 k2 = *((u64 *)wpStreamConsumeCount(u8, bytes, sizeof(u64)));
|
||||||
|
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = wpMiscUtilsRotl64(k1, 31);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
|
|
||||||
|
h1 = wpMiscUtilsRotl64(h1, 27);
|
||||||
|
h1 += h2;
|
||||||
|
h1 = h1 * 5 +0x52dce729;
|
||||||
|
|
||||||
|
k2 *= c2;
|
||||||
|
k2 = wpMiscUtilsRotl64(k2, 33);
|
||||||
|
k2 *= c1;
|
||||||
|
h2 ^= k2;
|
||||||
|
|
||||||
|
h2 = wpMiscUtilsRotl64(h2, 31);
|
||||||
|
h2 += h1;
|
||||||
|
h2 = h2*5+0x38495ab5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// tail
|
||||||
|
|
||||||
|
const u8 *tail = wpStreamConsumeCount(u8, bytes, bytes->count - bytes->position);
|
||||||
|
|
||||||
|
u64 k1 = 0;
|
||||||
|
u64 k2 = 0;
|
||||||
|
|
||||||
|
u64 len = bytes->count * bytes->item_size;
|
||||||
|
|
||||||
|
switch(len & 15) {
|
||||||
|
case 15: k2 ^= ((u64)tail[14]) << 48;
|
||||||
|
case 14: k2 ^= ((u64)tail[13]) << 40;
|
||||||
|
case 13: k2 ^= ((u64)tail[12]) << 32;
|
||||||
|
case 12: k2 ^= ((u64)tail[11]) << 24;
|
||||||
|
case 11: k2 ^= ((u64)tail[10]) << 16;
|
||||||
|
case 10: k2 ^= ((u64)tail[ 9]) << 8;
|
||||||
|
case 9: k2 ^= ((u64)tail[ 8]) << 0;
|
||||||
|
k2 *= c2; k2 = wpMiscUtilsRotl64(k2,33); k2 *= c1; h2 ^= k2;
|
||||||
|
|
||||||
|
case 8: k1 ^= ((u64)tail[ 7]) << 56;
|
||||||
|
case 7: k1 ^= ((u64)tail[ 6]) << 48;
|
||||||
|
case 6: k1 ^= ((u64)tail[ 5]) << 40;
|
||||||
|
case 5: k1 ^= ((u64)tail[ 4]) << 32;
|
||||||
|
case 4: k1 ^= ((u64)tail[ 3]) << 24;
|
||||||
|
case 3: k1 ^= ((u64)tail[ 2]) << 16;
|
||||||
|
case 2: k1 ^= ((u64)tail[ 1]) << 8;
|
||||||
|
case 1: k1 ^= ((u64)tail[ 0]) << 0;
|
||||||
|
k1 *= c1; k1 = wpMiscUtilsRotl64(k1,31); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// finalization
|
||||||
|
|
||||||
|
h1 ^= len; h2 ^= len;
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
h1 = fmix64(h1);
|
||||||
|
h2 = fmix64(h2);
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
return (WpU128){ .value = { [0] = h1, [1] = h2 } };
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_intern inline void validateMur3HasherCtx(const WpHasherCtx *ctx) {
|
||||||
|
wpRuntimeAssert(ctx->type == WP_HASHER_CTX_MURMUR3, "Invalid Murmur3 hash context");
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_intern inline u64 fmix64(u64 k) {
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= wpU64Const(0xff51afd7ed558ccd);
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= wpU64Const(0xc4ceb9fe1a85ec53);
|
||||||
|
k ^= k >> 33;
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of the x64 128-bit variant of the MurmurHash3 algorithm
|
||||||
|
* based on https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MURMUR3_H
|
||||||
|
#define MURMUR3_H
|
||||||
|
|
||||||
|
#include "hasher.h"
|
||||||
|
#include "../../stream/stream.h"
|
||||||
|
#include "../../../common/aliases/aliases.h"
|
||||||
|
#include "../../../common/platform/platform.h"
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
BEGIN_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
WpHasher wpX64Mur3Hasher(void);
|
||||||
|
WpHasher wpX64Mur3HasherWithSeed(u32 seed);
|
||||||
|
WpU128 wpX64Mur3GetHash128(WpU8Stream *bytes, WpHasherCtx ctx);
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
END_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
#endif // !MURMUR3_H
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "siphash.h"
|
||||||
|
#include "hasher.h"
|
||||||
|
#include "../../../common/aliases/aliases.h"
|
||||||
|
#include "../../../common/assert/assert.h"
|
||||||
|
#include "../../../common/misc/misc_utils.h"
|
||||||
|
#include "../../../prng/xorshift/xorshift.h"
|
||||||
|
|
||||||
|
wp_intern inline void siphash(WpStream *bytes, const WpHasherCtx *ctx, u8 *out, u64 outlen);
|
||||||
|
wp_intern inline void validateSipHasherCtx(const WpHasherCtx *ctx);
|
||||||
|
wp_intern inline b8 checkRounds(const WpHasherCtx *ctx);
|
||||||
|
|
||||||
|
#define _u32To8LE(p, v) \
|
||||||
|
(p)[0] = (u8)((v)); \
|
||||||
|
(p)[1] = (u8)((v) >> 8); \
|
||||||
|
(p)[2] = (u8)((v) >> 16); \
|
||||||
|
(p)[3] = (u8)((v) >> 24);
|
||||||
|
|
||||||
|
#define _u64To8LE(p, v) \
|
||||||
|
_u32To8LE((p), (u32)((v))); \
|
||||||
|
_u32To8LE((p) + 4, (u32)((v) >> 32));
|
||||||
|
|
||||||
|
#define _u8To64LE(p) \
|
||||||
|
(((u64)((p)[0])) | ((u64)((p)[1]) << 8) | \
|
||||||
|
((u64)((p)[2]) << 16) | ((u64)((p)[3]) << 24) | \
|
||||||
|
((u64)((p)[4]) << 32) | ((u64)((p)[5]) << 40) | \
|
||||||
|
((u64)((p)[6]) << 48) | ((u64)((p)[7]) << 56))
|
||||||
|
|
||||||
|
#define _sipRound \
|
||||||
|
do { \
|
||||||
|
v0 += v1; \
|
||||||
|
v1 = wpMiscUtilsRotl64(v1, 13); \
|
||||||
|
v1 ^= v0; \
|
||||||
|
v0 = wpMiscUtilsRotl64(v0, 32); \
|
||||||
|
v2 += v3; \
|
||||||
|
v3 = wpMiscUtilsRotl64(v3, 16); \
|
||||||
|
v3 ^= v2; \
|
||||||
|
v0 += v3; \
|
||||||
|
v3 = wpMiscUtilsRotl64(v3, 21); \
|
||||||
|
v3 ^= v0; \
|
||||||
|
v2 += v1; \
|
||||||
|
v1 = wpMiscUtilsRotl64(v1, 17); \
|
||||||
|
v1 ^= v2; \
|
||||||
|
v2 = wpMiscUtilsRotl64(v2, 32); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
WpHasher wpSip24Hasher(void) {
|
||||||
|
WpXor256State state = wpPrngXorshiftInit();
|
||||||
|
WpU128 key = { .value = { wpPrngXorshift256(&state), wpPrngXorshift256(&state) } };
|
||||||
|
return wpSip24HasherWithKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHasher wpSip48Hasher(void) {
|
||||||
|
WpXor256State state = wpPrngXorshiftInit();
|
||||||
|
WpU128 key = { .value = { wpPrngXorshift256(&state), wpPrngXorshift256(&state) } };
|
||||||
|
return wpSip48HasherWithKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHasher wpSip24HasherWithKey(WpU128 key) {
|
||||||
|
return (WpHasher){
|
||||||
|
.func = wpSipGetHash128,
|
||||||
|
.ctx = (WpHasherCtx){
|
||||||
|
.type = WP_HASHER_CTX_SIPHASH,
|
||||||
|
.siphash = (WpSiphashCtx){ .key = key, .compression = 2, .finalisation = 4 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHasher wpSip48HasherWithKey(WpU128 key) {
|
||||||
|
return (WpHasher){
|
||||||
|
.func = wpSipGetHash128,
|
||||||
|
.ctx = (WpHasherCtx){
|
||||||
|
.type = WP_HASHER_CTX_SIPHASH,
|
||||||
|
.siphash = (WpSiphashCtx){ .key = key, .compression = 4, .finalisation = 8 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
WpU128 wpSipGetHash128(WpStream *bytes, WpHasherCtx ctx) {
|
||||||
|
validateSipHasherCtx(&ctx);
|
||||||
|
WpU128 output = {0};
|
||||||
|
siphash(bytes, &ctx, (u8 *)&output.value, sizeof(u64) * 2);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the 128-variant of the siphash algorithm
|
||||||
|
*/
|
||||||
|
wp_intern inline void siphash(WpStream *bytes, const WpHasherCtx *ctx, u8 *out, u64 outlen) {
|
||||||
|
const u8 *kk = (const u8 *)&ctx->siphash.key;
|
||||||
|
u64 inlen = bytes->count * bytes->item_size;
|
||||||
|
|
||||||
|
wpRuntimeAssert(outlen == 16, "outlen should be 16");
|
||||||
|
|
||||||
|
u64 v0 = wpU64Const(0x736f6d6570736575);
|
||||||
|
u64 v1 = wpU64Const(0x646f72616e646f6d);
|
||||||
|
u64 v2 = wpU64Const(0x6c7967656e657261);
|
||||||
|
u64 v3 = wpU64Const(0x7465646279746573);
|
||||||
|
u64 k0 = _u8To64LE(kk);
|
||||||
|
u64 k1 = _u8To64LE(kk + 8);
|
||||||
|
u64 m;
|
||||||
|
u64 i;
|
||||||
|
const i32 left = inlen & 7;
|
||||||
|
u64 b = ((u64)inlen) << 56;
|
||||||
|
v3 ^= k1;
|
||||||
|
v2 ^= k0;
|
||||||
|
v1 ^= k1;
|
||||||
|
v0 ^= k0;
|
||||||
|
|
||||||
|
v1 ^= 0xee;
|
||||||
|
|
||||||
|
u8 *data;
|
||||||
|
while (wpStreamHasCount(bytes, sizeof(u64))) {
|
||||||
|
data = wpStreamConsumeCount(u8, bytes, sizeof(u64));
|
||||||
|
m = _u8To64LE(data);
|
||||||
|
v3 ^= m;
|
||||||
|
|
||||||
|
for (i = 0; i < ctx->siphash.compression; ++i) {
|
||||||
|
_sipRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
v0 ^= m;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = wpStreamConsume(u8, bytes);
|
||||||
|
switch (left) {
|
||||||
|
case 7:
|
||||||
|
b |= ((u64)data[6]) << 48;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 6:
|
||||||
|
b |= ((u64)data[5]) << 40;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 5:
|
||||||
|
b |= ((u64)data[4]) << 32;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 4:
|
||||||
|
b |= ((u64)data[3]) << 24;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 3:
|
||||||
|
b |= ((u64)data[2]) << 16;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 2:
|
||||||
|
b |= ((u64)data[1]) << 8;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 1:
|
||||||
|
b |= ((u64)data[0]);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
v3 ^= b;
|
||||||
|
|
||||||
|
for (i = 0; i < ctx->siphash.compression; ++i) {
|
||||||
|
_sipRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
v0 ^= b;
|
||||||
|
|
||||||
|
v2 ^= 0xee;
|
||||||
|
|
||||||
|
for (i = 0; i < ctx->siphash.finalisation; ++i) {
|
||||||
|
_sipRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
b = v0 ^ v1 ^ v2 ^ v3;
|
||||||
|
_u64To8LE(out, b);
|
||||||
|
|
||||||
|
v1 ^= 0xdd;
|
||||||
|
|
||||||
|
for (i = 0; i < ctx->siphash.finalisation; ++i) {
|
||||||
|
_sipRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
b = v0 ^ v1 ^ v2 ^ v3;
|
||||||
|
_u64To8LE(out + 8, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_intern inline void validateSipHasherCtx(const WpHasherCtx *ctx) {
|
||||||
|
b8 magic_match = ctx->type == WP_HASHER_CTX_SIPHASH;
|
||||||
|
b8 rounds = checkRounds(ctx);
|
||||||
|
wpRuntimeAssert(magic_match && rounds, "Invalid Siphash context");
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_intern inline b8 checkRounds(const WpHasherCtx *ctx) {
|
||||||
|
b8 rounds24 = ctx->siphash.compression == 2 && ctx->siphash.finalisation == 4;
|
||||||
|
b8 rounds48 = ctx->siphash.compression == 4 && ctx->siphash.finalisation == 8;
|
||||||
|
return rounds24 || rounds48;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementations of the SipHash-2-4-128, SipHash4-8-128 algorithms based on
|
||||||
|
* https://github.com/veorq/SipHash/blob/master/siphash.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SIPHASH_H
|
||||||
|
#define SIPHASH_H
|
||||||
|
|
||||||
|
#include "hasher.h"
|
||||||
|
#include "../../stream/stream.h"
|
||||||
|
#include "../../../common/platform/platform.h"
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
BEGIN_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
WpHasher wpSip24Hasher(void);
|
||||||
|
WpHasher wpSip48Hasher(void);
|
||||||
|
WpHasher wpSip24HasherWithKey(WpU128 key);
|
||||||
|
WpHasher wpSip48HasherWithKey(WpU128 key);
|
||||||
|
WpU128 wpSipGetHash128(WpU8Stream *bytes, WpHasherCtx ctx);
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
END_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
#endif // !SIPHASH_H
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "map.h"
|
||||||
|
#include "../table/table.h"
|
||||||
|
|
||||||
|
WpHashMap hashMapAlloc(const WpAllocator *allocator, WpU8StreamEncoder encoder, WpKeyEqualTest key_eq,
|
||||||
|
u64 capacity, u64 key_size, u64 value_size) {
|
||||||
|
return hashMapAllocWithCustomHasher(allocator, WP_HASH_TABLE_DEFAULT_HASHER, encoder, key_eq,
|
||||||
|
capacity, key_size, value_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashMap hashMapAllocWithCustomHasher(const WpAllocator *allocator, WpHasher hasher,
|
||||||
|
WpU8StreamEncoder encoder, WpKeyEqualTest key_eq,
|
||||||
|
u64 capacity, u64 key_size, u64 value_size) {
|
||||||
|
WpHashMap map = {0};
|
||||||
|
hashTableAlloc(allocator, &map, hasher, encoder, key_eq, capacity, key_size, value_size, true);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashLookupResult hashMapFind(WpHashMap *map, void *key, u64 key_size) {
|
||||||
|
u64 hash = hashTableCalcHash(map, key, key_size);
|
||||||
|
WpHashBucketRef ref = hashTableBucketRef(map, hash);
|
||||||
|
return hashTableLookup(map, key, ref, key_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashMapUpdate(WpHashMap *map, void *key, void *value, u64 key_size, u64 value_size) {
|
||||||
|
WpHashLookupResult result = hashMapFind(map, key, key_size);
|
||||||
|
if (result.found) {
|
||||||
|
hashTableUpdate(map, value, result.ref, value_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashMapInsertCapped(WpHashMap *map, void *key, void *value, u64 key_size, u64 value_size) {
|
||||||
|
WpHashLookupResult result = hashMapFind(map, key, key_size);
|
||||||
|
if (!result.found && map->load_factor < WP_HASH_MAX_LOAD_FACTOR) {
|
||||||
|
hashTableInsert(map, key, value, result.ref, key_size, value_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashMapInsertOrUpdateCapped(WpHashMap *map, void *key, void *value, u64 key_size, u64 value_size) {
|
||||||
|
WpHashLookupResult result = hashMapFind(map, key, key_size);
|
||||||
|
if (result.found) {
|
||||||
|
hashTableUpdate(map, value, result.ref, value_size);
|
||||||
|
} else if (map->load_factor < WP_HASH_MAX_LOAD_FACTOR) {
|
||||||
|
hashTableInsert(map, key, value, result.ref, key_size, value_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashMapInsertAlloc(const WpAllocator *allocator, WpHashMap *map, void *key, void *value,
|
||||||
|
u64 key_size, u64 value_size) {
|
||||||
|
WpHashLookupResult result = hashMapFind(map, key, key_size);
|
||||||
|
if (!result.found) {
|
||||||
|
if (map->load_factor >= WP_HASH_MAX_LOAD_FACTOR) {
|
||||||
|
hashTableGrow(allocator, map, key_size, value_size);
|
||||||
|
// Rerun key lookup after growing
|
||||||
|
result = hashMapFind(map, key, key_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashTableInsert(map, key, value, result.ref, key_size, value_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashMapInsertOrUpdateAlloc(const WpAllocator *allocator, WpHashMap *map, void *key, void *value,
|
||||||
|
u64 key_size, u64 value_size) {
|
||||||
|
WpHashLookupResult result = hashMapFind(map, key, key_size);
|
||||||
|
if (result.found) {
|
||||||
|
hashTableUpdate(map, value, result.ref, value_size);
|
||||||
|
} else {
|
||||||
|
if (map->load_factor >= WP_HASH_MAX_LOAD_FACTOR) {
|
||||||
|
hashTableGrow(allocator, map, key_size, value_size);
|
||||||
|
// Rerun key lookup after growing
|
||||||
|
result = hashMapFind(map, key, key_size);
|
||||||
|
}
|
||||||
|
hashTableInsert(map, key, value, result.ref, key_size, value_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashMapRemove(WpHashMap *map, void *key, u64 key_size, u64 value_size) {
|
||||||
|
WpHashLookupResult result = hashMapFind(map, key, key_size);
|
||||||
|
if (result.found) {
|
||||||
|
hashTableRemove(map, result.ref, key_size, value_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#ifndef MAP_H
|
||||||
|
#define MAP_H
|
||||||
|
|
||||||
|
#include "../table/table.h"
|
||||||
|
#include "../../../common/misc/misc_utils.h"
|
||||||
|
#include "../../../common/platform/platform.h"
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
BEGIN_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
typedef WpHashTable WpHashMap;
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
#define wpHashMap(KEY_TYPE, VALUE_TYPE, U8_STREAM_ENCODER, KEY_EQ_TEST, CAPACITY) \
|
||||||
|
(WpHashMap{ \
|
||||||
|
WP_HASH_TABLE_DEFAULT_HASHER, \
|
||||||
|
U8_STREAM_ENCODER, \
|
||||||
|
KEY_EQ_TEST, \
|
||||||
|
wpArrayWithCapacity(KEY_TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_NONE), \
|
||||||
|
wpArrayWithCapacity(VALUE_TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_NONE), \
|
||||||
|
wpArrayWithCapacity(WpHashBucket, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_FILLED), \
|
||||||
|
WP_HASH_TABLE_MAGIC, \
|
||||||
|
wpMiscUtilsU64RoundUpPow2(CAPACITY) - 1, \
|
||||||
|
0.0f, \
|
||||||
|
true, \
|
||||||
|
})
|
||||||
|
#define wpHashMapCustomHasher(KEY_TYPE, VALUE_TYPE, HASHER, U8_STREAM_ENCODER, KEY_EQ_TEST, \
|
||||||
|
CAPACITY) \
|
||||||
|
(WpHashMap{ \
|
||||||
|
HASHER, \
|
||||||
|
U8_STREAM_ENCODER, \
|
||||||
|
KEY_EQ_TEST, \
|
||||||
|
wpArrayWithCapacity(KEY_TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_NONE), \
|
||||||
|
wpArrayWithCapacity(VALUE_TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_NONE), \
|
||||||
|
wpArrayWithCapacity(WpHashBucket, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_FILLED), \
|
||||||
|
WP_HASH_TABLE_MAGIC, \
|
||||||
|
wpMiscUtilsU64RoundUpPow2(CAPACITY) - 1, \
|
||||||
|
0.0f, \
|
||||||
|
true, \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
#define wpHashMap(KEY_TYPE, VALUE_TYPE, U8_STREAM_ENCODER, KEY_EQ_TEST, CAPACITY) \
|
||||||
|
((WpHashMap){ \
|
||||||
|
.hasher = WP_HASH_TABLE_DEFAULT_HASHER, \
|
||||||
|
.encoder = U8_STREAM_ENCODER, \
|
||||||
|
.key_eq = KEY_EQ_TEST, \
|
||||||
|
.keys = wpArrayWithCapacity(KEY_TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_NONE), \
|
||||||
|
.values = wpArrayWithCapacity(VALUE_TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_NONE), \
|
||||||
|
.buckets = wpArrayWithCapacity(WpHashBucket, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_FILLED), \
|
||||||
|
.magic = WP_HASH_TABLE_MAGIC, \
|
||||||
|
.bucket_mask = wpMiscUtilsU64RoundUpPow2(CAPACITY) - 1, \
|
||||||
|
.has_values = true, \
|
||||||
|
})
|
||||||
|
#define wpHashMapCustomHasher(KEY_TYPE, VALUE_TYPE, HASHER, U8_STREAM_ENCODER, KEY_EQ_TEST, \
|
||||||
|
CAPACITY) \
|
||||||
|
((WpHashMap){ \
|
||||||
|
.hasher = HASHER, \
|
||||||
|
.encoder = U8_STREAM_ENCODER, \
|
||||||
|
.key_eq = KEY_EQ_TEST, \
|
||||||
|
.keys = wpArrayWithCapacity(KEY_TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_NONE), \
|
||||||
|
.values = wpArrayWithCapacity(VALUE_TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_NONE), \
|
||||||
|
.buckets = wpArrayWithCapacity(WpHashBucket, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_FILLED), \
|
||||||
|
.magic = WP_HASH_TABLE_MAGIC, \
|
||||||
|
.bucket_mask = wpMiscUtilsU64RoundUpPow2(CAPACITY) - 1, \
|
||||||
|
.has_values = true, \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define wpHashMapAlloc(KEY_TYPE, VALUE_TYPE, ALLOCATOR_PTR, U8_STREAM_ENCODER, KEY_EQ_TEST, \
|
||||||
|
CAPACITY) \
|
||||||
|
hashMapAlloc(ALLOCATOR_PTR, U8_STREAM_ENCODER, KEY_EQ_TEST, CAPACITY, sizeof(KEY_TYPE), \
|
||||||
|
sizeof(VALUE_TYPE))
|
||||||
|
#define wpHashMapCustomHasherAlloc(KEY_TYPE, VALUE_TYPE, ALLOCATOR_PTR, HASHER, U8_STREAM_ENCODER, \
|
||||||
|
KEY_EQ_TEST, CAPACITY) \
|
||||||
|
hashMapAllocWithCustomHasher(ALLOCATOR_PTR, HASHER, U8_STREAM_ENCODER, KEY_EQ_TEST, CAPACITY, \
|
||||||
|
sizeof(KEY_TYPE), sizeof(VALUE_TYPE))
|
||||||
|
#define wpHashMapKeys(KEY_TYPE, MAP_PTR) ((KEY_TYPE *)hashTableKeys(MAP_PTR, sizeof(KEY_TYPE)))
|
||||||
|
#define wpHashMapValues(VALUE_TYPE, MAP_PTR) \
|
||||||
|
((VALUE_TYPE *)hashTableValues(MAP_PTR, sizeof(VALUE_TYPE)))
|
||||||
|
#define wpHashMapCapacity(MAP_PTR) hashTableCapacity(MAP_PTR)
|
||||||
|
#define wpHashMapCount(MAP_PTR) hashTableCount(MAP_PTR)
|
||||||
|
#define wpHashMapKeySize(MAP_PTR) hashTableKeySize(MAP_PTR)
|
||||||
|
#define wpHashMapValueSize(MAP_PTR) hashTableValueSize(MAP_PTR)
|
||||||
|
#define wpHashMapFind(KEY_TYPE, MAP_PTR, KEY_PTR) hashMapFind(MAP_PTR, KEY_PTR, sizeof(KEY_TYPE))
|
||||||
|
#define wpHashMapInsertCapped(KEY_TYPE, VALUE_TYPE, MAP_PTR, KEY_PTR, VALUE_PTR) \
|
||||||
|
hashMapInsertCapped(MAP_PTR, KEY_PTR, VALUE_PTR, sizeof(KEY_TYPE), sizeof(VALUE_TYPE))
|
||||||
|
#define wpHashMapInsertOrUpdateCapped(KEY_TYPE, VALUE_TYPE, MAP_PTR, KEY_PTR, VALUE_PTR) \
|
||||||
|
hashMapInsertOrUpdateCapped(MAP_PTR, KEY_PTR, VALUE_PTR, sizeof(KEY_TYPE), sizeof(VALUE_TYPE))
|
||||||
|
#define wpHashMapUpdate(KEY_TYPE, VALUE_TYPE, MAP_PTR, KEY_PTR, VALUE_PTR) \
|
||||||
|
hashMapUpdate(MAP_PTR, KEY_PTR, VALUE_PTR, sizeof(KEY_TYPE), sizeof(VALUE_TYPE))
|
||||||
|
#define wpHashMapInsertAlloc(KEY_TYPE, VALUE_TYPE, ALLOCATOR_PTR, MAP_PTR, KEY_PTR, VALUE_PTR) \
|
||||||
|
hashMapInsertAlloc(ALLOCATOR_PTR, MAP_PTR, KEY_PTR, VALUE_PTR, sizeof(KEY_TYPE), \
|
||||||
|
sizeof(VALUE_TYPE))
|
||||||
|
#define wpHashMapInsertOrUpdateAlloc(KEY_TYPE, VALUE_TYPE, ALLOCATOR_PTR, MAP_PTR, KEY_PTR, \
|
||||||
|
VALUE_PTR) \
|
||||||
|
hashMapInsertOrUpdateAlloc(ALLOCATOR_PTR, MAP_PTR, KEY_PTR, VALUE_PTR, sizeof(KEY_TYPE), \
|
||||||
|
sizeof(VALUE_TYPE))
|
||||||
|
#define wpHashMapRemove(KEY_TYPE, VALUE_TYPE, MAP_PTR, KEY_PTR) \
|
||||||
|
hashMapRemove(MAP_PTR, KEY_PTR, sizeof(KEY_TYPE), sizeof(VALUE_TYPE))
|
||||||
|
#define wpHashMapClear(KEY_TYPE, VALUE_TYPE, MAP_PTR) \
|
||||||
|
hashTableClear(MAP_PTR, sizeof(KEY_TYPE), sizeof(VALUE_TYPE))
|
||||||
|
#define wpHashMapDealloc(KEY_TYPE, VALUE_TYPE, ALLOCATOR_PTR, MAP_PTR) \
|
||||||
|
hashTableDealloc(ALLOCATOR_PTR, MAP_PTR, sizeof(KEY_TYPE), sizeof(VALUE_TYPE))
|
||||||
|
|
||||||
|
WpHashMap hashMapAlloc(const WpAllocator *allocator, WpU8StreamEncoder encoder,
|
||||||
|
WpKeyEqualTest key_eq, u64 capacity, u64 key_size, u64 value_size);
|
||||||
|
WpHashMap hashMapAllocWithCustomHasher(const WpAllocator *allocator, WpHasher hasher,
|
||||||
|
WpU8StreamEncoder encoder, WpKeyEqualTest key_eq,
|
||||||
|
u64 capacity, u64 key_size, u64 value_size);
|
||||||
|
WpHashLookupResult hashMapFind(WpHashMap *map, void *key, u64 key_size);
|
||||||
|
void hashMapUpdate(WpHashMap *map, void *key, void *value, u64 key_size, u64 value_size);
|
||||||
|
void hashMapInsertCapped(WpHashMap *map, void *key, void *value, u64 key_size, u64 value_size);
|
||||||
|
void hashMapInsertOrUpdateCapped(WpHashMap *map, void *key, void *value, u64 key_size,
|
||||||
|
u64 value_size);
|
||||||
|
void hashMapInsertAlloc(const WpAllocator *allocator, WpHashMap *map, void *key,
|
||||||
|
void *value, u64 key_size, u64 value_size);
|
||||||
|
void hashMapInsertOrUpdateAlloc(const WpAllocator *allocator, WpHashMap *map, void *key,
|
||||||
|
void *value, u64 key_size, u64 value_size);
|
||||||
|
void hashMapRemove(WpHashMap *map, void *key, u64 key_size, u64 value_size);
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
END_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
#endif // !MAP_H
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "set.h"
|
||||||
|
#include "../table/table.h"
|
||||||
|
|
||||||
|
WpHashSet hashSetAlloc(const WpAllocator *allocator, WpU8StreamEncoder encoder, WpKeyEqualTest key_eq,
|
||||||
|
u64 capacity, u64 key_size) {
|
||||||
|
return hashSetAllocWithCustomHasher(allocator, WP_HASH_TABLE_DEFAULT_HASHER, encoder, key_eq,
|
||||||
|
capacity, key_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashSet hashSetAllocWithCustomHasher(const WpAllocator *allocator, WpHasher hasher,
|
||||||
|
WpU8StreamEncoder encoder, WpKeyEqualTest key_eq, u64 capacity,
|
||||||
|
u64 key_size) {
|
||||||
|
WpHashSet set = {0};
|
||||||
|
hashTableAlloc(allocator, &set, hasher, encoder, key_eq, capacity, key_size, 0, false);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashLookupResult hashSetFind(WpHashSet *set, void *item, u64 item_size) {
|
||||||
|
u64 hash = hashTableCalcHash(set, item, item_size);
|
||||||
|
WpHashBucketRef ref = hashTableBucketRef(set, hash);
|
||||||
|
return hashTableLookup(set, item, ref, item_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashSetInsertCapped(WpHashSet *set, void *item, u64 item_size) {
|
||||||
|
WpHashLookupResult result = hashSetFind(set, item, item_size);
|
||||||
|
if (!result.found && set->load_factor < WP_HASH_MAX_LOAD_FACTOR) {
|
||||||
|
hashTableInsert(set, item, NULL, result.ref, item_size, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashSetInsertAlloc(const WpAllocator *allocator, WpHashSet *set, void *item, u64 item_size) {
|
||||||
|
WpHashLookupResult result = hashSetFind(set, item, item_size);
|
||||||
|
if (!result.found) {
|
||||||
|
if (set->load_factor >= WP_HASH_MAX_LOAD_FACTOR) {
|
||||||
|
hashTableGrow(allocator, set, item_size, 0);
|
||||||
|
// Rerun item lookup after growing
|
||||||
|
result = hashSetFind(set, item, item_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashTableInsert(set, item, NULL, result.ref, item_size, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashSetRemove(WpHashSet *set, void *item, u64 item_size) {
|
||||||
|
WpHashLookupResult result = hashSetFind(set, item, item_size);
|
||||||
|
if (result.found) {
|
||||||
|
hashTableRemove(set, result.ref, item_size, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#ifndef SET_H
|
||||||
|
#define SET_H
|
||||||
|
|
||||||
|
#include "../table/table.h"
|
||||||
|
#include "../../../common/misc/misc_utils.h"
|
||||||
|
#include "../../../common/platform/platform.h"
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
BEGIN_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
typedef WpHashTable WpHashSet;
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
#define wpHashSet(TYPE, U8_STREAM_ENCODER, ITEM_EQ_TEST, CAPACITY) \
|
||||||
|
(WpHashSet{ \
|
||||||
|
WP_HASH_TABLE_DEFAULT_HASHER, \
|
||||||
|
U8_STREAM_ENCODER, \
|
||||||
|
ITEM_EQ_TEST, \
|
||||||
|
wpArrayWithCapacity(TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_NONE), \
|
||||||
|
NULL, \
|
||||||
|
wpArrayWithCapacity(WpHashBucket, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_FILLED), \
|
||||||
|
WP_HASH_TABLE_MAGIC, \
|
||||||
|
wpMiscUtilsU64RoundUpPow2(CAPACITY) - 1, \
|
||||||
|
0.0f, \
|
||||||
|
false, \
|
||||||
|
})
|
||||||
|
#define wpHashSetCustomHasher(TYPE, HASHER, U8_STREAM_ENCODER, ITEM_EQ_TEST, CAPACITY) \
|
||||||
|
(WpHashSet{ \
|
||||||
|
HASHER, \
|
||||||
|
U8_STREAM_ENCODER, \
|
||||||
|
ITEM_EQ_TEST, \
|
||||||
|
wpArrayWithCapacity(TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_NONE), \
|
||||||
|
NULL, \
|
||||||
|
wpArrayWithCapacity(WpHashBucket, wpMiscUtilsU64RoundUpPow2(CAPACITY), WP_ARRAY_INIT_FILLED), \
|
||||||
|
WP_HASH_TABLE_MAGIC, \
|
||||||
|
wpMiscUtilsU64RoundUpPow2(CAPACITY) - 1, \
|
||||||
|
0.0f, \
|
||||||
|
false, \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
#define wpHashSet(TYPE, U8_STREAM_ENCODER, ITEM_EQ_TEST, CAPACITY) \
|
||||||
|
((WpHashSet){ \
|
||||||
|
.hasher = WP_HASH_TABLE_DEFAULT_HASHER, \
|
||||||
|
.encoder = U8_STREAM_ENCODER, \
|
||||||
|
.key_eq = ITEM_EQ_TEST, \
|
||||||
|
.keys = wpArrayWithCapacity(TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_NONE), \
|
||||||
|
.buckets = wpArrayWithCapacity(WpHashBucket, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_FILLED), \
|
||||||
|
.magic = WP_HASH_TABLE_MAGIC, \
|
||||||
|
.bucket_mask = wpMiscUtilsU64RoundUpPow2(CAPACITY) - 1, \
|
||||||
|
})
|
||||||
|
#define wpHashSetCustomHasher(TYPE, HASHER, U8_STREAM_ENCODER, ITEM_EQ_TEST, CAPACITY) \
|
||||||
|
((WpHashSet){ \
|
||||||
|
.hasher = HASHER, \
|
||||||
|
.encoder = U8_STREAM_ENCODER, \
|
||||||
|
.key_eq = ITEM_EQ_TEST, \
|
||||||
|
.keys = wpArrayWithCapacity(TYPE, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_NONE), \
|
||||||
|
.buckets = wpArrayWithCapacity(WpHashBucket, wpMiscUtilsU64RoundUpPow2(CAPACITY), \
|
||||||
|
WP_ARRAY_INIT_FILLED), \
|
||||||
|
.magic = WP_HASH_TABLE_MAGIC, \
|
||||||
|
.bucket_mask = wpMiscUtilsU64RoundUpPow2(CAPACITY) - 1, \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define wpHashSetAlloc(TYPE, ALLOCATOR_PTR, U8_STREAM_ENCODER, ITEM_EQ_TEST, CAPACITY) \
|
||||||
|
hashSetAlloc(ALLOCATOR_PTR, U8_STREAM_ENCODER, ITEM_EQ_TEST, CAPACITY, sizeof(TYPE))
|
||||||
|
#define wpHashSetCustomHasherAlloc(TYPE, ALLOCATOR_PTR, HASHER, U8_STREAM_ENCODER, ITEM_EQ_TEST, \
|
||||||
|
CAPACITY) \
|
||||||
|
hashSetAllocWithCustomHasher(ALLOCATOR_PTR, HASHER, U8_STREAM_ENCODER, ITEM_EQ_TEST, CAPACITY, \
|
||||||
|
sizeof(TYPE))
|
||||||
|
#define wpHashSetItems(TYPE, SET_PTR) ((TYPE *)hashTableKeys(SET_PTR, sizeof(TYPE)))
|
||||||
|
#define wpHashSetCapacity(SET_PTR) hashTableCapacity(SET_PTR)
|
||||||
|
#define wpHashSetCount(SET_PTR) hashTableCount(SET_PTR)
|
||||||
|
#define wpHashSetItemSize(SET_PTR) hashTableKeySize(SET_PTR)
|
||||||
|
#define wpHashSetFind(TYPE, SET_PTR, ITEM_PTR) hashSetFind(SET_PTR, ITEM_PTR, sizeof(TYPE))
|
||||||
|
#define wpHashSetInsertCapped(TYPE, SET_PTR, ITEM_PTR) \
|
||||||
|
hashSetInsertCapped(SET_PTR, ITEM_PTR, sizeof(TYPE))
|
||||||
|
#define wpHashSetInsertAlloc(TYPE, ALLOCATOR_PTR, SET_PTR, ITEM_PTR) \
|
||||||
|
hashSetInsertAlloc(ALLOCATOR_PTR, SET_PTR, ITEM_PTR, sizeof(TYPE))
|
||||||
|
#define wpHashSetRemove(TYPE, SET_PTR, ITEM_PTR) hashSetRemove(SET_PTR, ITEM_PTR, sizeof(TYPE))
|
||||||
|
#define wpHashSetClear(TYPE, SET_PTR) hashTableClear(SET_PTR, sizeof(TYPE), 0)
|
||||||
|
#define wpHashSetDealloc(TYPE, ALLOCATOR_PTR, SET_PTR) \
|
||||||
|
hashTableDealloc(ALLOCATOR_PTR, SET_PTR, sizeof(TYPE), 0)
|
||||||
|
|
||||||
|
WpHashSet hashSetAlloc(const WpAllocator *allocator, WpU8StreamEncoder encoder,
|
||||||
|
WpKeyEqualTest key_eq, u64 capacity, u64 key_size);
|
||||||
|
WpHashSet hashSetAllocWithCustomHasher(const WpAllocator *allocator, WpHasher hasher,
|
||||||
|
WpU8StreamEncoder encoder, WpKeyEqualTest key_eq,
|
||||||
|
u64 capacity, u64 key_size);
|
||||||
|
WpHashLookupResult hashSetFind(WpHashSet *set, void *item, u64 item_size);
|
||||||
|
void hashSetInsertCapped(WpHashSet *set, void *item, u64 item_size);
|
||||||
|
void hashSetInsertAlloc(const WpAllocator *allocator, WpHashSet *set, void *item,
|
||||||
|
u64 item_size);
|
||||||
|
void hashSetRemove(WpHashSet *set, void *item, u64 item_size);
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
END_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
#endif // !SET_H
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "table.h"
|
||||||
|
#include "../hasher/hasher.h"
|
||||||
|
#include "../../mem/allocator/mem_allocator.h"
|
||||||
|
#include "../../stream/stream.h"
|
||||||
|
#include "../../../common/aliases/aliases.h"
|
||||||
|
#include "../../../common/assert/assert.h"
|
||||||
|
#include "../../../common/misc/misc_utils.h"
|
||||||
|
|
||||||
|
wp_persist inline void *hashTableGetKeyFromBucket(WpHashTable *table, WpHashBucket bucket, u64 key_size);
|
||||||
|
wp_persist inline void *hashTableGetValueFromBucket(WpHashTable *table, WpHashBucket bucket, u64 value_size);
|
||||||
|
wp_persist inline u64 hashTableGetDist(u64 dist_and_tag);
|
||||||
|
wp_persist inline u64 hashTableNextBucket(WpHashTable *table, u64 bucket_index);
|
||||||
|
wp_persist inline u64 hashTableDistInc(u64 dist_and_tag);
|
||||||
|
wp_persist inline u64 hashTableDistDec(u64 dist_and_tag);
|
||||||
|
wp_persist inline void hashTableValidate(const WpHashTable *table, u64 key_size, u64 value_size);
|
||||||
|
|
||||||
|
void hashTableAlloc(const WpAllocator *allocator, WpHashTable *table, WpHasher hasher,
|
||||||
|
WpU8StreamEncoder encoder, WpKeyEqualTest key_eq, u64 capacity, u64 key_size,
|
||||||
|
u64 value_size, b8 has_values) {
|
||||||
|
wpDebugAssert(allocator != NULL && table != NULL && encoder != NULL && key_eq != NULL,
|
||||||
|
"`allocator`, `table`, `encoder` and `key_eq` should not be NULL");
|
||||||
|
|
||||||
|
u64 table_capacity = wpMiscUtilsU64RoundUpPow2(capacity);
|
||||||
|
table->hasher = hasher;
|
||||||
|
table->encoder = encoder;
|
||||||
|
table->key_eq = key_eq;
|
||||||
|
table->keys = arrayAllocCapacity(allocator, table_capacity, WP_ARRAY_INIT_NONE, key_size);;
|
||||||
|
table->buckets = wpArrayAllocCapacity(WpHashBucket, allocator, table_capacity, WP_ARRAY_INIT_FILLED);
|
||||||
|
table->magic = WP_HASH_TABLE_MAGIC;
|
||||||
|
table->bucket_mask = table_capacity - 1;
|
||||||
|
table->load_factor = WP_HASH_MAX_LOAD_FACTOR;
|
||||||
|
table->has_values = has_values;
|
||||||
|
|
||||||
|
wpRuntimeAssert(table->keys != NULL && table->buckets != NULL, "Failed to allocate keys, buckets or both");
|
||||||
|
|
||||||
|
if (has_values) {
|
||||||
|
table->values = arrayAllocCapacity(allocator, table_capacity, WP_ARRAY_INIT_NONE, value_size);;
|
||||||
|
wpRuntimeAssert(table->values != NULL, "Failed to allocate values");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 hashTableCalcHash(WpHashTable *table, void *key, u64 key_size) {
|
||||||
|
hashTableValidate(table, key_size, 0);
|
||||||
|
wpDebugAssert(key != NULL, "`key` should not be NULL");
|
||||||
|
WpU8Stream stream = table->encoder(key);
|
||||||
|
return wpHasherGetHash64(&table->hasher, &stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashBucketRef hashTableBucketRef(WpHashTable *table, u64 hash) {
|
||||||
|
hashTableValidate(table, 0, 0);
|
||||||
|
return (WpHashBucketRef){
|
||||||
|
.dist_and_tag = WP_HASH_DIST_INC | (hash & WP_HASH_TAG_MASK),
|
||||||
|
.bucket_index = hash & table->bucket_mask,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void *hashTableKeys(WpHashTable *table, u64 key_size) {
|
||||||
|
hashTableValidate(table, key_size, 0);
|
||||||
|
return table->keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *hashTableValues(WpHashTable *table, u64 value_size) {
|
||||||
|
hashTableValidate(table, 0, value_size);
|
||||||
|
return table->values;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *hashTableGetKeyFromBucketRef(WpHashTable *table, WpHashBucketRef ref, u64 key_size) {
|
||||||
|
return hashTableGetKeyFromBucket(table, table->buckets[ref.bucket_index], key_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *hashTableGetValueFromBucketRef(WpHashTable *table, WpHashBucketRef ref, u64 value_size) {
|
||||||
|
return hashTableGetValueFromBucket(table, table->buckets[ref.bucket_index], value_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 hashTableCapacity(WpHashTable *table) {
|
||||||
|
hashTableValidate(table, 0, 0);
|
||||||
|
return wpArrayCapacity(table->keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 hashTableCount(WpHashTable *table) {
|
||||||
|
hashTableValidate(table, 0, 0);
|
||||||
|
return wpArrayCount(table->keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 hashTableKeySize(WpHashTable *table) {
|
||||||
|
hashTableValidate(table, 0, 0);
|
||||||
|
return wpArrayItemSize(table->keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 hashTableValueSize(WpHashTable *table) {
|
||||||
|
hashTableValidate(table, 0, 0);
|
||||||
|
return table->has_values ? wpArrayItemSize(table->values) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashTableGrow(const WpAllocator *allocator, WpHashTable *table, u64 key_size, u64 value_size) {
|
||||||
|
hashTableValidate(table, key_size, value_size);
|
||||||
|
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
|
||||||
|
|
||||||
|
u64 capacity = wpMiscUtilsU64RoundUpPow2(hashTableCapacity(table) * 2);
|
||||||
|
u64 mask = capacity - wpU64Const(1);
|
||||||
|
WpArray keys = arrayAllocCapacity(allocator, capacity, WP_ARRAY_INIT_NONE, key_size);
|
||||||
|
WpArray values = NULL;
|
||||||
|
WpHashBucketArray buckets = wpArrayAllocCapacity(WpHashBucket, allocator, capacity, WP_ARRAY_INIT_FILLED);
|
||||||
|
|
||||||
|
wpRuntimeAssert(keys != NULL && buckets != NULL, "Failed to allocate keys, buckets or both");
|
||||||
|
|
||||||
|
if (table->has_values) {
|
||||||
|
values = arrayAllocCapacity(allocator, capacity, WP_ARRAY_INIT_NONE, value_size);
|
||||||
|
wpRuntimeAssert(values != NULL, "Failed to allocate values");
|
||||||
|
}
|
||||||
|
|
||||||
|
WpArray old_keys = table->keys;
|
||||||
|
WpArray old_values = table->values;
|
||||||
|
|
||||||
|
table->keys = keys;
|
||||||
|
table->values = values;
|
||||||
|
table->buckets = buckets;
|
||||||
|
table->bucket_mask = mask;
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(old_keys); ++i) {
|
||||||
|
void *key = arrayGet(old_keys, i, key_size);
|
||||||
|
void *value = table->has_values ? arrayGet(old_values, i, value_size) : NULL;
|
||||||
|
u64 hash = hashTableCalcHash(table, key, key_size);
|
||||||
|
WpHashBucketRef ref = hashTableBucketRef(table, hash);
|
||||||
|
hashTableInsert(table, key, value, ref, key_size, value_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashLookupResult hashTableLookup(WpHashTable *table, void *key, WpHashBucketRef ref, u64 key_size) {
|
||||||
|
hashTableValidate(table, key_size, 0);
|
||||||
|
wpDebugAssert(key != NULL, "`key` should not be NULL");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
WpHashBucket *bucket = &table->buckets[ref.bucket_index];
|
||||||
|
|
||||||
|
if (ref.dist_and_tag == bucket->dist_and_tag) {
|
||||||
|
b8 key_equal = table->key_eq(key, arrayGet(table->keys, bucket->item_index, key_size));
|
||||||
|
return (WpHashLookupResult){
|
||||||
|
.ref.dist_and_tag = ref.dist_and_tag,
|
||||||
|
.ref.bucket_index = ref.bucket_index,
|
||||||
|
.found = key_equal,
|
||||||
|
};
|
||||||
|
} else if (hashTableGetDist(ref.dist_and_tag) > hashTableGetDist(bucket->dist_and_tag)) {
|
||||||
|
return (WpHashLookupResult){
|
||||||
|
.ref.dist_and_tag = ref.dist_and_tag,
|
||||||
|
.ref.bucket_index = ref.bucket_index,
|
||||||
|
.found = false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ref.dist_and_tag = hashTableDistInc(ref.dist_and_tag);
|
||||||
|
ref.bucket_index = hashTableNextBucket(table, ref.bucket_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashTableUpdate(WpHashTable *table, void *value, WpHashBucketRef ref, u64 value_size) {
|
||||||
|
hashTableValidate(table, 0, value_size);
|
||||||
|
if (!(table->has_values)) {
|
||||||
|
wpRuntimeAssert(0, "Attempting to update a hash table that has no values");
|
||||||
|
}
|
||||||
|
wpDebugAssert(value != NULL, "`value` should not be NULL");
|
||||||
|
|
||||||
|
WpHashBucket *bucket = &table->buckets[ref.bucket_index];
|
||||||
|
arraySet(table->values, bucket->item_index, value, value_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashTableInsert(WpHashTable *table, void *key, void *value, WpHashBucketRef ref, u64 key_size,
|
||||||
|
u64 value_size) {
|
||||||
|
hashTableValidate(table, key_size, value_size);
|
||||||
|
wpDebugAssert(key != NULL, "`key` should not be NULL");
|
||||||
|
|
||||||
|
u64 index = wpArrayCount(table->keys);
|
||||||
|
while (true) {
|
||||||
|
WpHashBucket *bucket = &table->buckets[ref.bucket_index];
|
||||||
|
|
||||||
|
if (bucket->dist_and_tag == 0) {
|
||||||
|
bucket->dist_and_tag = ref.dist_and_tag;
|
||||||
|
bucket->item_index = index;
|
||||||
|
break;
|
||||||
|
} else if (hashTableGetDist(ref.dist_and_tag) > hashTableGetDist(bucket->dist_and_tag)) {
|
||||||
|
wpMiscUtilsSwap(u64, &ref.dist_and_tag, &bucket->dist_and_tag);
|
||||||
|
wpMiscUtilsSwap(u64, &index, &bucket->item_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
ref.dist_and_tag = hashTableDistInc(ref.dist_and_tag);
|
||||||
|
ref.bucket_index = hashTableNextBucket(table, ref.bucket_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayAppendCapped(table->keys, key, key_size);
|
||||||
|
if (table->has_values) {
|
||||||
|
arrayAppendCapped(table->values, value, value_size);
|
||||||
|
}
|
||||||
|
table->load_factor = (f32)wpArrayCount(table->keys) / (f32)wpArrayCapacity(table->keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashTableRemove(WpHashTable *table, WpHashBucketRef ref, u64 key_size, u64 value_size) {
|
||||||
|
hashTableValidate(table, key_size, value_size);
|
||||||
|
|
||||||
|
WpHashBucket *bucket = &table->buckets[ref.bucket_index];
|
||||||
|
|
||||||
|
u64 last_item_index = wpArrayCount(table->keys) - 1;
|
||||||
|
|
||||||
|
if (bucket->item_index < last_item_index) {
|
||||||
|
// Update the bucket for the last item before swapping
|
||||||
|
u64 hash = hashTableCalcHash(table, arrayGet(table->keys, last_item_index, key_size), key_size);
|
||||||
|
|
||||||
|
WpHashLookupResult result = hashTableLookup(table, arrayGet(table->keys, last_item_index, key_size),
|
||||||
|
hashTableBucketRef(table, hash), key_size);
|
||||||
|
wpRuntimeAssert(result.found, "Hash table item should exist but it doesn't");
|
||||||
|
|
||||||
|
table->buckets[result.ref.bucket_index].item_index = bucket->item_index;
|
||||||
|
|
||||||
|
arrayRemoveSwapEnd(table->keys, bucket->item_index, key_size);
|
||||||
|
if (table->has_values) {
|
||||||
|
arrayRemoveSwapEnd(table->values, bucket->item_index, value_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bucket->dist_and_tag > 0) {
|
||||||
|
u64 next_index = hashTableNextBucket(table, ref.bucket_index);
|
||||||
|
WpHashBucket *next = &table->buckets[next_index];
|
||||||
|
|
||||||
|
if (hashTableGetDist(next->dist_and_tag) > WP_HASH_DIST_INC) {
|
||||||
|
bucket->dist_and_tag = hashTableDistDec(next->dist_and_tag);
|
||||||
|
bucket->item_index = next->item_index;
|
||||||
|
|
||||||
|
ref.bucket_index = next_index;
|
||||||
|
bucket = &table->buckets[ref.bucket_index];
|
||||||
|
} else {
|
||||||
|
bucket->dist_and_tag = 0;
|
||||||
|
bucket->item_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashTableClear(WpHashTable *table, u64 key_size, u64 value_size) {
|
||||||
|
hashTableValidate(table, key_size, value_size);
|
||||||
|
arrayClear(table->keys, key_size);
|
||||||
|
if (table->has_values) {
|
||||||
|
arrayClear(table->values, value_size);
|
||||||
|
}
|
||||||
|
wpArrayZero(WpHashBucket, table->buckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashTableDealloc(const WpAllocator *allocator, WpHashTable *table, u64 key_size, u64 value_size) {
|
||||||
|
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
|
||||||
|
hashTableValidate(table, key_size, value_size);
|
||||||
|
arrayDealloc(allocator, table->keys, key_size);
|
||||||
|
wpArrayDealloc(WpHashBucket, allocator, table->buckets);
|
||||||
|
if (table->has_values) {
|
||||||
|
arrayDealloc(allocator, table->values, value_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline void *hashTableGetKeyFromBucket(WpHashTable *table, WpHashBucket bucket, u64 key_size) {
|
||||||
|
hashTableValidate(table, key_size, 0);
|
||||||
|
return arrayGet(table->keys, bucket.item_index, key_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline void *hashTableGetValueFromBucket(WpHashTable *table, WpHashBucket bucket, u64 value_size) {
|
||||||
|
hashTableValidate(table, 0, value_size);
|
||||||
|
return table->has_values ? arrayGet(table->values, bucket.item_index, value_size) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline u64 hashTableGetDist(u64 dist_and_tag) {
|
||||||
|
return dist_and_tag & (~WP_HASH_TAG_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline u64 hashTableNextBucket(WpHashTable *table, u64 bucket_index) {
|
||||||
|
return (++bucket_index) & table->bucket_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline u64 hashTableDistInc(u64 dist_and_tag) {
|
||||||
|
return dist_and_tag + WP_HASH_DIST_INC;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline u64 hashTableDistDec(u64 dist_and_tag) {
|
||||||
|
return dist_and_tag - WP_HASH_DIST_INC;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline void hashTableValidate(const WpHashTable *table, u64 key_size, u64 value_size) {
|
||||||
|
wpDebugAssert(table != NULL, "`table` should not be NULL");
|
||||||
|
wpRuntimeAssert(WP_HASH_TABLE_MAGIC == table->magic, "`table` is not a valid wapp hash table");
|
||||||
|
if (key_size > 0) {
|
||||||
|
wpRuntimeAssert(key_size == wpArrayItemSize(table->keys), "Invalid key type provided");
|
||||||
|
}
|
||||||
|
if (value_size > 0) {
|
||||||
|
wpRuntimeAssert(value_size == wpArrayItemSize(table->values), "Invalid value type provided");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hash table implementation with Robin Hood open addressing for collision resolution.
|
||||||
|
*
|
||||||
|
* The implementation is based on a version of this C++ implementation:
|
||||||
|
* https://github.com/martinus/unordered_dense
|
||||||
|
*
|
||||||
|
* Extra references:
|
||||||
|
* - https://faultlore.com/blah/robinhood-part-1/
|
||||||
|
* - https://blog.hieunt.me/blog/robinhood-hashing
|
||||||
|
*
|
||||||
|
* IMPORTANT:
|
||||||
|
* This is the internal hash table implementation and it is not intended to be used directly.
|
||||||
|
* Please check ../map/map.h and ../set/set.h for the public APIs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TABLE_H
|
||||||
|
#define TABLE_H
|
||||||
|
|
||||||
|
#include "../hasher/hasher.h"
|
||||||
|
#include "../hasher/murmur3.h"
|
||||||
|
#include "../../array/array.h"
|
||||||
|
#include "../../mem/allocator/mem_allocator.h"
|
||||||
|
#include "../../stream/stream.h"
|
||||||
|
#include "../../../common/aliases/aliases.h"
|
||||||
|
#include "../../../common/platform/platform.h"
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
BEGIN_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
#define WP_HASH_TABLE_MAGIC wpU64Const(0x57504854424c)
|
||||||
|
#define WP_HASH_TAG_BITS wpU64Const(32)
|
||||||
|
#define WP_HASH_DIST_INC (wpU64Const(1) << WP_HASH_TAG_BITS)
|
||||||
|
#define WP_HASH_TAG_MASK (WP_HASH_DIST_INC - wpU64Const(1))
|
||||||
|
#define WP_HASH_MAX_LOAD_FACTOR 0.65f
|
||||||
|
#define WP_HASH_TABLE_DEFAULT_HASHER wpX64Mur3Hasher()
|
||||||
|
|
||||||
|
typedef WpU8Stream (*WpU8StreamEncoder)(void *data);
|
||||||
|
typedef b8 (*WpKeyEqualTest)(void *a, void *b);
|
||||||
|
|
||||||
|
typedef struct WpHashBucket {
|
||||||
|
u64 dist_and_tag;
|
||||||
|
u64 item_index;
|
||||||
|
} WpHashBucket;
|
||||||
|
typedef WpHashBucket *WpHashBucketArray;
|
||||||
|
|
||||||
|
typedef struct WpHashTable {
|
||||||
|
WpHasher hasher;
|
||||||
|
WpU8StreamEncoder encoder;
|
||||||
|
WpKeyEqualTest key_eq;
|
||||||
|
WpArray keys;
|
||||||
|
WpArray values;
|
||||||
|
WpHashBucketArray buckets;
|
||||||
|
u64 magic;
|
||||||
|
u64 bucket_mask;
|
||||||
|
f32 load_factor;
|
||||||
|
b8 has_values;
|
||||||
|
} WpHashTable;
|
||||||
|
|
||||||
|
typedef struct WpHashBucketRef {
|
||||||
|
u64 dist_and_tag;
|
||||||
|
u64 bucket_index;
|
||||||
|
} WpHashBucketRef;
|
||||||
|
|
||||||
|
typedef struct WpHashLookupResult {
|
||||||
|
WpHashBucketRef ref;
|
||||||
|
b8 found;
|
||||||
|
} WpHashLookupResult;
|
||||||
|
|
||||||
|
void hashTableAlloc(const WpAllocator *allocator, WpHashTable *table,
|
||||||
|
WpHasher hasher, WpU8StreamEncoder encoder,
|
||||||
|
WpKeyEqualTest key_eq, u64 capacity, u64 key_size,
|
||||||
|
u64 value_size, b8 has_values);
|
||||||
|
u64 hashTableCalcHash(WpHashTable *table, void *key, u64 key_size);
|
||||||
|
WpHashBucketRef hashTableBucketRef(WpHashTable *table, u64 hash);
|
||||||
|
void *hashTableKeys(WpHashTable *table, u64 key_size);
|
||||||
|
void *hashTableValues(WpHashTable *table, u64 value_size);
|
||||||
|
void *hashTableGetKeyFromBucketRef(WpHashTable *table, WpHashBucketRef ref, u64 key_size);
|
||||||
|
void *hashTableGetValueFromBucketRef(WpHashTable *table, WpHashBucketRef ref, u64 value_size);
|
||||||
|
u64 hashTableCapacity(WpHashTable *table);
|
||||||
|
u64 hashTableCount(WpHashTable *table);
|
||||||
|
u64 hashTableKeySize(WpHashTable *table);
|
||||||
|
u64 hashTableValueSize(WpHashTable *table);
|
||||||
|
void hashTableGrow(const WpAllocator *allocator, WpHashTable *table, u64 key_size,
|
||||||
|
u64 value_size);
|
||||||
|
WpHashLookupResult hashTableLookup(WpHashTable *table, void *key, WpHashBucketRef ref, u64 key_size);
|
||||||
|
void hashTableUpdate(WpHashTable *table, void *value, WpHashBucketRef ref, u64 value_size);
|
||||||
|
void hashTableInsert(WpHashTable *table, void *key, void *value, WpHashBucketRef ref,
|
||||||
|
u64 key_size, u64 value_size);
|
||||||
|
void hashTableRemove(WpHashTable *table, WpHashBucketRef ref, u64 key_size, u64 value_size);
|
||||||
|
void hashTableClear(WpHashTable *table, u64 key_size, u64 value_size);
|
||||||
|
void hashTableDealloc(const WpAllocator *allocator, WpHashTable *table, u64 key_size,
|
||||||
|
u64 value_size);
|
||||||
|
|
||||||
|
#ifdef WP_PLATFORM_CPP
|
||||||
|
END_C_LINKAGE
|
||||||
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
|
#endif // !TABLE_H
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
BEGIN_C_LINKAGE
|
BEGIN_C_LINKAGE
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpMemOp {
|
||||||
WP_MEM_OP_ALLOC,
|
WP_MEM_OP_ALLOC,
|
||||||
WP_MEM_OP_ALLOC_ALIGNED,
|
WP_MEM_OP_ALLOC_ALIGNED,
|
||||||
WP_MEM_OP_REALLOC,
|
WP_MEM_OP_REALLOC,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "../../common/misc/misc_utils.h"
|
#include "../../common/misc/misc_utils.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void _queuePush(WpQueue *queue, void *item, u64 item_size) {
|
void queuePush(WpQueue *queue, void *item, u64 item_size) {
|
||||||
wpDebugAssert(queue != NULL, "`queue` should not be NULL");
|
wpDebugAssert(queue != NULL, "`queue` should not be NULL");
|
||||||
wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type");
|
wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type");
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ void _queuePush(WpQueue *queue, void *item, u64 item_size) {
|
|||||||
if (queue->count >= capacity) { return; }
|
if (queue->count >= capacity) { return; }
|
||||||
|
|
||||||
u64 index = (queue->back)++;
|
u64 index = (queue->back)++;
|
||||||
_arraySet(queue->items, index, item, item_size);
|
arraySet(queue->items, index, item, item_size);
|
||||||
++(queue->count);
|
++(queue->count);
|
||||||
|
|
||||||
if (queue->back >= capacity) {
|
if (queue->back >= capacity) {
|
||||||
@@ -22,7 +22,7 @@ void _queuePush(WpQueue *queue, void *item, u64 item_size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WpQueue *_queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *item, u64 item_size) {
|
WpQueue *queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *item, u64 item_size) {
|
||||||
wpDebugAssert(allocator != NULL && queue != NULL && item != NULL,
|
wpDebugAssert(allocator != NULL && queue != NULL && item != NULL,
|
||||||
"`allocator`, `queue` and `item` should not be NULL");
|
"`allocator`, `queue` and `item` should not be NULL");
|
||||||
wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type");
|
wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type");
|
||||||
@@ -35,7 +35,7 @@ WpQueue *_queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *ite
|
|||||||
b8 queue_full = queue->count >= capacity;
|
b8 queue_full = queue->count >= capacity;
|
||||||
if (queue_full) {
|
if (queue_full) {
|
||||||
u64 new_capacity = wpMiscUtilsU64RoundUpPow2(capacity * 2);
|
u64 new_capacity = wpMiscUtilsU64RoundUpPow2(capacity * 2);
|
||||||
u64 array_size = _arrayCalcAllocSize(new_capacity, item_size);
|
u64 array_size = arrayCalcAllocSize(new_capacity, item_size);
|
||||||
u64 alloc_size = sizeof(WpQueue) + array_size;
|
u64 alloc_size = sizeof(WpQueue) + array_size;
|
||||||
void *buffer = wpMemAllocatorAlloc(allocator, alloc_size);
|
void *buffer = wpMemAllocatorAlloc(allocator, alloc_size);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
@@ -45,7 +45,7 @@ WpQueue *_queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *ite
|
|||||||
memset((void *)buffer, 0, alloc_size);
|
memset((void *)buffer, 0, alloc_size);
|
||||||
|
|
||||||
output = (WpQueue *)buffer;
|
output = (WpQueue *)buffer;
|
||||||
output->items = _arrayFromPreallocatedBuffer((void *)(output + 1), array_size, WP_ARRAY_INIT_FILLED, item_size);
|
output->items = arrayFromPreallocatedBuffer((void *)(output + 1), array_size, WP_ARRAY_INIT_FILLED, item_size);
|
||||||
|
|
||||||
// NOTE (Abdelrahman): When the queue is full, the front and back indices should
|
// NOTE (Abdelrahman): When the queue is full, the front and back indices should
|
||||||
// always be the same
|
// always be the same
|
||||||
@@ -84,13 +84,13 @@ WpQueue *_queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *ite
|
|||||||
output->count = queue->count;
|
output->count = queue->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
_queuePush(output, item, item_size);
|
queuePush(output, item, item_size);
|
||||||
|
|
||||||
RETURN_QUEUE_PUSH_ALLOC:
|
RETURN_QUEUE_PUSH_ALLOC:
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *_queuePop(WpQueue *queue, u64 item_size) {
|
void *queuePop(WpQueue *queue, u64 item_size) {
|
||||||
wpDebugAssert(queue != NULL, "`queue` should not be NULL");
|
wpDebugAssert(queue != NULL, "`queue` should not be NULL");
|
||||||
wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type");
|
wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type");
|
||||||
|
|
||||||
@@ -104,5 +104,5 @@ void *_queuePop(WpQueue *queue, u64 item_size) {
|
|||||||
queue->front = 0;
|
queue->front = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _arrayGet(queue->items, index, item_size);
|
return arrayGet(queue->items, index, item_size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
BEGIN_C_LINKAGE
|
BEGIN_C_LINKAGE
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
typedef struct {
|
typedef struct WpQueue {
|
||||||
WpArray items;
|
WpArray items;
|
||||||
u64 front;
|
u64 front;
|
||||||
u64 back;
|
u64 back;
|
||||||
@@ -80,13 +80,13 @@ typedef WpQueue WpStr8Queue;
|
|||||||
#define wpQueueCapacity(QUEUE_PTR) (wpArrayCapacity((QUEUE_PTR)->items))
|
#define wpQueueCapacity(QUEUE_PTR) (wpArrayCapacity((QUEUE_PTR)->items))
|
||||||
#define wpQueueItemSize(QUEUE_PTR) (wpArrayItemSize((QUEUE_PTR)->items))
|
#define wpQueueItemSize(QUEUE_PTR) (wpArrayItemSize((QUEUE_PTR)->items))
|
||||||
#define wpQueuePush(TYPE, QUEUE_PTR, VALUE_PTR) ( \
|
#define wpQueuePush(TYPE, QUEUE_PTR, VALUE_PTR) ( \
|
||||||
_queuePush(QUEUE_PTR, VALUE_PTR, sizeof(TYPE)) \
|
queuePush(QUEUE_PTR, VALUE_PTR, sizeof(TYPE)) \
|
||||||
)
|
)
|
||||||
#define wpQueuePushAlloc(TYPE, ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR) ( \
|
#define wpQueuePushAlloc(TYPE, ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR) ( \
|
||||||
_queuePushAlloc(ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR, sizeof(TYPE)) \
|
queuePushAlloc(ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR, sizeof(TYPE)) \
|
||||||
)
|
)
|
||||||
#define wpQueuePop(TYPE, QUEUE_PTR) ( \
|
#define wpQueuePop(TYPE, QUEUE_PTR) ( \
|
||||||
(TYPE *)_queuePop(QUEUE_PTR, sizeof(TYPE)) \
|
(TYPE *)queuePop(QUEUE_PTR, sizeof(TYPE)) \
|
||||||
)
|
)
|
||||||
#define wpQueueDealloc(TYPE, ALLOCATOR_PTR, QUEUE_PTR) \
|
#define wpQueueDealloc(TYPE, ALLOCATOR_PTR, QUEUE_PTR) \
|
||||||
(wpArrayDealloc(TYPE, ALLOCATOR_PTR, &((QUEUE_PTR)->items)), \
|
(wpArrayDealloc(TYPE, ALLOCATOR_PTR, &((QUEUE_PTR)->items)), \
|
||||||
@@ -94,9 +94,9 @@ typedef WpQueue WpStr8Queue;
|
|||||||
(QUEUE_PTR)->back = 0, \
|
(QUEUE_PTR)->back = 0, \
|
||||||
(QUEUE_PTR)->count = 0)
|
(QUEUE_PTR)->count = 0)
|
||||||
|
|
||||||
void _queuePush(WpQueue *queue, void *item, u64 item_size);
|
void queuePush(WpQueue *queue, void *item, u64 item_size);
|
||||||
WpQueue *_queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *item, u64 item_size);
|
WpQueue *queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *item, u64 item_size);
|
||||||
void *_queuePop(WpQueue *queue, u64 item_size);
|
void *queuePop(WpQueue *queue, u64 item_size);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
@@ -4,20 +4,20 @@
|
|||||||
#include "../../common/aliases/aliases.h"
|
#include "../../common/aliases/aliases.h"
|
||||||
#include "../../common/assert/assert.h"
|
#include "../../common/assert/assert.h"
|
||||||
|
|
||||||
void _streamValidate(const WpStream *stream, u64 item_size);
|
void streamValidate(const WpStream *stream, u64 item_size);
|
||||||
|
|
||||||
b8 wpStreamAtEnd(const WpStream *stream) {
|
b8 wpStreamAtEnd(const WpStream *stream) {
|
||||||
return stream->position >= stream->count;
|
return stream->position >= stream->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
b8 _streamHasCount(const WpStream *stream, u64 count) {
|
b8 streamHasCount(const WpStream *stream, u64 count) {
|
||||||
return stream->position + count <= stream->count;
|
return stream->position + count <= stream->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *_streamPeekWithOffset(const WpStream *stream, u64 offset, u64 item_size) {
|
void *streamPeekWithOffset(const WpStream *stream, u64 offset, u64 item_size) {
|
||||||
_streamValidate(stream, item_size);
|
streamValidate(stream, item_size);
|
||||||
|
|
||||||
if (_streamHasCount(stream, offset + 1)) {
|
if (streamHasCount(stream, offset + 1)) {
|
||||||
u64 index = (stream->position + offset) * stream->item_size;
|
u64 index = (stream->position + offset) * stream->item_size;
|
||||||
return (void *)(&((u8 *)(stream->data))[index]);
|
return (void *)(&((u8 *)(stream->data))[index]);
|
||||||
}
|
}
|
||||||
@@ -25,10 +25,10 @@ void *_streamPeekWithOffset(const WpStream *stream, u64 offset, u64 item_size) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *_streamConsumeCount(WpStream *stream, u64 count, u64 item_size) {
|
void *streamConsumeCount(WpStream *stream, u64 count, u64 item_size) {
|
||||||
_streamValidate(stream, item_size);
|
streamValidate(stream, item_size);
|
||||||
|
|
||||||
if (_streamHasCount(stream, count)) {
|
if (streamHasCount(stream, count)) {
|
||||||
u64 index = stream->position * stream->item_size;
|
u64 index = stream->position * stream->item_size;
|
||||||
stream->position += count;
|
stream->position += count;
|
||||||
return (void *)(&((u8 *)(stream->data))[index]);
|
return (void *)(&((u8 *)(stream->data))[index]);
|
||||||
@@ -37,7 +37,7 @@ void *_streamConsumeCount(WpStream *stream, u64 count, u64 item_size) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _streamValidate(const WpStream *stream, u64 item_size) {
|
void streamValidate(const WpStream *stream, u64 item_size) {
|
||||||
wpDebugAssert(stream != NULL, "`stream` should not be NULL");
|
wpDebugAssert(stream != NULL, "`stream` should not be NULL");
|
||||||
wpRuntimeAssert(stream->item_size == item_size, "Invalid item type provided");
|
wpRuntimeAssert(stream->item_size == item_size, "Invalid item type provided");
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -10,7 +10,7 @@
|
|||||||
BEGIN_C_LINKAGE
|
BEGIN_C_LINKAGE
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
typedef struct {
|
typedef struct WpStream {
|
||||||
void *data;
|
void *data;
|
||||||
u64 count;
|
u64 count;
|
||||||
u64 position;
|
u64 position;
|
||||||
@@ -58,20 +58,20 @@ typedef WpStream WpStr8Stream;
|
|||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define wpStreamHasNext(STREAM) _streamHasCount(STREAM, 1)
|
#define wpStreamHasNext(STREAM) streamHasCount(STREAM, 1)
|
||||||
#define wpStreamHasCount(STREAM, COUNT) _streamHasCount(STREAM, COUNT)
|
#define wpStreamHasCount(STREAM, COUNT) streamHasCount(STREAM, COUNT)
|
||||||
#define wpStreamPeek(TYPE, STREAM) ((TYPE *)_streamPeekWithOffset(STREAM, 0, sizeof(TYPE)))
|
#define wpStreamPeek(TYPE, STREAM) ((TYPE *)streamPeekWithOffset(STREAM, 0, sizeof(TYPE)))
|
||||||
#define wpStreamPeekWithOffset(TYPE, STREAM, OFFSET) \
|
#define wpStreamPeekWithOffset(TYPE, STREAM, OFFSET) \
|
||||||
((TYPE *)_streamPeekWithOffset(STREAM, OFFSET, sizeof(TYPE)))
|
((TYPE *)streamPeekWithOffset(STREAM, OFFSET, sizeof(TYPE)))
|
||||||
#define wpStreamConsume(TYPE, STREAM) ((TYPE *)_streamConsumeCount(STREAM, 1, sizeof(TYPE)))
|
#define wpStreamConsume(TYPE, STREAM) ((TYPE *)streamConsumeCount(STREAM, 1, sizeof(TYPE)))
|
||||||
#define wpStreamConsumeCount(TYPE, STREAM, COUNT) \
|
#define wpStreamConsumeCount(TYPE, STREAM, COUNT) \
|
||||||
((TYPE *)_streamConsumeCount(STREAM, COUNT, sizeof(TYPE)))
|
((TYPE *)streamConsumeCount(STREAM, COUNT, sizeof(TYPE)))
|
||||||
|
|
||||||
b8 wpStreamAtEnd(const WpStream *stream);
|
b8 wpStreamAtEnd(const WpStream *stream);
|
||||||
|
|
||||||
b8 _streamHasCount(const WpStream *stream, u64 count);
|
b8 streamHasCount(const WpStream *stream, u64 count);
|
||||||
void *_streamPeekWithOffset(const WpStream *stream, u64 offset, u64 item_size);
|
void *streamPeekWithOffset(const WpStream *stream, u64 offset, u64 item_size);
|
||||||
void *_streamConsumeCount(WpStream *stream, u64 count, u64 item_size);
|
void *streamConsumeCount(WpStream *stream, u64 count, u64 item_size);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
@@ -115,6 +115,11 @@ void wpStr8Set(WpStr8 *str, u64 index, c8 c) {
|
|||||||
str->buf[index] = c;
|
str->buf[index] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wpStr8Clear(WpStr8 *str) {
|
||||||
|
memset(str->buf, 0, str->capacity);
|
||||||
|
str->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void wpStr8PushBack(WpStr8 *str, c8 c) {
|
void wpStr8PushBack(WpStr8 *str, c8 c) {
|
||||||
if (!(str->size < str->capacity)) {
|
if (!(str->size < str->capacity)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ typedef const WpStr8 WpStr8RO;
|
|||||||
/**
|
/**
|
||||||
* Utilities to be used with printf functions
|
* Utilities to be used with printf functions
|
||||||
*/
|
*/
|
||||||
#define WP_STR8_SPEC "%.*s"
|
#define WP_STR8_SPEC ".*s"
|
||||||
#define wpStr8Varg(STRING) (int)((STRING).size), (STRING).buf
|
#define wpStr8Varg(STRING) (int)((STRING).size), (STRING).buf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,6 +90,7 @@ void wpStr8DeallocBuf(const WpAllocator *allocator, WpStr8 **str);
|
|||||||
*/
|
*/
|
||||||
c8 wpStr8Get(WpStr8RO *str, u64 index);
|
c8 wpStr8Get(WpStr8RO *str, u64 index);
|
||||||
void wpStr8Set(WpStr8 *str, u64 index, c8 c);
|
void wpStr8Set(WpStr8 *str, u64 index, c8 c);
|
||||||
|
void wpStr8Clear(WpStr8 *str);
|
||||||
void wpStr8PushBack(WpStr8 *str, c8 c);
|
void wpStr8PushBack(WpStr8 *str, c8 c);
|
||||||
b8 wpStr8Equal(WpStr8RO *s1, WpStr8RO *s2);
|
b8 wpStr8Equal(WpStr8RO *s1, WpStr8RO *s2);
|
||||||
b8 wpStr8EqualToCount(WpStr8RO* s1, WpStr8RO* s2, u64 count);
|
b8 wpStr8EqualToCount(WpStr8RO* s1, WpStr8RO* s2, u64 count);
|
||||||
|
|||||||
@@ -6,6 +6,12 @@
|
|||||||
#include "wapp_base.h"
|
#include "wapp_base.h"
|
||||||
#include "array/array.c"
|
#include "array/array.c"
|
||||||
#include "dbl_list/dbl_list.c"
|
#include "dbl_list/dbl_list.c"
|
||||||
|
#include "hash/hasher/hasher.c"
|
||||||
|
#include "hash/hasher/murmur3.c"
|
||||||
|
#include "hash/hasher/siphash.c"
|
||||||
|
#include "hash/table/table.c"
|
||||||
|
#include "hash/set/set.c"
|
||||||
|
#include "hash/map/map.c"
|
||||||
#include "queue/queue.c"
|
#include "queue/queue.c"
|
||||||
#include "stream/stream.c"
|
#include "stream/stream.c"
|
||||||
#include "mem/allocator/mem_allocator.c"
|
#include "mem/allocator/mem_allocator.c"
|
||||||
|
|||||||
@@ -5,6 +5,12 @@
|
|||||||
|
|
||||||
#include "array/array.h"
|
#include "array/array.h"
|
||||||
#include "dbl_list/dbl_list.h"
|
#include "dbl_list/dbl_list.h"
|
||||||
|
#include "hash/hasher/hasher.h"
|
||||||
|
#include "hash/hasher/murmur3.h"
|
||||||
|
#include "hash/hasher/siphash.h"
|
||||||
|
#include "hash/table/table.h"
|
||||||
|
#include "hash/set/set.h"
|
||||||
|
#include "hash/map/map.h"
|
||||||
#include "queue/queue.h"
|
#include "queue/queue.h"
|
||||||
#include "stream/stream.h"
|
#include "stream/stream.h"
|
||||||
#include "mem/allocator/mem_allocator.h"
|
#include "mem/allocator/mem_allocator.h"
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ typedef uint16_t u16;
|
|||||||
typedef uint32_t u32;
|
typedef uint32_t u32;
|
||||||
typedef uint64_t u64;
|
typedef uint64_t u64;
|
||||||
|
|
||||||
|
#define wpU8Const UINT8_C
|
||||||
|
#define wpU16Const UINT16_C
|
||||||
|
#define wpU32Const UINT32_C
|
||||||
|
#define wpU64Const UINT64_C
|
||||||
|
|
||||||
typedef uint8_t b8;
|
typedef uint8_t b8;
|
||||||
|
|
||||||
#ifndef WP_PLATFORM_CPP
|
#ifndef WP_PLATFORM_CPP
|
||||||
@@ -47,6 +52,11 @@ typedef int16_t i16;
|
|||||||
typedef int32_t i32;
|
typedef int32_t i32;
|
||||||
typedef int64_t i64;
|
typedef int64_t i64;
|
||||||
|
|
||||||
|
#define wpI8Const INT8_C
|
||||||
|
#define wpI16Const INT16_C
|
||||||
|
#define wpI32Const INT32_C
|
||||||
|
#define wpI64Const INT64_C
|
||||||
|
|
||||||
typedef float f32;
|
typedef float f32;
|
||||||
typedef double f64;
|
typedef double f64;
|
||||||
typedef long double f128;
|
typedef long double f128;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ BEGIN_C_LINKAGE
|
|||||||
#define wpStaticAssert(EXPR, MSG) wp_extern char ASSERTION_FAILED[EXPR ? 1 : -1]
|
#define wpStaticAssert(EXPR, MSG) wp_extern char ASSERTION_FAILED[EXPR ? 1 : -1]
|
||||||
|
|
||||||
#ifndef WP_NO_RUNTIME_ASSERT
|
#ifndef WP_NO_RUNTIME_ASSERT
|
||||||
#define wpRuntimeAssert(EXPR, MSG) _runtimeAssert(EXPR, MSG)
|
#define wpRuntimeAssert(EXPR, MSG) runtimeAssert(EXPR, MSG)
|
||||||
#else
|
#else
|
||||||
#define wpRuntimeAssert(EXPR, MSG)
|
#define wpRuntimeAssert(EXPR, MSG)
|
||||||
#endif
|
#endif
|
||||||
@@ -28,23 +28,23 @@ BEGIN_C_LINKAGE
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_WINDOWS
|
#ifdef WP_PLATFORM_WINDOWS
|
||||||
#define _runtimeAssert(EXPR, MSG) do { \
|
#define runtimeAssert(EXPR, MSG) do { \
|
||||||
__pragma(warning(push)) \
|
__pragma(warning(push)) \
|
||||||
__pragma(warning(disable:4127)) \
|
__pragma(warning(disable:4127)) \
|
||||||
if (!(EXPR)) { \
|
if (!(EXPR)) { \
|
||||||
__pragma(warning(pop)) \
|
__pragma(warning(pop)) \
|
||||||
_runtimeAssertFailed(EXPR, MSG); \
|
runtimeAssertFailed(EXPR, MSG); \
|
||||||
} \
|
} \
|
||||||
} while(false)
|
} while(false)
|
||||||
#else
|
#else
|
||||||
#define _runtimeAssert(EXPR, MSG) do { \
|
#define runtimeAssert(EXPR, MSG) do { \
|
||||||
if (!(EXPR)) { \
|
if (!(EXPR)) { \
|
||||||
_runtimeAssertFailed(EXPR, MSG); \
|
runtimeAssertFailed(EXPR, MSG); \
|
||||||
} \
|
} \
|
||||||
} while(false)
|
} while(false)
|
||||||
#endif // !WP_PLATFORM_WINDOWS
|
#endif // !WP_PLATFORM_WINDOWS
|
||||||
|
|
||||||
#define _runtimeAssertFailed(EXPR, MSG) do { \
|
#define runtimeAssertFailed(EXPR, MSG) do { \
|
||||||
fprintf( \
|
fprintf( \
|
||||||
stderr, \
|
stderr, \
|
||||||
"%s:%d (In function `%s`): Assertion failed (%" PRIu32 ")\nDiagnostic: %s\n\n", \
|
"%s:%d (In function `%s`): Assertion failed (%" PRIu32 ")\nDiagnostic: %s\n\n", \
|
||||||
|
|||||||
@@ -49,6 +49,15 @@ BEGIN_C_LINKAGE
|
|||||||
|
|
||||||
#define wpMiscUtilsIsPowerOfTwo(NUM) ((NUM & (NUM - 1)) == 0)
|
#define wpMiscUtilsIsPowerOfTwo(NUM) ((NUM & (NUM - 1)) == 0)
|
||||||
#define wpMiscUtilsOffsetPointer(PTR, OFFSET) ((void *)((uptr)(PTR) + (OFFSET)))
|
#define wpMiscUtilsOffsetPointer(PTR, OFFSET) ((void *)((uptr)(PTR) + (OFFSET)))
|
||||||
|
#define wpMiscUtilsSwap(TYPE, A_PTR, B_PTR) do { \
|
||||||
|
TYPE tmp = *(A_PTR); \
|
||||||
|
*(A_PTR) = *(B_PTR); \
|
||||||
|
*(B_PTR) = tmp; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
wp_intern inline u64 wpMiscUtilsRotl64(u64 x, i8 rotation) {
|
||||||
|
return (x << rotation) | (x >> (64 - rotation));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
+12
-12
@@ -15,7 +15,7 @@ wp_intern WpStr8RO L_BRACKET = wpStr8LitRo("[");
|
|||||||
wp_intern WpStr8RO R_BRACKET_SPACE = wpStr8LitRo("] ");
|
wp_intern WpStr8RO R_BRACKET_SPACE = wpStr8LitRo("] ");
|
||||||
wp_intern WpStr8RO R_BRACKET_NEWLINE = wpStr8LitRo("]\n");
|
wp_intern WpStr8RO R_BRACKET_NEWLINE = wpStr8LitRo("]\n");
|
||||||
|
|
||||||
typedef struct {
|
typedef struct LogConfig {
|
||||||
WpFile *outlog;
|
WpFile *outlog;
|
||||||
WpFile *errlog;
|
WpFile *errlog;
|
||||||
WpLogLevel level;
|
WpLogLevel level;
|
||||||
@@ -35,8 +35,8 @@ wp_intern WpStr8RO LOG_LEVEL_STRINGS[COUNT_LOG_LEVEL] = {
|
|||||||
[WP_LOG_LEVEL_DEBUG] = wpStr8LitRoInitialiserList("debug "),
|
[WP_LOG_LEVEL_DEBUG] = wpStr8LitRoInitialiserList("debug "),
|
||||||
};
|
};
|
||||||
|
|
||||||
wp_intern void _get_current_time_string(WpStr8 *dst);
|
wp_intern void getCurrentTimeString(WpStr8 *dst);
|
||||||
wp_intern void _write_log_line(WpFile *fp, const WpLogger *logger, WpStr8 msg, WpLogLevel level);
|
wp_intern void writeLogLine(WpFile *fp, const WpLogger *logger, WpStr8 msg, WpLogLevel level);
|
||||||
|
|
||||||
void wpLogSetLevel(WpLogLevel level) {
|
void wpLogSetLevel(WpLogLevel level) {
|
||||||
LOG_CONFIG.level = level;
|
LOG_CONFIG.level = level;
|
||||||
@@ -57,7 +57,7 @@ void wpLogDebug(const WpLogger *logger, WpStr8 msg) {
|
|||||||
if (LOG_CONFIG.level < WP_LOG_LEVEL_DEBUG) { return; }
|
if (LOG_CONFIG.level < WP_LOG_LEVEL_DEBUG) { return; }
|
||||||
|
|
||||||
WpFile *fp = LOG_CONFIG.outlog != NULL ? LOG_CONFIG.outlog : wpFileStdout();
|
WpFile *fp = LOG_CONFIG.outlog != NULL ? LOG_CONFIG.outlog : wpFileStdout();
|
||||||
_write_log_line(fp, logger, msg, WP_LOG_LEVEL_DEBUG);
|
writeLogLine(fp, logger, msg, WP_LOG_LEVEL_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wpLogInfo(const WpLogger *logger, WpStr8 msg) {
|
void wpLogInfo(const WpLogger *logger, WpStr8 msg) {
|
||||||
@@ -65,7 +65,7 @@ void wpLogInfo(const WpLogger *logger, WpStr8 msg) {
|
|||||||
if (LOG_CONFIG.level < WP_LOG_LEVEL_INFO) { return; }
|
if (LOG_CONFIG.level < WP_LOG_LEVEL_INFO) { return; }
|
||||||
|
|
||||||
WpFile *fp = LOG_CONFIG.outlog != NULL ? LOG_CONFIG.outlog : wpFileStdout();
|
WpFile *fp = LOG_CONFIG.outlog != NULL ? LOG_CONFIG.outlog : wpFileStdout();
|
||||||
_write_log_line(fp, logger, msg, WP_LOG_LEVEL_INFO);
|
writeLogLine(fp, logger, msg, WP_LOG_LEVEL_INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wpLogWarning(const WpLogger *logger, WpStr8 msg) {
|
void wpLogWarning(const WpLogger *logger, WpStr8 msg) {
|
||||||
@@ -73,7 +73,7 @@ void wpLogWarning(const WpLogger *logger, WpStr8 msg) {
|
|||||||
if (LOG_CONFIG.level < WP_LOG_LEVEL_WARNING) { return; }
|
if (LOG_CONFIG.level < WP_LOG_LEVEL_WARNING) { return; }
|
||||||
|
|
||||||
WpFile *fp = LOG_CONFIG.outlog != NULL ? LOG_CONFIG.outlog : wpFileStdout();
|
WpFile *fp = LOG_CONFIG.outlog != NULL ? LOG_CONFIG.outlog : wpFileStdout();
|
||||||
_write_log_line(fp, logger, msg, WP_LOG_LEVEL_WARNING);
|
writeLogLine(fp, logger, msg, WP_LOG_LEVEL_WARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wpLogError(const WpLogger *logger, WpStr8 msg) {
|
void wpLogError(const WpLogger *logger, WpStr8 msg) {
|
||||||
@@ -81,7 +81,7 @@ void wpLogError(const WpLogger *logger, WpStr8 msg) {
|
|||||||
if (LOG_CONFIG.level < WP_LOG_LEVEL_ERROR) { return; }
|
if (LOG_CONFIG.level < WP_LOG_LEVEL_ERROR) { return; }
|
||||||
|
|
||||||
WpFile *fp = LOG_CONFIG.errlog != NULL ? LOG_CONFIG.errlog : wpFileStderr();
|
WpFile *fp = LOG_CONFIG.errlog != NULL ? LOG_CONFIG.errlog : wpFileStderr();
|
||||||
_write_log_line(fp, logger, msg, WP_LOG_LEVEL_ERROR);
|
writeLogLine(fp, logger, msg, WP_LOG_LEVEL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wpLogCritical(const WpLogger *logger, WpStr8 msg) {
|
void wpLogCritical(const WpLogger *logger, WpStr8 msg) {
|
||||||
@@ -89,7 +89,7 @@ void wpLogCritical(const WpLogger *logger, WpStr8 msg) {
|
|||||||
if (LOG_CONFIG.level < WP_LOG_LEVEL_CRITICAL) { return; }
|
if (LOG_CONFIG.level < WP_LOG_LEVEL_CRITICAL) { return; }
|
||||||
|
|
||||||
WpFile *fp = LOG_CONFIG.errlog != NULL ? LOG_CONFIG.errlog : wpFileStderr();
|
WpFile *fp = LOG_CONFIG.errlog != NULL ? LOG_CONFIG.errlog : wpFileStderr();
|
||||||
_write_log_line(fp, logger, msg, WP_LOG_LEVEL_CRITICAL);
|
writeLogLine(fp, logger, msg, WP_LOG_LEVEL_CRITICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wpLogFatal(const WpLogger *logger, WpStr8 msg) {
|
void wpLogFatal(const WpLogger *logger, WpStr8 msg) {
|
||||||
@@ -97,10 +97,10 @@ void wpLogFatal(const WpLogger *logger, WpStr8 msg) {
|
|||||||
if (LOG_CONFIG.level < WP_LOG_LEVEL_FATAL) { return; }
|
if (LOG_CONFIG.level < WP_LOG_LEVEL_FATAL) { return; }
|
||||||
|
|
||||||
WpFile *fp = LOG_CONFIG.errlog != NULL ? LOG_CONFIG.errlog : wpFileStderr();
|
WpFile *fp = LOG_CONFIG.errlog != NULL ? LOG_CONFIG.errlog : wpFileStderr();
|
||||||
_write_log_line(fp, logger, msg, WP_LOG_LEVEL_FATAL);
|
writeLogLine(fp, logger, msg, WP_LOG_LEVEL_FATAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void _get_current_time_string(WpStr8 *dst) {
|
wp_intern void getCurrentTimeString(WpStr8 *dst) {
|
||||||
// TODO (Abdelrahman): Replace with proper date/time utilities
|
// TODO (Abdelrahman): Replace with proper date/time utilities
|
||||||
char buf[TIME_BUF_CAPACITY];
|
char buf[TIME_BUF_CAPACITY];
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
@@ -110,13 +110,13 @@ wp_intern void _get_current_time_string(WpStr8 *dst) {
|
|||||||
wpStr8CopyCstrCapped(dst, buf);
|
wpStr8CopyCstrCapped(dst, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void _write_log_line(WpFile *fp, const WpLogger *logger, WpStr8 msg, WpLogLevel level) {
|
wp_intern void writeLogLine(WpFile *fp, const WpLogger *logger, WpStr8 msg, WpLogLevel level) {
|
||||||
WpStr8 padding = wpStr8Buf(MIN_LOG_MSG_LENGTH);
|
WpStr8 padding = wpStr8Buf(MIN_LOG_MSG_LENGTH);
|
||||||
u32 padding_size = msg.size < MIN_LOG_MSG_LENGTH ? MIN_LOG_MSG_LENGTH - msg.size + 1 : 0;
|
u32 padding_size = msg.size < MIN_LOG_MSG_LENGTH ? MIN_LOG_MSG_LENGTH - msg.size + 1 : 0;
|
||||||
wpStr8Format(&padding, "%-*s", padding_size, " ");
|
wpStr8Format(&padding, "%-*s", padding_size, " ");
|
||||||
|
|
||||||
WpStr8 time_str = wpStr8Buf(TIME_BUF_CAPACITY);
|
WpStr8 time_str = wpStr8Buf(TIME_BUF_CAPACITY);
|
||||||
_get_current_time_string(&time_str);
|
getCurrentTimeString(&time_str);
|
||||||
|
|
||||||
WpStr8RO **strings = wpArray(
|
WpStr8RO **strings = wpArray(
|
||||||
WpStr8RO *,
|
WpStr8RO *,
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@
|
|||||||
BEGIN_C_LINKAGE
|
BEGIN_C_LINKAGE
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpLogLevel {
|
||||||
WP_LOG_LEVEL_FATAL,
|
WP_LOG_LEVEL_FATAL,
|
||||||
WP_LOG_LEVEL_CRITICAL,
|
WP_LOG_LEVEL_CRITICAL,
|
||||||
WP_LOG_LEVEL_ERROR,
|
WP_LOG_LEVEL_ERROR,
|
||||||
@@ -21,7 +21,7 @@ typedef enum {
|
|||||||
COUNT_LOG_LEVEL,
|
COUNT_LOG_LEVEL,
|
||||||
} WpLogLevel;
|
} WpLogLevel;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct WpLogger {
|
||||||
WpStr8 name;
|
WpStr8 name;
|
||||||
} WpLogger;
|
} WpLogger;
|
||||||
|
|
||||||
|
|||||||
+45
-27
@@ -392,6 +392,24 @@
|
|||||||
#define wapp_array_alloc_capacity wpArrayAllocCapacity
|
#define wapp_array_alloc_capacity wpArrayAllocCapacity
|
||||||
#define wapp_array_from_preallcated_buffer wpArrayFromPreallcatedBuffer
|
#define wapp_array_from_preallcated_buffer wpArrayFromPreallcatedBuffer
|
||||||
|
|
||||||
|
#define _array_count arrayCount
|
||||||
|
#define _array_capacity arrayCapacity
|
||||||
|
#define _array_item_size arrayItemSize
|
||||||
|
#define _array_set_count arraySetCount
|
||||||
|
#define _array_get arrayGet
|
||||||
|
#define _array_set arraySet
|
||||||
|
#define _array_append_capped arrayAppendCapped
|
||||||
|
#define _array_extend_capped arrayExtendCappend
|
||||||
|
#define _array_copy_capped arrayCopyCapped
|
||||||
|
#define _array_append_alloc arrayAppendAlloc
|
||||||
|
#define _array_extend_alloc arrayExtendAlloc
|
||||||
|
#define _array_copy_alloc arrayCopyAlloc
|
||||||
|
#define _array_pop arrayPop
|
||||||
|
#define _array_clear arrayClear
|
||||||
|
#define _array_calc_alloc_size arrayCalcAllocSize
|
||||||
|
#define _array_alloc_capacity arrayAllocCapacity
|
||||||
|
#define _array_from_preallocated_buffer arrayFromPreallocatedBuffer
|
||||||
|
|
||||||
// --- Assert ---
|
// --- Assert ---
|
||||||
|
|
||||||
#define wapp_static_assert wpStaticAssert
|
#define wapp_static_assert wpStaticAssert
|
||||||
@@ -403,7 +421,7 @@
|
|||||||
#define wapp_cpath_dirname wpCpathDirname
|
#define wapp_cpath_dirname wpCpathDirname
|
||||||
#define wapp_cpath_dirup wpCpathDirup
|
#define wapp_cpath_dirup wpCpathDirup
|
||||||
#define wapp_cpath_join_path wpCpathJoinPath
|
#define wapp_cpath_join_path wpCpathJoinPath
|
||||||
#define dirup _dirup
|
#define dirup dirUp
|
||||||
|
|
||||||
// --- DblList ---
|
// --- DblList ---
|
||||||
|
|
||||||
@@ -426,16 +444,16 @@
|
|||||||
#define wapp_dbl_list_remove_node wpDblListRemoveNode
|
#define wapp_dbl_list_remove_node wpDblListRemoveNode
|
||||||
#define wapp_dbl_list_empty wpDblListEmpty
|
#define wapp_dbl_list_empty wpDblListEmpty
|
||||||
|
|
||||||
#define _dbl_list_alloc _dblListAlloc
|
#define _dbl_list_alloc dblListAlloc
|
||||||
#define _dbl_list_node_alloc _dblListNodeAlloc
|
#define _dbl_list_node_alloc dblListNodeAlloc
|
||||||
#define _dbl_list_get _dblListGet
|
#define _dbl_list_get dblListGet
|
||||||
#define _dbl_list_push_front _dblListPushFront
|
#define _dbl_list_push_front dblListPushFront
|
||||||
#define _dbl_list_push_back _dblListPushBack
|
#define _dbl_list_push_back dblListPushBack
|
||||||
#define _dbl_list_insert _dblListInsert
|
#define _dbl_list_insert dblListInsert
|
||||||
#define _dbl_list_pop_front _dblListPopFront
|
#define _dbl_list_pop_front dblListPopFront
|
||||||
#define _dbl_list_pop_back _dblListPopBack
|
#define _dbl_list_pop_back dblListPopBack
|
||||||
#define _dbl_list_remove _dblListRemove
|
#define _dbl_list_remove dblListRemove
|
||||||
#define _dbl_list_empty _dblListEmpty
|
#define _dbl_list_empty dblListEmpty
|
||||||
|
|
||||||
// --- File ---
|
// --- File ---
|
||||||
|
|
||||||
@@ -457,14 +475,14 @@
|
|||||||
#define wapp_file_rename wpFileRename
|
#define wapp_file_rename wpFileRename
|
||||||
#define wapp_file_remove wpFileRemove
|
#define wapp_file_remove wpFileRemove
|
||||||
|
|
||||||
#define _file_open _fileOpen
|
#define _file_open fileOpen
|
||||||
#define _file_seek _fileSeek
|
#define _file_seek fileSeek
|
||||||
#define _file_read _fileRead
|
#define _file_read fileRead
|
||||||
#define _file_write _fileWrite
|
#define _file_write fileWrite
|
||||||
#define _file_flush _fileFlush
|
#define _file_flush fileFlush
|
||||||
#define _file_close _fileClose
|
#define _file_close fileClose
|
||||||
#define _file_rename _fileRename
|
#define _file_rename fileRename
|
||||||
#define _file_remove _fileRemove
|
#define _file_remove fileRemove
|
||||||
|
|
||||||
// --- Log ---
|
// --- Log ---
|
||||||
|
|
||||||
@@ -491,8 +509,8 @@
|
|||||||
|
|
||||||
#define wapp_os_mem_alloc wpOsMemAlloc
|
#define wapp_os_mem_alloc wpOsMemAlloc
|
||||||
#define wapp_os_mem_free wpOsMemFree
|
#define wapp_os_mem_free wpOsMemFree
|
||||||
#define os_mem_allocate _osMemAllocate
|
#define os_mem_allocate osMemAllocate
|
||||||
#define os_mem_free _osMemFree
|
#define os_mem_free osMemFree
|
||||||
|
|
||||||
// --- Mem Utils ---
|
// --- Mem Utils ---
|
||||||
|
|
||||||
@@ -523,21 +541,21 @@
|
|||||||
#define wapp_queue_push_alloc wpQueuePushAlloc
|
#define wapp_queue_push_alloc wpQueuePushAlloc
|
||||||
#define wapp_queue_pop wpQueuePop
|
#define wapp_queue_pop wpQueuePop
|
||||||
|
|
||||||
#define _queue_push _queuePush
|
#define _queue_push queuePush
|
||||||
#define _queue_push_alloc _queuePushAlloc
|
#define _queue_push_alloc queuePushAlloc
|
||||||
#define _queue_pop _queuePop
|
#define _queue_pop queuePop
|
||||||
|
|
||||||
// --- Shell Commander ---
|
// --- Shell Commander ---
|
||||||
|
|
||||||
#define CMD_NO_EXIT wpCmdNoExit
|
#define CMD_NO_EXIT wpCmdNoExit
|
||||||
#define wapp_shell_commander_execute wpShellCommanderExecute
|
#define wapp_shell_commander_execute wpShellCommanderExecute
|
||||||
#define get_output_status _getOutputStatus
|
#define get_output_status getOutputStatus
|
||||||
|
|
||||||
// --- Shell Termcolour ---
|
// --- Shell Termcolour ---
|
||||||
|
|
||||||
#define wapp_shell_termcolour_print_text wpShellTermcolourPrintText
|
#define wapp_shell_termcolour_print_text wpShellTermcolourPrintText
|
||||||
#define wapp_shell_termcolour_clear_colour wpShellTermcolourClearColour
|
#define wapp_shell_termcolour_clear_colour wpShellTermcolourClearColour
|
||||||
#define print_coloured_text _printColouredText
|
#define print_coloured_text printColouredText
|
||||||
|
|
||||||
// --- Shell Utils ---
|
// --- Shell Utils ---
|
||||||
|
|
||||||
@@ -585,7 +603,7 @@
|
|||||||
|
|
||||||
#define wapp_tester_result wpTesterResult
|
#define wapp_tester_result wpTesterResult
|
||||||
#define wapp_tester_run wpTesterRun
|
#define wapp_tester_run wpTesterRun
|
||||||
#define run_tests _runTests
|
#define run_tests runTests
|
||||||
|
|
||||||
// --- UUID ---
|
// --- UUID ---
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#define ARENA_MINIMUM_CAPACITY KiB(16) // Allocate minimum of 4 pages
|
#define ARENA_MINIMUM_CAPACITY KiB(16) // Allocate minimum of 4 pages
|
||||||
|
|
||||||
typedef enum {
|
typedef enum ArenaStorageType {
|
||||||
ARENA_STORAGE_TYPE_ALLOCATED,
|
ARENA_STORAGE_TYPE_ALLOCATED,
|
||||||
ARENA_STORAGE_TYPE_BUFFER,
|
ARENA_STORAGE_TYPE_BUFFER,
|
||||||
} ArenaStorageType;
|
} ArenaStorageType;
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
#include "../../../common/aliases/aliases.h"
|
#include "../../../common/aliases/aliases.h"
|
||||||
#include "../../../common/assert/assert.h"
|
#include "../../../common/assert/assert.h"
|
||||||
|
|
||||||
wp_intern void initialise_arena_allocator(WpAllocator *allocator);
|
wp_intern void initialiseArenaAllocator(WpAllocator *allocator);
|
||||||
wp_intern void *mem_arena_alloc(u64 size, void *alloc_obj);
|
wp_intern void *memArenaAlloc(u64 size, void *alloc_obj);
|
||||||
wp_intern void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj);
|
wp_intern void *memArenaAllocAligned(u64 size, u64 alignment, void *alloc_obj);
|
||||||
wp_intern void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
|
wp_intern void *memArenaRealloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
|
||||||
wp_intern void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
|
wp_intern void *memArenaReallocAligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
|
||||||
void *alloc_obj);
|
void *alloc_obj);
|
||||||
|
|
||||||
WpAllocator wpMemArenaAllocatorInitWithBuffer(u8 *buffer, u64 buffer_size) {
|
WpAllocator wpMemArenaAllocatorInitWithBuffer(u8 *buffer, u64 buffer_size) {
|
||||||
@@ -20,7 +20,7 @@ WpAllocator wpMemArenaAllocatorInitWithBuffer(u8 *buffer, u64 buffer_size) {
|
|||||||
return allocator;
|
return allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialise_arena_allocator(&allocator);
|
initialiseArenaAllocator(&allocator);
|
||||||
|
|
||||||
return allocator;
|
return allocator;
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ WpAllocator wpMemArenaAllocatorInitCustom(u64 base_capacity, WpMemAllocFlags fla
|
|||||||
return allocator;
|
return allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialise_arena_allocator(&allocator);
|
initialiseArenaAllocator(&allocator);
|
||||||
|
|
||||||
return allocator;
|
return allocator;
|
||||||
}
|
}
|
||||||
@@ -58,29 +58,29 @@ void wpMemArenaAllocatorDestroy(WpAllocator *allocator) {
|
|||||||
*allocator = (WpAllocator){0};
|
*allocator = (WpAllocator){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void initialise_arena_allocator(WpAllocator *allocator) {
|
wp_intern void initialiseArenaAllocator(WpAllocator *allocator) {
|
||||||
allocator->alloc = mem_arena_alloc;
|
allocator->alloc = memArenaAlloc;
|
||||||
allocator->alloc_aligned = mem_arena_alloc_aligned;
|
allocator->alloc_aligned = memArenaAllocAligned;
|
||||||
allocator->realloc = mem_arena_realloc;
|
allocator->realloc = memArenaRealloc;
|
||||||
allocator->realloc_aligned = mem_arena_realloc_aligned;
|
allocator->realloc_aligned = memArenaReallocAligned;
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void *mem_arena_alloc(u64 size, void *alloc_obj) {
|
wp_intern void *memArenaAlloc(u64 size, void *alloc_obj) {
|
||||||
WpArena *arena = (WpArena *)alloc_obj;
|
WpArena *arena = (WpArena *)alloc_obj;
|
||||||
return wpMemArenaAlloc(arena, size);
|
return wpMemArenaAlloc(arena, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj) {
|
wp_intern void *memArenaAllocAligned(u64 size, u64 alignment, void *alloc_obj) {
|
||||||
WpArena *arena = (WpArena *)alloc_obj;
|
WpArena *arena = (WpArena *)alloc_obj;
|
||||||
return wpMemArenaAllocAligned(arena, size, alignment);
|
return wpMemArenaAllocAligned(arena, size, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj) {
|
wp_intern void *memArenaRealloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj) {
|
||||||
WpArena *arena = (WpArena *)alloc_obj;
|
WpArena *arena = (WpArena *)alloc_obj;
|
||||||
return wpMemArenaRealloc(arena, ptr, old_size, new_size);
|
return wpMemArenaRealloc(arena, ptr, old_size, new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
|
wp_intern void *memArenaReallocAligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
|
||||||
void *alloc_obj) {
|
void *alloc_obj) {
|
||||||
WpArena *arena = (WpArena *)alloc_obj;
|
WpArena *arena = (WpArena *)alloc_obj;
|
||||||
return wpMemArenaReallocAligned(arena, ptr, old_size, new_size, alignment);
|
return wpMemArenaReallocAligned(arena, ptr, old_size, new_size, alignment);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ CPATH_JOIN_LOOP_END:
|
|||||||
return WP_CPATH_JOIN_RESULT_SUCCESS;
|
return WP_CPATH_JOIN_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpStr8 *_dirup(const WpAllocator *allocator, WpStr8RO *path, u64 levels) {
|
WpStr8 *dirUp(const WpAllocator *allocator, WpStr8RO *path, u64 levels) {
|
||||||
WpStr8 *output = NULL;
|
WpStr8 *output = NULL;
|
||||||
if (!allocator || !path) {
|
if (!allocator || !path) {
|
||||||
goto RETURN_DIRUP;
|
goto RETURN_DIRUP;
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ BEGIN_C_LINKAGE
|
|||||||
#error "Unrecognised platform"
|
#error "Unrecognised platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define wpCpathDirname(ALLOCATOR, PATH) _dirup(ALLOCATOR, PATH, 1)
|
#define wpCpathDirname(ALLOCATOR, PATH) dirUp(ALLOCATOR, PATH, 1)
|
||||||
#define wpCpathDirup(ALLOCATOR, PATH, COUNT) _dirup(ALLOCATOR, PATH, COUNT)
|
#define wpCpathDirUp(ALLOCATOR, PATH, COUNT) dirUp(ALLOCATOR, PATH, COUNT)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpCpathJoinResult {
|
||||||
WP_CPATH_JOIN_RESULT_SUCCESS = 0,
|
WP_CPATH_JOIN_RESULT_SUCCESS = 0,
|
||||||
WP_CPATH_JOIN_RESULT_INVALID_ARGS,
|
WP_CPATH_JOIN_RESULT_INVALID_ARGS,
|
||||||
WP_CPATH_JOIN_RESULT_EMPTY_PARTS,
|
WP_CPATH_JOIN_RESULT_EMPTY_PARTS,
|
||||||
@@ -36,7 +36,7 @@ typedef enum {
|
|||||||
} WpCpathJoinResult;
|
} WpCpathJoinResult;
|
||||||
|
|
||||||
WpCpathJoinResult wpCpathJoinPath(WpStr8 *dst, const WpStr8List *parts);
|
WpCpathJoinResult wpCpathJoinPath(WpStr8 *dst, const WpStr8List *parts);
|
||||||
WpStr8 *_dirup(const WpAllocator *allocator, WpStr8RO *path, u64 levels);
|
WpStr8 *dirUp(const WpAllocator *allocator, WpStr8RO *path, u64 levels);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
+13
-13
@@ -10,17 +10,17 @@
|
|||||||
WpFile *wpFileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode) {
|
WpFile *wpFileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode) {
|
||||||
wpDebugAssert(allocator != NULL && filepath != NULL, "`allocator` and `filepath` should not be NULL");
|
wpDebugAssert(allocator != NULL && filepath != NULL, "`allocator` and `filepath` should not be NULL");
|
||||||
wpDebugAssert(filepath->size < WP_PATH_MAX, "`filepath` exceeds max path limit.");
|
wpDebugAssert(filepath->size < WP_PATH_MAX, "`filepath` exceeds max path limit.");
|
||||||
return _fileOpen(allocator, filepath, mode);
|
return fileOpen(allocator, filepath, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 wpFileGetCurrentPosition(WpFile *file) {
|
i64 wpFileGetCurrentPosition(WpFile *file) {
|
||||||
wpDebugAssert(file != NULL, "`file` should not be NULL.");
|
wpDebugAssert(file != NULL, "`file` should not be NULL.");
|
||||||
return _fileSeek(file, 0, WP_SEEK_CURRENT);
|
return fileSeek(file, 0, WP_SEEK_CURRENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 wpFileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) {
|
i64 wpFileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) {
|
||||||
wpDebugAssert(file != NULL, "`file` should not be NULL.");
|
wpDebugAssert(file != NULL, "`file` should not be NULL.");
|
||||||
return _fileSeek(file, offset, origin);
|
return fileSeek(file, offset, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 wpFileGetLength(WpFile *file) {
|
i64 wpFileGetLength(WpFile *file) {
|
||||||
@@ -28,12 +28,12 @@ i64 wpFileGetLength(WpFile *file) {
|
|||||||
|
|
||||||
i64 current = wpFileGetCurrentPosition(file);
|
i64 current = wpFileGetCurrentPosition(file);
|
||||||
|
|
||||||
_fileSeek(file, 0, WP_SEEK_END);
|
fileSeek(file, 0, WP_SEEK_END);
|
||||||
|
|
||||||
i64 output = wpFileGetCurrentPosition(file);
|
i64 output = wpFileGetCurrentPosition(file);
|
||||||
|
|
||||||
// Restore position
|
// Restore position
|
||||||
_fileSeek(file, current, WP_SEEK_START);
|
fileSeek(file, current, WP_SEEK_START);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -47,13 +47,13 @@ u64 wpFileRead(void *dst_buf, WpFile *file, u64 byte_count) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _fileRead(dst_buf, byte_count, file, file_length);
|
return fileRead(dst_buf, byte_count, file, file_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 wpFileWrite(const void *src_buf, WpFile *file, u64 byte_count) {
|
i64 wpFileWrite(const void *src_buf, WpFile *file, u64 byte_count) {
|
||||||
wpDebugAssert(src_buf != NULL && file != NULL,
|
wpDebugAssert(src_buf != NULL && file != NULL,
|
||||||
"`src_buf` and `file` should not be NULL.");
|
"`src_buf` and `file` should not be NULL.");
|
||||||
return _fileWrite(src_buf, file, byte_count);
|
return fileWrite(src_buf, file, byte_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 wpFileReadStr8(WpStr8 *str, WpFile *file) {
|
u64 wpFileReadStr8(WpStr8 *str, WpFile *file) {
|
||||||
@@ -87,7 +87,7 @@ u64 wpFileReadArray(WpArray dst_buf, WpFile *file, u64 item_count) {
|
|||||||
copy_byte_count = file_length <= dst_byte_capacity ? file_length : dst_byte_capacity;
|
copy_byte_count = file_length <= dst_byte_capacity ? file_length : dst_byte_capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 byte_count = _fileRead(dst_buf, copy_byte_count, file, file_length);
|
u64 byte_count = fileRead(dst_buf, copy_byte_count, file, file_length);
|
||||||
if (byte_count == 0) {
|
if (byte_count == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ i64 wpFileWriteArray(const WpArray src_buf, WpFile *file, u64 item_count) {
|
|||||||
u64 req_byte_count = item_count * item_size;
|
u64 req_byte_count = item_count * item_size;
|
||||||
u64 to_copy = req_byte_count <= src_byte_count ? req_byte_count : src_byte_count;
|
u64 to_copy = req_byte_count <= src_byte_count ? req_byte_count : src_byte_count;
|
||||||
|
|
||||||
i64 bytes_written = _fileWrite(src_buf, file, to_copy);
|
i64 bytes_written = fileWrite(src_buf, file, to_copy);
|
||||||
if (bytes_written < 0) {
|
if (bytes_written < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -116,12 +116,12 @@ i64 wpFileWriteArray(const WpArray src_buf, WpFile *file, u64 item_count) {
|
|||||||
|
|
||||||
i32 wpFileFlush(WpFile *file) {
|
i32 wpFileFlush(WpFile *file) {
|
||||||
wpDebugAssert(file != NULL, "`file` should not be NULL.");
|
wpDebugAssert(file != NULL, "`file` should not be NULL.");
|
||||||
return _fileFlush(file);
|
return fileFlush(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 wpFileClose(WpFile *file) {
|
i32 wpFileClose(WpFile *file) {
|
||||||
wpDebugAssert(file != NULL, "`file` should not be NULL.");
|
wpDebugAssert(file != NULL, "`file` should not be NULL.");
|
||||||
return _fileClose(file);
|
return fileClose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 wpFileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) {
|
i32 wpFileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) {
|
||||||
@@ -129,11 +129,11 @@ i32 wpFileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) {
|
|||||||
"`old_filepath` and `new_filepath` should not be NULL");
|
"`old_filepath` and `new_filepath` should not be NULL");
|
||||||
wpDebugAssert(old_filepath->size < WP_PATH_MAX, "`old_filepath` exceeds max path limit.");
|
wpDebugAssert(old_filepath->size < WP_PATH_MAX, "`old_filepath` exceeds max path limit.");
|
||||||
wpDebugAssert(new_filepath->size < WP_PATH_MAX, "`new_filepath` exceeds max path limit.");
|
wpDebugAssert(new_filepath->size < WP_PATH_MAX, "`new_filepath` exceeds max path limit.");
|
||||||
return _fileRename(old_filepath, new_filepath);
|
return fileRename(old_filepath, new_filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 wpFileRemove(WpStr8RO *filepath) {
|
i32 wpFileRemove(WpStr8RO *filepath) {
|
||||||
wpDebugAssert(filepath != NULL, "`filepath` should not be NULL");
|
wpDebugAssert(filepath != NULL, "`filepath` should not be NULL");
|
||||||
wpDebugAssert(filepath->size < WP_PATH_MAX, "`filepath` exceeds max path limit.");
|
wpDebugAssert(filepath->size < WP_PATH_MAX, "`filepath` exceeds max path limit.");
|
||||||
return _fileRemove(filepath);
|
return fileRemove(filepath);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -13,7 +13,7 @@ BEGIN_C_LINKAGE
|
|||||||
|
|
||||||
typedef struct WpFile WpFile;
|
typedef struct WpFile WpFile;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpFileAccessMode {
|
||||||
WP_ACCESS_READ, // Equivalent to r
|
WP_ACCESS_READ, // Equivalent to r
|
||||||
WP_ACCESS_WRITE, // Equivalent to w
|
WP_ACCESS_WRITE, // Equivalent to w
|
||||||
WP_ACCESS_APPEND, // Equivalent to a
|
WP_ACCESS_APPEND, // Equivalent to a
|
||||||
@@ -26,7 +26,7 @@ typedef enum {
|
|||||||
COUNT_FILE_ACCESS_MODE,
|
COUNT_FILE_ACCESS_MODE,
|
||||||
} WpFileAccessMode;
|
} WpFileAccessMode;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpFileSeekOrigin {
|
||||||
WP_SEEK_START,
|
WP_SEEK_START,
|
||||||
WP_SEEK_CURRENT,
|
WP_SEEK_CURRENT,
|
||||||
WP_SEEK_END,
|
WP_SEEK_END,
|
||||||
@@ -61,14 +61,14 @@ i32 wpFileClose(WpFile *file);
|
|||||||
i32 wpFileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath);
|
i32 wpFileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath);
|
||||||
i32 wpFileRemove(WpStr8RO *filepath);
|
i32 wpFileRemove(WpStr8RO *filepath);
|
||||||
|
|
||||||
wp_extern WpFile *_fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode);
|
wp_extern WpFile *fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode);
|
||||||
wp_extern i64 _fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin);
|
wp_extern i64 fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin);
|
||||||
wp_extern u64 _fileRead(void *dst_buf, u64 byte_count, WpFile *file, u64 file_length);
|
wp_extern u64 fileRead(void *dst_buf, u64 byte_count, WpFile *file, u64 file_length);
|
||||||
wp_extern i64 _fileWrite(const void *src_buf, WpFile *file, u64 byte_count);
|
wp_extern i64 fileWrite(const void *src_buf, WpFile *file, u64 byte_count);
|
||||||
wp_extern i32 _fileFlush(WpFile *file);
|
wp_extern i32 fileFlush(WpFile *file);
|
||||||
wp_extern i32 _fileClose(WpFile *file);
|
wp_extern i32 fileClose(WpFile *file);
|
||||||
wp_extern i32 _fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath);
|
wp_extern i32 fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath);
|
||||||
wp_extern i32 _fileRemove(WpStr8RO *filepath);
|
wp_extern i32 fileRemove(WpStr8RO *filepath);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ WpFile *wpFileStderr(void) {
|
|||||||
return &_stderr;
|
return &_stderr;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpFile *_fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode) {
|
WpFile *fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode) {
|
||||||
wp_persist c8 tmp[WP_PATH_MAX] = {0};
|
wp_persist c8 tmp[WP_PATH_MAX] = {0};
|
||||||
memset(tmp, 0, WP_PATH_MAX);
|
memset(tmp, 0, WP_PATH_MAX);
|
||||||
memcpy(tmp, filepath->buf, filepath->size);
|
memcpy(tmp, filepath->buf, filepath->size);
|
||||||
@@ -82,11 +82,11 @@ WpFile *_fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccess
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 _fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) {
|
i64 fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) {
|
||||||
return lseek64(file->fd, offset, file_seek_origins[origin]);
|
return lseek64(file->fd, offset, file_seek_origins[origin]);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 _fileRead(void *dst_buf, u64 byte_count, WpFile *file, u64 file_length) {
|
u64 fileRead(void *dst_buf, u64 byte_count, WpFile *file, u64 file_length) {
|
||||||
u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count;
|
u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count;
|
||||||
|
|
||||||
i64 count = read(file->fd, dst_buf, copy_byte_count);
|
i64 count = read(file->fd, dst_buf, copy_byte_count);
|
||||||
@@ -95,19 +95,19 @@ u64 _fileRead(void *dst_buf, u64 byte_count, WpFile *file, u64 file_length) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 _fileWrite(const void *src_buf, WpFile *file, u64 byte_count) {
|
i64 fileWrite(const void *src_buf, WpFile *file, u64 byte_count) {
|
||||||
return write(file->fd, src_buf, byte_count);
|
return write(file->fd, src_buf, byte_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 _fileFlush(WpFile *file) {
|
i32 fileFlush(WpFile *file) {
|
||||||
return fsync(file->fd);
|
return fsync(file->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 _fileClose(WpFile *file) {
|
i32 fileClose(WpFile *file) {
|
||||||
return close(file->fd);
|
return close(file->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 _fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) {
|
i32 fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) {
|
||||||
wp_persist c8 old_tmp[WP_PATH_MAX] = {0};
|
wp_persist c8 old_tmp[WP_PATH_MAX] = {0};
|
||||||
wp_persist c8 new_tmp[WP_PATH_MAX] = {0};
|
wp_persist c8 new_tmp[WP_PATH_MAX] = {0};
|
||||||
memset(old_tmp, 0, WP_PATH_MAX);
|
memset(old_tmp, 0, WP_PATH_MAX);
|
||||||
@@ -117,13 +117,13 @@ i32 _fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) {
|
|||||||
|
|
||||||
i32 link_result = link((const char *)old_tmp, (const char *)new_tmp);
|
i32 link_result = link((const char *)old_tmp, (const char *)new_tmp);
|
||||||
if (link_result == 0) {
|
if (link_result == 0) {
|
||||||
_fileRemove(old_filepath);
|
fileRemove(old_filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return link_result;
|
return link_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 _fileRemove(WpStr8RO *filepath) {
|
i32 fileRemove(WpStr8RO *filepath) {
|
||||||
wp_persist c8 tmp[WP_PATH_MAX] = {0};
|
wp_persist c8 tmp[WP_PATH_MAX] = {0};
|
||||||
memset(tmp, 0, WP_PATH_MAX);
|
memset(tmp, 0, WP_PATH_MAX);
|
||||||
memcpy(tmp, filepath->buf, filepath->size);
|
memcpy(tmp, filepath->buf, filepath->size);
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ WpFile *wpFileStderr(void) {
|
|||||||
return &_stderr;
|
return &_stderr;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpFile *_fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode) {
|
WpFile *fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode) {
|
||||||
wp_persist c8 tmp[WP_PATH_MAX] = {0};
|
wp_persist c8 tmp[WP_PATH_MAX] = {0};
|
||||||
memset(tmp, 0, WP_PATH_MAX);
|
memset(tmp, 0, WP_PATH_MAX);
|
||||||
memcpy(tmp, filepath->buf, filepath->size);
|
memcpy(tmp, filepath->buf, filepath->size);
|
||||||
@@ -96,7 +96,7 @@ WpFile *_fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccess
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 _fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) {
|
i64 fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) {
|
||||||
LARGE_INTEGER distance = {0};
|
LARGE_INTEGER distance = {0};
|
||||||
LARGE_INTEGER output = {0};
|
LARGE_INTEGER output = {0};
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ i64 _fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) {
|
|||||||
return output.QuadPart;
|
return output.QuadPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 _fileRead(void* dst_buf, u64 byte_count, WpFile* file, u64 file_length) {
|
u64 fileRead(void* dst_buf, u64 byte_count, WpFile* file, u64 file_length) {
|
||||||
u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count;
|
u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count;
|
||||||
wpDebugAssert(copy_byte_count <= DWORD_MAX, "Attempting to read large number of bytes at once");
|
wpDebugAssert(copy_byte_count <= DWORD_MAX, "Attempting to read large number of bytes at once");
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ u64 _fileRead(void* dst_buf, u64 byte_count, WpFile* file, u64 file_length) {
|
|||||||
return (u64)read_count;
|
return (u64)read_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 _fileWrite(const void *src_buf, WpFile *file, u64 byte_count) {
|
i64 fileWrite(const void *src_buf, WpFile *file, u64 byte_count) {
|
||||||
wpDebugAssert(byte_count <= DWORD_MAX, "Attempting to write large number of bytes at once");
|
wpDebugAssert(byte_count <= DWORD_MAX, "Attempting to write large number of bytes at once");
|
||||||
|
|
||||||
DWORD write_count = 0;
|
DWORD write_count = 0;
|
||||||
@@ -131,7 +131,7 @@ i64 _fileWrite(const void *src_buf, WpFile *file, u64 byte_count) {
|
|||||||
return (i64)write_count;
|
return (i64)write_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 _fileFlush(WpFile *file) {
|
i32 fileFlush(WpFile *file) {
|
||||||
if (!FlushFileBuffers(file->fh)) {
|
if (!FlushFileBuffers(file->fh)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ i32 _fileFlush(WpFile *file) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 _fileClose(WpFile *file) {
|
i32 fileClose(WpFile *file) {
|
||||||
if (!CloseHandle(file->fh)) {
|
if (!CloseHandle(file->fh)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,7 @@ i32 _fileClose(WpFile *file) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 _fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) {
|
i32 fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) {
|
||||||
wp_persist c8 old_tmp[WP_PATH_MAX] = {0};
|
wp_persist c8 old_tmp[WP_PATH_MAX] = {0};
|
||||||
wp_persist c8 new_tmp[WP_PATH_MAX] = {0};
|
wp_persist c8 new_tmp[WP_PATH_MAX] = {0};
|
||||||
memset(old_tmp, 0, WP_PATH_MAX);
|
memset(old_tmp, 0, WP_PATH_MAX);
|
||||||
@@ -162,7 +162,7 @@ i32 _fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 _fileRemove(WpStr8RO *filepath) {
|
i32 fileRemove(WpStr8RO *filepath) {
|
||||||
wp_persist c8 tmp[WP_PATH_MAX] = {0};
|
wp_persist c8 tmp[WP_PATH_MAX] = {0};
|
||||||
memset(tmp, 0, WP_PATH_MAX);
|
memset(tmp, 0, WP_PATH_MAX);
|
||||||
memcpy(tmp, filepath->buf, filepath->size);
|
memcpy(tmp, filepath->buf, filepath->size);
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void *wpOsMemAlloc(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type) {
|
void *wpOsMemAlloc(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type) {
|
||||||
void *output = _osMemAllocate(addr, size, access, flags, type);
|
void *output = osMemAllocate(addr, size, access, flags, type);
|
||||||
|
|
||||||
if (type == WP_MEM_INIT_INITIALISED) {
|
if (type == WP_MEM_INIT_INITIALISED) {
|
||||||
memset(output, 0, size);
|
memset(output, 0, size);
|
||||||
@@ -26,5 +26,5 @@ void *wpOsMemAlloc(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags fla
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wpOsMemFree(void *ptr, u64 size) {
|
void wpOsMemFree(void *ptr, u64 size) {
|
||||||
_osMemFree(ptr, size);
|
osMemFree(ptr, size);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -23,8 +23,8 @@ BEGIN_C_LINKAGE
|
|||||||
void *wpOsMemAlloc(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type);
|
void *wpOsMemAlloc(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type);
|
||||||
void wpOsMemFree(void *ptr, u64 size);
|
void wpOsMemFree(void *ptr, u64 size);
|
||||||
|
|
||||||
wp_extern void *_osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type);
|
wp_extern void *osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type);
|
||||||
wp_extern void _osMemFree(void *ptr, u64 size);
|
wp_extern void osMemFree(void *ptr, u64 size);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
BEGIN_C_LINKAGE
|
BEGIN_C_LINKAGE
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpMemAccess {
|
||||||
WP_MEM_ACCESS_NONE,
|
WP_MEM_ACCESS_NONE,
|
||||||
WP_MEM_ACCESS_READ_ONLY,
|
WP_MEM_ACCESS_READ_ONLY,
|
||||||
WP_MEM_ACCESS_EXEC_ONLY,
|
WP_MEM_ACCESS_EXEC_ONLY,
|
||||||
@@ -18,7 +18,7 @@ typedef enum {
|
|||||||
WP_MEM_ACCESS_READ_WRITE_EXEC,
|
WP_MEM_ACCESS_READ_WRITE_EXEC,
|
||||||
} WpMemAccess;
|
} WpMemAccess;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpMemInitType {
|
||||||
WP_MEM_INIT_UNINITIALISED,
|
WP_MEM_INIT_UNINITIALISED,
|
||||||
WP_MEM_INIT_INITIALISED,
|
WP_MEM_INIT_INITIALISED,
|
||||||
} WpMemInitType;
|
} WpMemInitType;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ wp_intern const i32 access_types[] = {
|
|||||||
[WP_MEM_ACCESS_READ_WRITE_EXEC] = PROT_READ | PROT_WRITE | PROT_EXEC,
|
[WP_MEM_ACCESS_READ_WRITE_EXEC] = PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||||
};
|
};
|
||||||
|
|
||||||
void *_osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type) {
|
void *osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type) {
|
||||||
(void)type;
|
(void)type;
|
||||||
i32 alloc_flags = flags | MAP_ANON | MAP_PRIVATE;
|
i32 alloc_flags = flags | MAP_ANON | MAP_PRIVATE;
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ void *_osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags f
|
|||||||
return mmap(addr, size, access_types[access], alloc_flags, -1, 0);
|
return mmap(addr, size, access_types[access], alloc_flags, -1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _osMemFree(void *ptr, u64 size) {
|
void osMemFree(void *ptr, u64 size) {
|
||||||
munmap(ptr, size);
|
munmap(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ BEGIN_C_LINKAGE
|
|||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpMemAllocFlags {
|
||||||
#if defined(WP_PLATFORM_LINUX) || defined(WP_PLATFORM_GNU)
|
#if defined(WP_PLATFORM_LINUX) || defined(WP_PLATFORM_GNU)
|
||||||
WP_MEM_ALLOC_RESERVE = 0,
|
WP_MEM_ALLOC_RESERVE = 0,
|
||||||
WP_MEM_ALLOC_COMMIT = MAP_POPULATE,
|
WP_MEM_ALLOC_COMMIT = MAP_POPULATE,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ wp_intern const i32 access_types[] = {
|
|||||||
[WP_MEM_ACCESS_READ_WRITE_EXEC] = PAGE_EXECUTE_READWRITE,
|
[WP_MEM_ACCESS_READ_WRITE_EXEC] = PAGE_EXECUTE_READWRITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
void *_osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type) {
|
void *osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type) {
|
||||||
// Ensure memory is committed if it's meant to be initialised
|
// Ensure memory is committed if it's meant to be initialised
|
||||||
if (type == WP_MEM_INIT_INITIALISED) {
|
if (type == WP_MEM_INIT_INITIALISED) {
|
||||||
flags |= WP_MEM_ALLOC_COMMIT;
|
flags |= WP_MEM_ALLOC_COMMIT;
|
||||||
@@ -30,7 +30,7 @@ void *_osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags f
|
|||||||
return VirtualAlloc(addr, (SIZE_T)size, flags, access_types[access]);
|
return VirtualAlloc(addr, (SIZE_T)size, flags, access_types[access]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _osMemFree(void *ptr, u64 size) {
|
void osMemFree(void *ptr, u64 size) {
|
||||||
VirtualFree(ptr, size, MEM_RELEASE);
|
VirtualFree(ptr, size, MEM_RELEASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ BEGIN_C_LINKAGE
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <memoryapi.h>
|
#include <memoryapi.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpMemAllocFlags {
|
||||||
WP_MEM_ALLOC_RESERVE = MEM_RESERVE,
|
WP_MEM_ALLOC_RESERVE = MEM_RESERVE,
|
||||||
WP_MEM_ALLOC_COMMIT = MEM_COMMIT,
|
WP_MEM_ALLOC_COMMIT = MEM_COMMIT,
|
||||||
} WpMemAllocFlags;
|
} WpMemAllocFlags;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ wp_intern WpCmdResult executeCommand(WpStr8RO *cmd, WpCmdOutHandling out_handlin
|
|||||||
}
|
}
|
||||||
|
|
||||||
i32 st = EXIT_SUCCESS;
|
i32 st = EXIT_SUCCESS;
|
||||||
err = _getOutputStatus(fp, &st);
|
err = getOutputStatus(fp, &st);
|
||||||
if (err > WP_SHELL_ERR_NO_ERROR) {
|
if (err > WP_SHELL_ERR_NO_ERROR) {
|
||||||
output = wpCmdNoExit(err);
|
output = wpCmdNoExit(err);
|
||||||
goto executeCommand_CLOSE;
|
goto executeCommand_CLOSE;
|
||||||
@@ -94,7 +94,7 @@ wp_intern WpCmdError getCommandOutput(FILE *fp, WpCmdOutHandling out_handling, W
|
|||||||
|
|
||||||
wpStr8ConcatCapped(out_buf, &out);
|
wpStr8ConcatCapped(out_buf, &out);
|
||||||
} else if (out_handling == WP_SHELL_OUTPUT_PRINT) {
|
} else if (out_handling == WP_SHELL_OUTPUT_PRINT) {
|
||||||
printf(WP_STR8_SPEC, wpStr8Varg(out));
|
printf("%" WP_STR8_SPEC, wpStr8Varg(out));
|
||||||
}
|
}
|
||||||
|
|
||||||
return WP_SHELL_ERR_NO_ERROR;
|
return WP_SHELL_ERR_NO_ERROR;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ BEGIN_C_LINKAGE
|
|||||||
|
|
||||||
WpCmdResult wpShellCommanderExecute(WpCmdOutHandling out_handling, WpStr8 *out_buf, const WpStr8List *cmd);
|
WpCmdResult wpShellCommanderExecute(WpCmdOutHandling out_handling, WpStr8 *out_buf, const WpStr8List *cmd);
|
||||||
|
|
||||||
wp_extern WpCmdError _getOutputStatus(FILE *fp, i32 *status_out);
|
wp_extern WpCmdError getOutputStatus(FILE *fp, i32 *status_out);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
@@ -11,13 +11,13 @@
|
|||||||
BEGIN_C_LINKAGE
|
BEGIN_C_LINKAGE
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpCmdOutHandling {
|
||||||
WP_SHELL_OUTPUT_DISCARD,
|
WP_SHELL_OUTPUT_DISCARD,
|
||||||
WP_SHELL_OUTPUT_PRINT,
|
WP_SHELL_OUTPUT_PRINT,
|
||||||
WP_SHELL_OUTPUT_CAPTURE,
|
WP_SHELL_OUTPUT_CAPTURE,
|
||||||
} WpCmdOutHandling;
|
} WpCmdOutHandling;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpCmdError {
|
||||||
WP_SHELL_ERR_NO_ERROR,
|
WP_SHELL_ERR_NO_ERROR,
|
||||||
WP_SHELL_ERR_INVALID_ARGS,
|
WP_SHELL_ERR_INVALID_ARGS,
|
||||||
WP_SHELL_ERR_ALLOCATION_FAIL,
|
WP_SHELL_ERR_ALLOCATION_FAIL,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
WpCmdError _getOutputStatus(FILE *fp, i32 *status_out) {
|
WpCmdError getOutputStatus(FILE *fp, i32 *status_out) {
|
||||||
*status_out = wpShellUtilsPclose(fp);
|
*status_out = wpShellUtilsPclose(fp);
|
||||||
|
|
||||||
if (!WIFEXITED(*status_out)) {
|
if (!WIFEXITED(*status_out)) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "../../utils/shell_utils.h"
|
#include "../../utils/shell_utils.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
WpCmdError _getOutputStatus(FILE *fp, i32 *status_out) {
|
WpCmdError getOutputStatus(FILE *fp, i32 *status_out) {
|
||||||
if (!feof(fp)) {
|
if (!feof(fp)) {
|
||||||
// Ensure process is closed on failure
|
// Ensure process is closed on failure
|
||||||
wpShellUtilsPclose(fp);
|
wpShellUtilsPclose(fp);
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ wp_intern WpStr8RO colours[COUNT_TERM_COLOUR] = {
|
|||||||
[WP_TERM_COLOUR_CLEAR] = wpStr8LitRoInitialiserList("\033[0m"),
|
[WP_TERM_COLOUR_CLEAR] = wpStr8LitRoInitialiserList("\033[0m"),
|
||||||
};
|
};
|
||||||
|
|
||||||
void _printColouredText(WpStr8RO *text, WpTerminalColour colour) {
|
void printColouredText(WpStr8RO *text, WpTerminalColour colour) {
|
||||||
printf(WP_STR8_SPEC WP_STR8_SPEC, wpStr8Varg(colours[colour]), wpStr8Varg((*text)));
|
printf("%" WP_STR8_SPEC "%" WP_STR8_SPEC, wpStr8Varg(colours[colour]), wpStr8Varg((*text)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !WP_PLATFORM_POSIX
|
#endif // !WP_PLATFORM_POSIX
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ void wpShellTermcolourPrintText(WpStr8RO *text, WpTerminalColour colour) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_printColouredText(text, colour);
|
printColouredText(text, colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wpShellTermcolourClearColour(void) {
|
void wpShellTermcolourClearColour(void) {
|
||||||
WpStr8RO empty = wpStr8LitRo("");
|
WpStr8RO empty = wpStr8LitRo("");
|
||||||
_printColouredText(&empty, WP_TERM_COLOUR_CLEAR);
|
printColouredText(&empty, WP_TERM_COLOUR_CLEAR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ BEGIN_C_LINKAGE
|
|||||||
void wpShellTermcolourPrintText(WpStr8RO *text, WpTerminalColour colour);
|
void wpShellTermcolourPrintText(WpStr8RO *text, WpTerminalColour colour);
|
||||||
void wpShellTermcolourClearColour(void);
|
void wpShellTermcolourClearColour(void);
|
||||||
|
|
||||||
wp_extern void _printColouredText(WpStr8RO *text, WpTerminalColour colour);
|
wp_extern void printColouredText(WpStr8RO *text, WpTerminalColour colour);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
BEGIN_C_LINKAGE
|
BEGIN_C_LINKAGE
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
typedef enum {
|
typedef enum WpTerminalColour {
|
||||||
WP_TERM_COLOUR_FG_BLACK,
|
WP_TERM_COLOUR_FG_BLACK,
|
||||||
WP_TERM_COLOUR_FG_RED,
|
WP_TERM_COLOUR_FG_RED,
|
||||||
WP_TERM_COLOUR_FG_GREEN,
|
WP_TERM_COLOUR_FG_GREEN,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ struct TermcolourData {
|
|||||||
wpMiscUtilsReservePadding(sizeof(HANDLE) + sizeof(WORD) + sizeof(WORD));
|
wpMiscUtilsReservePadding(sizeof(HANDLE) + sizeof(WORD) + sizeof(WORD));
|
||||||
};
|
};
|
||||||
|
|
||||||
wp_intern void init_data(TermcolourData *data);
|
wp_intern void initData(TermcolourData *data);
|
||||||
|
|
||||||
wp_intern WORD colours[COUNT_TERM_COLOUR] = {
|
wp_intern WORD colours[COUNT_TERM_COLOUR] = {
|
||||||
[WP_TERM_COLOUR_FG_BLACK] = 0,
|
[WP_TERM_COLOUR_FG_BLACK] = 0,
|
||||||
@@ -43,10 +43,10 @@ wp_intern WORD colours[COUNT_TERM_COLOUR] = {
|
|||||||
[WP_TERM_COLOUR_FG_BR_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
[WP_TERM_COLOUR_FG_BR_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||||
};
|
};
|
||||||
|
|
||||||
void _printColouredText(WpStr8RO *text, WpTerminalColour colour) {
|
void printColouredText(WpStr8RO *text, WpTerminalColour colour) {
|
||||||
wp_persist TermcolourData data = {0};
|
wp_persist TermcolourData data = {0};
|
||||||
if (data.handle == 0) {
|
if (data.handle == 0) {
|
||||||
init_data(&data);
|
initData(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (colour == WP_TERM_COLOUR_CLEAR) {
|
if (colour == WP_TERM_COLOUR_CLEAR) {
|
||||||
@@ -56,10 +56,10 @@ void _printColouredText(WpStr8RO *text, WpTerminalColour colour) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetConsoleTextAttribute(data.handle, data.current_colour);
|
SetConsoleTextAttribute(data.handle, data.current_colour);
|
||||||
printf(WP_STR8_SPEC, wpStr8Varg((*text)));
|
printf("%" WP_STR8_SPEC, wpStr8Varg((*text)));
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void init_data(TermcolourData *data) {
|
wp_intern void initData(TermcolourData *data) {
|
||||||
// create handle
|
// create handle
|
||||||
data->handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
data->handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "splitmix64.h"
|
||||||
|
#include "../../common/aliases/aliases.h"
|
||||||
|
#include "../../common/assert/assert.h"
|
||||||
|
#include "../../common/platform/platform.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
wp_intern void seedOsGenerator(u64 seed);
|
||||||
|
wp_intern u64 genRandomNumber(void);
|
||||||
|
|
||||||
|
WpSplitmix64State wpPrngSplitmix64Init(void) {
|
||||||
|
wp_persist b8 seeded = false;
|
||||||
|
if (!seeded) {
|
||||||
|
seeded = true;
|
||||||
|
seedOsGenerator(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (WpSplitmix64State){ .seed = genRandomNumber() };
|
||||||
|
}
|
||||||
|
|
||||||
|
WpSplitmix64State wpPrngSplitmix64InitWithSeed(u64 seed) {
|
||||||
|
return (WpSplitmix64State){ .seed = seed };
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 wpPrngSplitmix64(WpSplitmix64State *state) {
|
||||||
|
state->seed += 0x9E3779B97f4A7C15;
|
||||||
|
|
||||||
|
u64 result = state->seed;
|
||||||
|
result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9;
|
||||||
|
result = (result ^ (result >> 27)) * 0x94D049BB133111EB;
|
||||||
|
|
||||||
|
return result ^ (result >> 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 wpPrngSplitmix64InRange(WpSplitmix64State *state, u64 start, u64 end) {
|
||||||
|
return wpPrngSplitmix64(state) % (end - start) + start;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 wpPrngSplitmix64Choice(WpSplitmix64State *state, u64 available_choices) {
|
||||||
|
return wpPrngSplitmix64(state) % available_choices;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(WP_PLATFORM_C) && WP_PLATFORM_C_VERSION >= WP_PLATFORM_C11_VERSION
|
||||||
|
#ifdef WP_PLATFORM_POSIX
|
||||||
|
wp_intern void seedOsGenerator(u64 seed) {
|
||||||
|
if (seed == 0) {
|
||||||
|
struct timespec ts = {0};
|
||||||
|
int result = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||||
|
wpRuntimeAssert(result == 0, "Invalid seed value");
|
||||||
|
seed = (u64)ts.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
srand48(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_intern u64 genRandomNumber(void) {
|
||||||
|
return lrand48();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
wp_intern void seedOsGenerator(u64 seed) {
|
||||||
|
if (seed == 0) {
|
||||||
|
struct timespec ts = {0};
|
||||||
|
int result = timespec_get(&ts, TIME_UTC);
|
||||||
|
wpRuntimeAssert(result != 0, "Invalid seed value");
|
||||||
|
seed = (u64)ts.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
srand(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_intern u64 genRandomNumber(void) {
|
||||||
|
i32 n1 = rand();
|
||||||
|
i32 n2 = rand();
|
||||||
|
|
||||||
|
return (((u64)n1) << 32 | (u64)n2);
|
||||||
|
}
|
||||||
|
#endif // !WP_PLATFORM_POSIX
|
||||||
|
#else
|
||||||
|
wp_intern void seedOsGenerator(u64 seed) {
|
||||||
|
if (seed == 0) {
|
||||||
|
time_t result = time(NULL);
|
||||||
|
wpRuntimeAssert(result != (time_t)(-1), "Invalid seed value");
|
||||||
|
seed = (u64)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
srand(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_intern u64 genRandomNumber(void) {
|
||||||
|
i32 n1 = rand();
|
||||||
|
i32 n2 = rand();
|
||||||
|
|
||||||
|
return (((u64)n1) << 32 | (u64)n2);
|
||||||
|
}
|
||||||
|
#endif // !WP_PLATFORM_C
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#ifndef SPLITMIX64_H
|
||||||
|
#define SPLITMIX64_H
|
||||||
|
|
||||||
|
#include "../../common/aliases/aliases.h"
|
||||||
|
|
||||||
|
typedef struct WpSplitmix64State {
|
||||||
|
u64 seed;
|
||||||
|
} WpSplitmix64State;
|
||||||
|
|
||||||
|
WpSplitmix64State wpPrngSplitmix64Init(void);
|
||||||
|
WpSplitmix64State wpPrngSplitmix64InitWithSeed(u64 seed);
|
||||||
|
u64 wpPrngSplitmix64(WpSplitmix64State *state);
|
||||||
|
u64 wpPrngSplitmix64InRange(WpSplitmix64State *state, u64 start, u64 end);
|
||||||
|
u64 wpPrngSplitmix64Choice(WpSplitmix64State *state, u64 available_choices);
|
||||||
|
|
||||||
|
#endif // !SPLITMIX64_H
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#ifndef WAPP_PRNG_C
|
#ifndef WAPP_PRNG_C
|
||||||
#define WAPP_PRNG_C
|
#define WAPP_PRNG_C
|
||||||
|
|
||||||
|
#include "splitmix64/splitmix64.c"
|
||||||
#include "xorshift/xorshift.c"
|
#include "xorshift/xorshift.c"
|
||||||
|
|
||||||
#endif // !WAPP_PRNG_C
|
#endif // !WAPP_PRNG_C
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#ifndef WAPP_PRNG_H
|
#ifndef WAPP_PRNG_H
|
||||||
#define WAPP_PRNG_H
|
#define WAPP_PRNG_H
|
||||||
|
|
||||||
|
#include "splitmix64/splitmix64.h"
|
||||||
#include "xorshift/xorshift.h"
|
#include "xorshift/xorshift.h"
|
||||||
#include "../common/wapp_common.h"
|
#include "../common/wapp_common.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +1,29 @@
|
|||||||
// vim:fileencoding=utf-8:foldmethod=marker
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
#include "xorshift.h"
|
#include "xorshift.h"
|
||||||
|
#include "../splitmix64/splitmix64.h"
|
||||||
#include "../../common/aliases/aliases.h"
|
#include "../../common/aliases/aliases.h"
|
||||||
#include "../../common/assert/assert.h"
|
#include "../../common/misc/misc_utils.h"
|
||||||
#include "../../common/platform/platform.h"
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
typedef struct SplitMix64State SplitMix64State;
|
|
||||||
struct SplitMix64State {
|
|
||||||
u64 seed;
|
|
||||||
};
|
|
||||||
|
|
||||||
wp_intern u64 rol64(u64 x, u64 bits);
|
|
||||||
wp_intern u64 split_mix_64(SplitMix64State *state);
|
|
||||||
wp_intern void seed_os_generator(void);
|
|
||||||
wp_intern u64 generate_random_number(void);
|
|
||||||
|
|
||||||
WpXor256State wpPrngXorshiftInit(void) {
|
WpXor256State wpPrngXorshiftInit(void) {
|
||||||
wp_persist b8 seeded = false;
|
return wpPrngXorshiftInitWithSeed(0);
|
||||||
if (!seeded) {
|
}
|
||||||
seeded = true;
|
|
||||||
seed_os_generator();
|
WpXor256State wpPrngXorshiftInitWithSeed(u64 seed) {
|
||||||
|
WpSplitmix64State sm64;
|
||||||
|
if (seed > 0) {
|
||||||
|
sm64 = wpPrngSplitmix64InitWithSeed(seed);
|
||||||
|
} else {
|
||||||
|
sm64 = wpPrngSplitmix64Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
SplitMix64State sm64 = {.seed = generate_random_number()};
|
|
||||||
|
|
||||||
return (WpXor256State){
|
return (WpXor256State){
|
||||||
.x = split_mix_64(&sm64),
|
.x = wpPrngSplitmix64(&sm64),
|
||||||
.y = split_mix_64(&sm64),
|
.y = wpPrngSplitmix64(&sm64),
|
||||||
.z = split_mix_64(&sm64),
|
.z = wpPrngSplitmix64(&sm64),
|
||||||
.w = split_mix_64(&sm64),
|
.w = wpPrngSplitmix64(&sm64),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +39,7 @@ u64 wpPrngXorshift256(WpXor256State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 wpPrngXorshift256ss(WpXor256State *state) {
|
u64 wpPrngXorshift256ss(WpXor256State *state) {
|
||||||
const u64 result = rol64(state->z * 5, 7) * 9;
|
const u64 result = wpMiscUtilsRotl64(state->z * 5, 7) * 9;
|
||||||
const u64 t = state->z << 17;
|
const u64 t = state->z << 17;
|
||||||
|
|
||||||
state->y ^= state->w;
|
state->y ^= state->w;
|
||||||
@@ -55,7 +48,7 @@ u64 wpPrngXorshift256ss(WpXor256State *state) {
|
|||||||
state->w ^= state->x;
|
state->w ^= state->x;
|
||||||
|
|
||||||
state->y ^= t;
|
state->y ^= t;
|
||||||
state->x = rol64(state->x, 45);
|
state->x = wpMiscUtilsRotl64(state->x, 45);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -70,66 +63,31 @@ u64 wpPrngXorshift256p(WpXor256State *state) {
|
|||||||
state->w ^= state->x;
|
state->w ^= state->x;
|
||||||
|
|
||||||
state->y ^= t;
|
state->y ^= t;
|
||||||
state->x = rol64(state->x, 45);
|
state->x = wpMiscUtilsRotl64(state->x, 45);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern u64 rol64(u64 x, u64 bits) {
|
u64 wpPrngXorshift256InRange(WpXor256State *state, u64 start, u64 end) {
|
||||||
return (x << bits) | (x >> (64 - bits));
|
return wpPrngXorshift256(state) % (end - start) + start;
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern u64 split_mix_64(SplitMix64State *state) {
|
u64 wpPrngXorshift256ssInRange(WpXor256State *state, u64 start, u64 end) {
|
||||||
state->seed += 0x9E3779B97f4A7C15;
|
return wpPrngXorshift256ss(state) % (end - start) + start;
|
||||||
|
|
||||||
u64 result = state->seed;
|
|
||||||
result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9;
|
|
||||||
result = (result ^ (result >> 27)) * 0x94D049BB133111EB;
|
|
||||||
|
|
||||||
return result ^ (result >> 31);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(WP_PLATFORM_C) && WP_PLATFORM_C_VERSION >= WP_PLATFORM_C11_VERSION
|
u64 wpPrngXorshift256pInRange(WpXor256State *state, u64 start, u64 end) {
|
||||||
#ifdef WP_PLATFORM_POSIX
|
return wpPrngXorshift256p(state) % (end - start) + start;
|
||||||
wp_intern void seed_os_generator(void) {
|
|
||||||
struct timespec ts = {0};
|
|
||||||
int result = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
|
||||||
wpRuntimeAssert(result == 0, "Invalid seed value");
|
|
||||||
|
|
||||||
srand48(ts.tv_nsec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern u64 generate_random_number(void) {
|
u64 wpPrngXorshift256Choice(WpXor256State *state, u64 available_choices) {
|
||||||
return lrand48();
|
return wpPrngXorshift256(state) % available_choices;
|
||||||
}
|
|
||||||
#else
|
|
||||||
wp_intern void seed_os_generator(void) {
|
|
||||||
struct timespec ts = {0};
|
|
||||||
int result = timespec_get(&ts, TIME_UTC);
|
|
||||||
wpRuntimeAssert(result != 0, "Invalid seed value");
|
|
||||||
|
|
||||||
srand(ts.tv_nsec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern u64 generate_random_number(void) {
|
u64 wpPrngXorshift256ssChoice(WpXor256State *state, u64 available_choices) {
|
||||||
i32 n1 = rand();
|
return wpPrngXorshift256ss(state) % available_choices;
|
||||||
i32 n2 = rand();
|
|
||||||
|
|
||||||
return (((u64)n1) << 32 | (u64)n2);
|
|
||||||
}
|
|
||||||
#endif // !WP_PLATFORM_POSIX
|
|
||||||
#else
|
|
||||||
wp_intern void seed_os_generator(void) {
|
|
||||||
time_t result = time(NULL);
|
|
||||||
wpRuntimeAssert(result != (time_t)(-1), "Invalid seed value");
|
|
||||||
|
|
||||||
srand(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern u64 generate_random_number(void) {
|
u64 wpPrngXorshift256pChoice(WpXor256State *state, u64 available_choices) {
|
||||||
i32 n1 = rand();
|
return wpPrngXorshift256p(state) % available_choices;
|
||||||
i32 n2 = rand();
|
|
||||||
|
|
||||||
return (((u64)n1) << 32 | (u64)n2);
|
|
||||||
}
|
}
|
||||||
#endif // !WP_PLATFORM_C
|
|
||||||
|
|||||||
@@ -19,9 +19,16 @@ struct WpXor256State {
|
|||||||
};
|
};
|
||||||
|
|
||||||
WpXor256State wpPrngXorshiftInit(void);
|
WpXor256State wpPrngXorshiftInit(void);
|
||||||
|
WpXor256State wpPrngXorshiftInitWithSeed(u64 seed);
|
||||||
u64 wpPrngXorshift256(WpXor256State *state);
|
u64 wpPrngXorshift256(WpXor256State *state);
|
||||||
u64 wpPrngXorshift256ss(WpXor256State *state);
|
u64 wpPrngXorshift256ss(WpXor256State *state);
|
||||||
u64 wpPrngXorshift256p(WpXor256State *state);
|
u64 wpPrngXorshift256p(WpXor256State *state);
|
||||||
|
u64 wpPrngXorshift256InRange(WpXor256State *state, u64 start, u64 end);
|
||||||
|
u64 wpPrngXorshift256ssInRange(WpXor256State *state, u64 start, u64 end);
|
||||||
|
u64 wpPrngXorshift256pInRange(WpXor256State *state, u64 start, u64 end);
|
||||||
|
u64 wpPrngXorshift256Choice(WpXor256State *state, u64 available_choices);
|
||||||
|
u64 wpPrngXorshift256ssChoice(WpXor256State *state, u64 available_choices);
|
||||||
|
u64 wpPrngXorshift256pChoice(WpXor256State *state, u64 available_choices);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
wp_intern void handleTestResult(WpTestFuncResult result);
|
wp_intern void handleTestResult(WpTestFuncResult result);
|
||||||
|
|
||||||
void _runTests(WpTestFunc *func1, ...) {
|
void runTests(WpTestFunc *func1, ...) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
handleTestResult(func1());
|
handleTestResult(func1());
|
||||||
@@ -47,7 +47,7 @@ wp_intern void handleTestResult(WpTestFuncResult result) {
|
|||||||
printf("[");
|
printf("[");
|
||||||
wpShellTermcolourPrintText(&result_text, colour);
|
wpShellTermcolourPrintText(&result_text, colour);
|
||||||
wpShellTermcolourClearColour();
|
wpShellTermcolourClearColour();
|
||||||
printf("] " WP_STR8_SPEC "\n", wpStr8Varg(result.name));
|
printf("] %" WP_STR8_SPEC "\n", wpStr8Varg(result.name));
|
||||||
|
|
||||||
if (!result.passed) {
|
if (!result.passed) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ BEGIN_C_LINKAGE
|
|||||||
#define wpTesterResult(PASSED) ((WpTestFuncResult){.name = wpStr8LitRo(__func__), .passed = PASSED})
|
#define wpTesterResult(PASSED) ((WpTestFuncResult){.name = wpStr8LitRo(__func__), .passed = PASSED})
|
||||||
#endif // !WP_PLATFORM_CPP
|
#endif // !WP_PLATFORM_CPP
|
||||||
|
|
||||||
#define wpTesterRun(...) _runTests(__VA_ARGS__, NULL)
|
#define wpTesterRun(...) runTests(__VA_ARGS__, NULL)
|
||||||
|
|
||||||
typedef struct WpTestFuncResult WpTestFuncResult;
|
typedef struct WpTestFuncResult WpTestFuncResult;
|
||||||
struct WpTestFuncResult {
|
struct WpTestFuncResult {
|
||||||
@@ -27,7 +27,7 @@ struct WpTestFuncResult {
|
|||||||
|
|
||||||
typedef WpTestFuncResult(WpTestFunc)(void);
|
typedef WpTestFuncResult(WpTestFunc)(void);
|
||||||
|
|
||||||
void _runTests(WpTestFunc *func1, ...);
|
void runTests(WpTestFunc *func1, ...);
|
||||||
|
|
||||||
#ifdef WP_PLATFORM_CPP
|
#ifdef WP_PLATFORM_CPP
|
||||||
END_C_LINKAGE
|
END_C_LINKAGE
|
||||||
|
|||||||
+6
-6
@@ -15,19 +15,19 @@ struct UUID4 {
|
|||||||
u64 low;
|
u64 low;
|
||||||
};
|
};
|
||||||
|
|
||||||
wp_intern UUID4 generate_uuid4(void);
|
wp_intern UUID4 genUuid4(void);
|
||||||
wp_intern void uuid4_to_uuid(const UUID4* uuid4, WpUuid *uuid);
|
wp_intern void uuid4ToUuid(const UUID4* uuid4, WpUuid *uuid);
|
||||||
|
|
||||||
WpUuid *wpUuidInitUuid4(WpUuid *uuid) {
|
WpUuid *wpUuidInitUuid4(WpUuid *uuid) {
|
||||||
wpDebugAssert(uuid != NULL, "`uuid` should not be NULL");
|
wpDebugAssert(uuid != NULL, "`uuid` should not be NULL");
|
||||||
|
|
||||||
UUID4 uuid4 = generate_uuid4();
|
UUID4 uuid4 = genUuid4();
|
||||||
uuid4_to_uuid(&uuid4, uuid);
|
uuid4ToUuid(&uuid4, uuid);
|
||||||
|
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern UUID4 generate_uuid4(void) {
|
wp_intern UUID4 genUuid4(void) {
|
||||||
wp_persist WpXor256State state = {0};
|
wp_persist WpXor256State state = {0};
|
||||||
wp_persist b8 initialised = false;
|
wp_persist b8 initialised = false;
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ wp_intern UUID4 generate_uuid4(void) {
|
|||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void uuid4_to_uuid(const UUID4* uuid4, WpUuid *uuid) {
|
wp_intern void uuid4ToUuid(const UUID4* uuid4, WpUuid *uuid) {
|
||||||
u64 group1 = uuid4->high >> 32;
|
u64 group1 = uuid4->high >> 32;
|
||||||
u64 group2 = (uuid4->high << 32) >> 48;
|
u64 group2 = (uuid4->high << 32) >> 48;
|
||||||
u64 group3 = (uuid4->high << 48) >> 48;
|
u64 group3 = (uuid4->high << 48) >> 48;
|
||||||
|
|||||||
@@ -245,6 +245,19 @@ WpTestFuncResult test_i32_array_copy_alloc(void) {
|
|||||||
return wpTesterResult(result);
|
return wpTesterResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_i32_array_remove_swap_end(void) {
|
||||||
|
b8 result;
|
||||||
|
|
||||||
|
WpI32Array array = wpArray(i32, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||||
|
result = wpArrayCount(array) == 9 && array[4] == 4;
|
||||||
|
|
||||||
|
wpArrayRemoveSwapEnd(i32, array, 4);
|
||||||
|
|
||||||
|
result = result && wpArrayCount(array) == 8 && array[4] == 8;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
WpTestFuncResult test_i32_array_pop(void) {
|
WpTestFuncResult test_i32_array_pop(void) {
|
||||||
b8 result;
|
b8 result;
|
||||||
|
|
||||||
|
|||||||
@@ -261,6 +261,19 @@ WpTestFuncResult test_i32_array_clear(void) {
|
|||||||
return wpTesterResult(result);
|
return wpTesterResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_i32_array_remove_swap_end(void) {
|
||||||
|
b8 result;
|
||||||
|
|
||||||
|
WpI32Array array = wpArray(i32, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||||
|
result = wpArrayCount(array) == 9 && array[4] == 4;
|
||||||
|
|
||||||
|
wpArrayRemoveSwapEnd(i32, array, 4);
|
||||||
|
|
||||||
|
result = result && wpArrayCount(array) == 8 && array[4] == 8;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
WpTestFuncResult test_i32_array_pop(void) {
|
WpTestFuncResult test_i32_array_pop(void) {
|
||||||
b8 result;
|
b8 result;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ WpTestFuncResult test_i32_array_alloc_capacity(void);
|
|||||||
WpTestFuncResult test_i32_array_append_alloc(void);
|
WpTestFuncResult test_i32_array_append_alloc(void);
|
||||||
WpTestFuncResult test_i32_array_extend_alloc(void);
|
WpTestFuncResult test_i32_array_extend_alloc(void);
|
||||||
WpTestFuncResult test_i32_array_copy_alloc(void);
|
WpTestFuncResult test_i32_array_copy_alloc(void);
|
||||||
|
WpTestFuncResult test_i32_array_remove_swap_end(void);
|
||||||
WpTestFuncResult test_i32_array_pop(void);
|
WpTestFuncResult test_i32_array_pop(void);
|
||||||
WpTestFuncResult test_i32_array_clear(void);
|
WpTestFuncResult test_i32_array_clear(void);
|
||||||
|
|
||||||
|
|||||||
@@ -144,35 +144,35 @@ WpTestFuncResult test_cpath_dirup(void) {
|
|||||||
wpStr8Format(&tmp, "%c", WP_PATH_SEP);
|
wpStr8Format(&tmp, "%c", WP_PATH_SEP);
|
||||||
wpStr8Format(&expected, "%c", WP_PATH_SEP);
|
wpStr8Format(&expected, "%c", WP_PATH_SEP);
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 3);
|
output = wpCpathDirUp(&arena, &tmp, 3);
|
||||||
result = output != NULL && wpStr8Equal(output, &expected);
|
result = output != NULL && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
// CASE 2
|
// CASE 2
|
||||||
wpStr8Format(&tmp, "%chome%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP, WP_PATH_SEP);
|
wpStr8Format(&tmp, "%chome%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP, WP_PATH_SEP);
|
||||||
wpStr8Format(&expected, "%c", WP_PATH_SEP);
|
wpStr8Format(&expected, "%c", WP_PATH_SEP);
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 3);
|
output = wpCpathDirUp(&arena, &tmp, 3);
|
||||||
result = result && output != NULL && wpStr8Equal(output, &expected);
|
result = result && output != NULL && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
// CASE 3
|
// CASE 3
|
||||||
wpStr8Format(&tmp, "home%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP);
|
wpStr8Format(&tmp, "home%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP);
|
||||||
wpStr8CopyCstrCapped(&expected, ".");
|
wpStr8CopyCstrCapped(&expected, ".");
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 3);
|
output = wpCpathDirUp(&arena, &tmp, 3);
|
||||||
result = result && output != NULL && wpStr8Equal(output, &expected);
|
result = result && output != NULL && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
// CASE 4
|
// CASE 4
|
||||||
wpStr8Format(&tmp, "%chome%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP, WP_PATH_SEP);
|
wpStr8Format(&tmp, "%chome%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP, WP_PATH_SEP);
|
||||||
wpStr8Format(&expected, "%chome", WP_PATH_SEP);
|
wpStr8Format(&expected, "%chome", WP_PATH_SEP);
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 2);
|
output = wpCpathDirUp(&arena, &tmp, 2);
|
||||||
result = result && output != NULL && wpStr8Equal(output, &expected);
|
result = result && output != NULL && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
// CASE 5
|
// CASE 5
|
||||||
wpStr8Format(&tmp, "home%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP);
|
wpStr8Format(&tmp, "home%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP);
|
||||||
wpStr8CopyCstrCapped(&expected, "home");
|
wpStr8CopyCstrCapped(&expected, "home");
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 2);
|
output = wpCpathDirUp(&arena, &tmp, 2);
|
||||||
result = result && output != NULL && wpStr8Equal(output, &expected);
|
result = result && output != NULL && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
wpMemArenaAllocatorDestroy(&arena);
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|||||||
@@ -164,35 +164,35 @@ WpTestFuncResult test_cpath_dirup(void) {
|
|||||||
wpStr8Format(&tmp, "%c", WP_PATH_SEP);
|
wpStr8Format(&tmp, "%c", WP_PATH_SEP);
|
||||||
wpStr8Format(&expected, "%c", WP_PATH_SEP);
|
wpStr8Format(&expected, "%c", WP_PATH_SEP);
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 3);
|
output = wpCpathDirUp(&arena, &tmp, 3);
|
||||||
result = output != nullptr && wpStr8Equal(output, &expected);
|
result = output != nullptr && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
// CASE 2
|
// CASE 2
|
||||||
wpStr8Format(&tmp, "%chome%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP, WP_PATH_SEP);
|
wpStr8Format(&tmp, "%chome%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP, WP_PATH_SEP);
|
||||||
wpStr8Format(&expected, "%c", WP_PATH_SEP);
|
wpStr8Format(&expected, "%c", WP_PATH_SEP);
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 3);
|
output = wpCpathDirUp(&arena, &tmp, 3);
|
||||||
result = result && output != nullptr && wpStr8Equal(output, &expected);
|
result = result && output != nullptr && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
// CASE 3
|
// CASE 3
|
||||||
wpStr8Format(&tmp, "home%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP);
|
wpStr8Format(&tmp, "home%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP);
|
||||||
wpStr8CopyCstrCapped(&expected, ".");
|
wpStr8CopyCstrCapped(&expected, ".");
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 3);
|
output = wpCpathDirUp(&arena, &tmp, 3);
|
||||||
result = result && output != nullptr && wpStr8Equal(output, &expected);
|
result = result && output != nullptr && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
// CASE 4
|
// CASE 4
|
||||||
wpStr8Format(&tmp, "%chome%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP, WP_PATH_SEP);
|
wpStr8Format(&tmp, "%chome%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP, WP_PATH_SEP);
|
||||||
wpStr8Format(&expected, "%chome", WP_PATH_SEP);
|
wpStr8Format(&expected, "%chome", WP_PATH_SEP);
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 2);
|
output = wpCpathDirUp(&arena, &tmp, 2);
|
||||||
result = result && output != nullptr && wpStr8Equal(output, &expected);
|
result = result && output != nullptr && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
// CASE 5
|
// CASE 5
|
||||||
wpStr8Format(&tmp, "home%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP);
|
wpStr8Format(&tmp, "home%cabdelrahman%cDocuments", WP_PATH_SEP, WP_PATH_SEP);
|
||||||
wpStr8CopyCstrCapped(&expected, "home");
|
wpStr8CopyCstrCapped(&expected, "home");
|
||||||
|
|
||||||
output = wpCpathDirup(&arena, &tmp, 2);
|
output = wpCpathDirUp(&arena, &tmp, 2);
|
||||||
result = result && output != nullptr && wpStr8Equal(output, &expected);
|
result = result && output != nullptr && wpStr8Equal(output, &expected);
|
||||||
|
|
||||||
wpMemArenaAllocatorDestroy(&arena);
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|||||||
@@ -0,0 +1,335 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||||
|
// domain. The author hereby disclaims copyright to this source code.
|
||||||
|
|
||||||
|
// Note - The x86 and x64 versions do _not_ produce the same results, as the
|
||||||
|
// algorithms are optimized for their respective platforms. You can still
|
||||||
|
// compile and run any of them on any platform, but your performance with the
|
||||||
|
// non-native version will be less than optimal.
|
||||||
|
|
||||||
|
#include "MurmurHash3.h"
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Platform-specific functions and macros
|
||||||
|
|
||||||
|
// Microsoft Visual Studio
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
|
#define FORCE_INLINE __forceinline
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define ROTL32(x,y) _rotl(x,y)
|
||||||
|
#define ROTL64(x,y) _rotl64(x,y)
|
||||||
|
|
||||||
|
#define BIG_CONSTANT(x) (x)
|
||||||
|
|
||||||
|
// Other compilers
|
||||||
|
|
||||||
|
#else // defined(_MSC_VER)
|
||||||
|
|
||||||
|
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||||
|
|
||||||
|
static inline uint32_t rotl32 ( uint32_t x, int8_t r )
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (32 - r));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t rotl64 ( uint64_t x, int8_t r )
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (64 - r));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ROTL32(x,y) rotl32(x,y)
|
||||||
|
#define ROTL64(x,y) rotl64(x,y)
|
||||||
|
|
||||||
|
#define BIG_CONSTANT(x) (x##LLU)
|
||||||
|
|
||||||
|
#endif // !defined(_MSC_VER)
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Block read - if your platform needs to do endian-swapping or can only
|
||||||
|
// handle aligned reads, do the conversion here
|
||||||
|
|
||||||
|
FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i )
|
||||||
|
{
|
||||||
|
return p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, int i )
|
||||||
|
{
|
||||||
|
return p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Finalization mix - force all bits of a hash block to avalanche
|
||||||
|
|
||||||
|
FORCE_INLINE uint32_t fmix32 ( uint32_t h )
|
||||||
|
{
|
||||||
|
h ^= h >> 16;
|
||||||
|
h *= 0x85ebca6b;
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= 0xc2b2ae35;
|
||||||
|
h ^= h >> 16;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
|
||||||
|
FORCE_INLINE uint64_t fmix64 ( uint64_t k )
|
||||||
|
{
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
|
||||||
|
k ^= k >> 33;
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void MurmurHash3_x86_32 ( const void * key, int len,
|
||||||
|
uint32_t seed, void * out )
|
||||||
|
{
|
||||||
|
const uint8_t * data = (const uint8_t*)key;
|
||||||
|
const int nblocks = len / 4;
|
||||||
|
|
||||||
|
uint32_t h1 = seed;
|
||||||
|
|
||||||
|
const uint32_t c1 = 0xcc9e2d51;
|
||||||
|
const uint32_t c2 = 0x1b873593;
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// body
|
||||||
|
|
||||||
|
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
|
||||||
|
|
||||||
|
for(int i = -nblocks; i; i++)
|
||||||
|
{
|
||||||
|
uint32_t k1 = getblock32(blocks,i);
|
||||||
|
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = ROTL32(k1,15);
|
||||||
|
k1 *= c2;
|
||||||
|
|
||||||
|
h1 ^= k1;
|
||||||
|
h1 = ROTL32(h1,13);
|
||||||
|
h1 = h1*5+0xe6546b64;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// tail
|
||||||
|
|
||||||
|
const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
|
||||||
|
|
||||||
|
uint32_t k1 = 0;
|
||||||
|
|
||||||
|
switch(len & 3)
|
||||||
|
{
|
||||||
|
case 3: k1 ^= tail[2] << 16;
|
||||||
|
case 2: k1 ^= tail[1] << 8;
|
||||||
|
case 1: k1 ^= tail[0];
|
||||||
|
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// finalization
|
||||||
|
|
||||||
|
h1 ^= len;
|
||||||
|
|
||||||
|
h1 = fmix32(h1);
|
||||||
|
|
||||||
|
*(uint32_t*)out = h1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void MurmurHash3_x86_128 ( const void * key, const int len,
|
||||||
|
uint32_t seed, void * out )
|
||||||
|
{
|
||||||
|
const uint8_t * data = (const uint8_t*)key;
|
||||||
|
const int nblocks = len / 16;
|
||||||
|
|
||||||
|
uint32_t h1 = seed;
|
||||||
|
uint32_t h2 = seed;
|
||||||
|
uint32_t h3 = seed;
|
||||||
|
uint32_t h4 = seed;
|
||||||
|
|
||||||
|
const uint32_t c1 = 0x239b961b;
|
||||||
|
const uint32_t c2 = 0xab0e9789;
|
||||||
|
const uint32_t c3 = 0x38b34ae5;
|
||||||
|
const uint32_t c4 = 0xa1e38b93;
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// body
|
||||||
|
|
||||||
|
const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
|
||||||
|
|
||||||
|
for(int i = -nblocks; i; i++)
|
||||||
|
{
|
||||||
|
uint32_t k1 = getblock32(blocks,i*4+0);
|
||||||
|
uint32_t k2 = getblock32(blocks,i*4+1);
|
||||||
|
uint32_t k3 = getblock32(blocks,i*4+2);
|
||||||
|
uint32_t k4 = getblock32(blocks,i*4+3);
|
||||||
|
|
||||||
|
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||||
|
|
||||||
|
h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
|
||||||
|
|
||||||
|
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
|
||||||
|
|
||||||
|
h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
|
||||||
|
|
||||||
|
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
|
||||||
|
|
||||||
|
h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
|
||||||
|
|
||||||
|
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
|
||||||
|
|
||||||
|
h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// tail
|
||||||
|
|
||||||
|
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
|
||||||
|
|
||||||
|
uint32_t k1 = 0;
|
||||||
|
uint32_t k2 = 0;
|
||||||
|
uint32_t k3 = 0;
|
||||||
|
uint32_t k4 = 0;
|
||||||
|
|
||||||
|
switch(len & 15)
|
||||||
|
{
|
||||||
|
case 15: k4 ^= tail[14] << 16;
|
||||||
|
case 14: k4 ^= tail[13] << 8;
|
||||||
|
case 13: k4 ^= tail[12] << 0;
|
||||||
|
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
|
||||||
|
|
||||||
|
case 12: k3 ^= tail[11] << 24;
|
||||||
|
case 11: k3 ^= tail[10] << 16;
|
||||||
|
case 10: k3 ^= tail[ 9] << 8;
|
||||||
|
case 9: k3 ^= tail[ 8] << 0;
|
||||||
|
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
|
||||||
|
|
||||||
|
case 8: k2 ^= tail[ 7] << 24;
|
||||||
|
case 7: k2 ^= tail[ 6] << 16;
|
||||||
|
case 6: k2 ^= tail[ 5] << 8;
|
||||||
|
case 5: k2 ^= tail[ 4] << 0;
|
||||||
|
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
|
||||||
|
|
||||||
|
case 4: k1 ^= tail[ 3] << 24;
|
||||||
|
case 3: k1 ^= tail[ 2] << 16;
|
||||||
|
case 2: k1 ^= tail[ 1] << 8;
|
||||||
|
case 1: k1 ^= tail[ 0] << 0;
|
||||||
|
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// finalization
|
||||||
|
|
||||||
|
h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
|
||||||
|
|
||||||
|
h1 += h2; h1 += h3; h1 += h4;
|
||||||
|
h2 += h1; h3 += h1; h4 += h1;
|
||||||
|
|
||||||
|
h1 = fmix32(h1);
|
||||||
|
h2 = fmix32(h2);
|
||||||
|
h3 = fmix32(h3);
|
||||||
|
h4 = fmix32(h4);
|
||||||
|
|
||||||
|
h1 += h2; h1 += h3; h1 += h4;
|
||||||
|
h2 += h1; h3 += h1; h4 += h1;
|
||||||
|
|
||||||
|
((uint32_t*)out)[0] = h1;
|
||||||
|
((uint32_t*)out)[1] = h2;
|
||||||
|
((uint32_t*)out)[2] = h3;
|
||||||
|
((uint32_t*)out)[3] = h4;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void MurmurHash3_x64_128 ( const void * key, const int len,
|
||||||
|
const uint32_t seed, void * out )
|
||||||
|
{
|
||||||
|
const uint8_t * data = (const uint8_t*)key;
|
||||||
|
const int nblocks = len / 16;
|
||||||
|
|
||||||
|
uint64_t h1 = seed;
|
||||||
|
uint64_t h2 = seed;
|
||||||
|
|
||||||
|
const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
|
||||||
|
const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// body
|
||||||
|
|
||||||
|
const uint64_t * blocks = (const uint64_t *)(data);
|
||||||
|
|
||||||
|
for(int i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
uint64_t k1 = getblock64(blocks,i*2+0);
|
||||||
|
uint64_t k2 = getblock64(blocks,i*2+1);
|
||||||
|
|
||||||
|
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||||
|
|
||||||
|
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
|
||||||
|
|
||||||
|
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||||
|
|
||||||
|
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// tail
|
||||||
|
|
||||||
|
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
|
||||||
|
|
||||||
|
uint64_t k1 = 0;
|
||||||
|
uint64_t k2 = 0;
|
||||||
|
|
||||||
|
switch(len & 15)
|
||||||
|
{
|
||||||
|
case 15: k2 ^= ((uint64_t)tail[14]) << 48;
|
||||||
|
case 14: k2 ^= ((uint64_t)tail[13]) << 40;
|
||||||
|
case 13: k2 ^= ((uint64_t)tail[12]) << 32;
|
||||||
|
case 12: k2 ^= ((uint64_t)tail[11]) << 24;
|
||||||
|
case 11: k2 ^= ((uint64_t)tail[10]) << 16;
|
||||||
|
case 10: k2 ^= ((uint64_t)tail[ 9]) << 8;
|
||||||
|
case 9: k2 ^= ((uint64_t)tail[ 8]) << 0;
|
||||||
|
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||||
|
|
||||||
|
case 8: k1 ^= ((uint64_t)tail[ 7]) << 56;
|
||||||
|
case 7: k1 ^= ((uint64_t)tail[ 6]) << 48;
|
||||||
|
case 6: k1 ^= ((uint64_t)tail[ 5]) << 40;
|
||||||
|
case 5: k1 ^= ((uint64_t)tail[ 4]) << 32;
|
||||||
|
case 4: k1 ^= ((uint64_t)tail[ 3]) << 24;
|
||||||
|
case 3: k1 ^= ((uint64_t)tail[ 2]) << 16;
|
||||||
|
case 2: k1 ^= ((uint64_t)tail[ 1]) << 8;
|
||||||
|
case 1: k1 ^= ((uint64_t)tail[ 0]) << 0;
|
||||||
|
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// finalization
|
||||||
|
|
||||||
|
h1 ^= len; h2 ^= len;
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
h1 = fmix64(h1);
|
||||||
|
h2 = fmix64(h2);
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
((uint64_t*)out)[0] = h1;
|
||||||
|
((uint64_t*)out)[1] = h2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -0,0 +1,335 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||||
|
// domain. The author hereby disclaims copyright to this source code.
|
||||||
|
|
||||||
|
// Note - The x86 and x64 versions do _not_ produce the same results, as the
|
||||||
|
// algorithms are optimized for their respective platforms. You can still
|
||||||
|
// compile and run any of them on any platform, but your performance with the
|
||||||
|
// non-native version will be less than optimal.
|
||||||
|
|
||||||
|
#include "MurmurHash3.h"
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Platform-specific functions and macros
|
||||||
|
|
||||||
|
// Microsoft Visual Studio
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
|
#define FORCE_INLINE __forceinline
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define ROTL32(x,y) _rotl(x,y)
|
||||||
|
#define ROTL64(x,y) _rotl64(x,y)
|
||||||
|
|
||||||
|
#define BIG_CONSTANT(x) (x)
|
||||||
|
|
||||||
|
// Other compilers
|
||||||
|
|
||||||
|
#else // defined(_MSC_VER)
|
||||||
|
|
||||||
|
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||||
|
|
||||||
|
inline uint32_t rotl32 ( uint32_t x, int8_t r )
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (32 - r));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t rotl64 ( uint64_t x, int8_t r )
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (64 - r));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ROTL32(x,y) rotl32(x,y)
|
||||||
|
#define ROTL64(x,y) rotl64(x,y)
|
||||||
|
|
||||||
|
#define BIG_CONSTANT(x) (x##LLU)
|
||||||
|
|
||||||
|
#endif // !defined(_MSC_VER)
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Block read - if your platform needs to do endian-swapping or can only
|
||||||
|
// handle aligned reads, do the conversion here
|
||||||
|
|
||||||
|
FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i )
|
||||||
|
{
|
||||||
|
return p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, int i )
|
||||||
|
{
|
||||||
|
return p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Finalization mix - force all bits of a hash block to avalanche
|
||||||
|
|
||||||
|
FORCE_INLINE uint32_t fmix32 ( uint32_t h )
|
||||||
|
{
|
||||||
|
h ^= h >> 16;
|
||||||
|
h *= 0x85ebca6b;
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= 0xc2b2ae35;
|
||||||
|
h ^= h >> 16;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
|
||||||
|
FORCE_INLINE uint64_t fmix64 ( uint64_t k )
|
||||||
|
{
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
|
||||||
|
k ^= k >> 33;
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void MurmurHash3_x86_32 ( const void * key, int len,
|
||||||
|
uint32_t seed, void * out )
|
||||||
|
{
|
||||||
|
const uint8_t * data = (const uint8_t*)key;
|
||||||
|
const int nblocks = len / 4;
|
||||||
|
|
||||||
|
uint32_t h1 = seed;
|
||||||
|
|
||||||
|
const uint32_t c1 = 0xcc9e2d51;
|
||||||
|
const uint32_t c2 = 0x1b873593;
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// body
|
||||||
|
|
||||||
|
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
|
||||||
|
|
||||||
|
for(int i = -nblocks; i; i++)
|
||||||
|
{
|
||||||
|
uint32_t k1 = getblock32(blocks,i);
|
||||||
|
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = ROTL32(k1,15);
|
||||||
|
k1 *= c2;
|
||||||
|
|
||||||
|
h1 ^= k1;
|
||||||
|
h1 = ROTL32(h1,13);
|
||||||
|
h1 = h1*5+0xe6546b64;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// tail
|
||||||
|
|
||||||
|
const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
|
||||||
|
|
||||||
|
uint32_t k1 = 0;
|
||||||
|
|
||||||
|
switch(len & 3)
|
||||||
|
{
|
||||||
|
case 3: k1 ^= tail[2] << 16;
|
||||||
|
case 2: k1 ^= tail[1] << 8;
|
||||||
|
case 1: k1 ^= tail[0];
|
||||||
|
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// finalization
|
||||||
|
|
||||||
|
h1 ^= len;
|
||||||
|
|
||||||
|
h1 = fmix32(h1);
|
||||||
|
|
||||||
|
*(uint32_t*)out = h1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void MurmurHash3_x86_128 ( const void * key, const int len,
|
||||||
|
uint32_t seed, void * out )
|
||||||
|
{
|
||||||
|
const uint8_t * data = (const uint8_t*)key;
|
||||||
|
const int nblocks = len / 16;
|
||||||
|
|
||||||
|
uint32_t h1 = seed;
|
||||||
|
uint32_t h2 = seed;
|
||||||
|
uint32_t h3 = seed;
|
||||||
|
uint32_t h4 = seed;
|
||||||
|
|
||||||
|
const uint32_t c1 = 0x239b961b;
|
||||||
|
const uint32_t c2 = 0xab0e9789;
|
||||||
|
const uint32_t c3 = 0x38b34ae5;
|
||||||
|
const uint32_t c4 = 0xa1e38b93;
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// body
|
||||||
|
|
||||||
|
const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
|
||||||
|
|
||||||
|
for(int i = -nblocks; i; i++)
|
||||||
|
{
|
||||||
|
uint32_t k1 = getblock32(blocks,i*4+0);
|
||||||
|
uint32_t k2 = getblock32(blocks,i*4+1);
|
||||||
|
uint32_t k3 = getblock32(blocks,i*4+2);
|
||||||
|
uint32_t k4 = getblock32(blocks,i*4+3);
|
||||||
|
|
||||||
|
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||||
|
|
||||||
|
h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
|
||||||
|
|
||||||
|
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
|
||||||
|
|
||||||
|
h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
|
||||||
|
|
||||||
|
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
|
||||||
|
|
||||||
|
h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
|
||||||
|
|
||||||
|
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
|
||||||
|
|
||||||
|
h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// tail
|
||||||
|
|
||||||
|
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
|
||||||
|
|
||||||
|
uint32_t k1 = 0;
|
||||||
|
uint32_t k2 = 0;
|
||||||
|
uint32_t k3 = 0;
|
||||||
|
uint32_t k4 = 0;
|
||||||
|
|
||||||
|
switch(len & 15)
|
||||||
|
{
|
||||||
|
case 15: k4 ^= tail[14] << 16;
|
||||||
|
case 14: k4 ^= tail[13] << 8;
|
||||||
|
case 13: k4 ^= tail[12] << 0;
|
||||||
|
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
|
||||||
|
|
||||||
|
case 12: k3 ^= tail[11] << 24;
|
||||||
|
case 11: k3 ^= tail[10] << 16;
|
||||||
|
case 10: k3 ^= tail[ 9] << 8;
|
||||||
|
case 9: k3 ^= tail[ 8] << 0;
|
||||||
|
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
|
||||||
|
|
||||||
|
case 8: k2 ^= tail[ 7] << 24;
|
||||||
|
case 7: k2 ^= tail[ 6] << 16;
|
||||||
|
case 6: k2 ^= tail[ 5] << 8;
|
||||||
|
case 5: k2 ^= tail[ 4] << 0;
|
||||||
|
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
|
||||||
|
|
||||||
|
case 4: k1 ^= tail[ 3] << 24;
|
||||||
|
case 3: k1 ^= tail[ 2] << 16;
|
||||||
|
case 2: k1 ^= tail[ 1] << 8;
|
||||||
|
case 1: k1 ^= tail[ 0] << 0;
|
||||||
|
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// finalization
|
||||||
|
|
||||||
|
h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
|
||||||
|
|
||||||
|
h1 += h2; h1 += h3; h1 += h4;
|
||||||
|
h2 += h1; h3 += h1; h4 += h1;
|
||||||
|
|
||||||
|
h1 = fmix32(h1);
|
||||||
|
h2 = fmix32(h2);
|
||||||
|
h3 = fmix32(h3);
|
||||||
|
h4 = fmix32(h4);
|
||||||
|
|
||||||
|
h1 += h2; h1 += h3; h1 += h4;
|
||||||
|
h2 += h1; h3 += h1; h4 += h1;
|
||||||
|
|
||||||
|
((uint32_t*)out)[0] = h1;
|
||||||
|
((uint32_t*)out)[1] = h2;
|
||||||
|
((uint32_t*)out)[2] = h3;
|
||||||
|
((uint32_t*)out)[3] = h4;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void MurmurHash3_x64_128 ( const void * key, const int len,
|
||||||
|
const uint32_t seed, void * out )
|
||||||
|
{
|
||||||
|
const uint8_t * data = (const uint8_t*)key;
|
||||||
|
const int nblocks = len / 16;
|
||||||
|
|
||||||
|
uint64_t h1 = seed;
|
||||||
|
uint64_t h2 = seed;
|
||||||
|
|
||||||
|
const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
|
||||||
|
const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// body
|
||||||
|
|
||||||
|
const uint64_t * blocks = (const uint64_t *)(data);
|
||||||
|
|
||||||
|
for(int i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
uint64_t k1 = getblock64(blocks,i*2+0);
|
||||||
|
uint64_t k2 = getblock64(blocks,i*2+1);
|
||||||
|
|
||||||
|
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||||
|
|
||||||
|
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
|
||||||
|
|
||||||
|
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||||
|
|
||||||
|
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// tail
|
||||||
|
|
||||||
|
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
|
||||||
|
|
||||||
|
uint64_t k1 = 0;
|
||||||
|
uint64_t k2 = 0;
|
||||||
|
|
||||||
|
switch(len & 15)
|
||||||
|
{
|
||||||
|
case 15: k2 ^= ((uint64_t)tail[14]) << 48;
|
||||||
|
case 14: k2 ^= ((uint64_t)tail[13]) << 40;
|
||||||
|
case 13: k2 ^= ((uint64_t)tail[12]) << 32;
|
||||||
|
case 12: k2 ^= ((uint64_t)tail[11]) << 24;
|
||||||
|
case 11: k2 ^= ((uint64_t)tail[10]) << 16;
|
||||||
|
case 10: k2 ^= ((uint64_t)tail[ 9]) << 8;
|
||||||
|
case 9: k2 ^= ((uint64_t)tail[ 8]) << 0;
|
||||||
|
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||||
|
|
||||||
|
case 8: k1 ^= ((uint64_t)tail[ 7]) << 56;
|
||||||
|
case 7: k1 ^= ((uint64_t)tail[ 6]) << 48;
|
||||||
|
case 6: k1 ^= ((uint64_t)tail[ 5]) << 40;
|
||||||
|
case 5: k1 ^= ((uint64_t)tail[ 4]) << 32;
|
||||||
|
case 4: k1 ^= ((uint64_t)tail[ 3]) << 24;
|
||||||
|
case 3: k1 ^= ((uint64_t)tail[ 2]) << 16;
|
||||||
|
case 2: k1 ^= ((uint64_t)tail[ 1]) << 8;
|
||||||
|
case 1: k1 ^= ((uint64_t)tail[ 0]) << 0;
|
||||||
|
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// finalization
|
||||||
|
|
||||||
|
h1 ^= len; h2 ^= len;
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
h1 = fmix64(h1);
|
||||||
|
h2 = fmix64(h2);
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
((uint64_t*)out)[0] = h1;
|
||||||
|
((uint64_t*)out)[1] = h2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||||
|
// domain. The author hereby disclaims copyright to this source code.
|
||||||
|
|
||||||
|
#ifndef _MURMURHASH3_H_
|
||||||
|
#define _MURMURHASH3_H_
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Platform-specific functions and macros
|
||||||
|
|
||||||
|
// Microsoft Visual Studio
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||||
|
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
|
||||||
|
// Other compilers
|
||||||
|
|
||||||
|
#else // defined(_MSC_VER)
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#endif // !defined(_MSC_VER)
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out );
|
||||||
|
|
||||||
|
void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out );
|
||||||
|
|
||||||
|
void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out );
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif // _MURMURHASH3_H_
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
SipHash reference C implementation
|
||||||
|
|
||||||
|
Copyright (c) 2012-2022 Jean-Philippe Aumasson
|
||||||
|
<jeanphilippe.aumasson@gmail.com>
|
||||||
|
Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
|
||||||
|
|
||||||
|
To the extent possible under law, the author(s) have dedicated all copyright
|
||||||
|
and related and neighboring rights to this software to the public domain
|
||||||
|
worldwide. This software is distributed without any warranty.
|
||||||
|
|
||||||
|
You should have received a copy of the CC0 Public Domain Dedication along
|
||||||
|
with
|
||||||
|
this software. If not, see
|
||||||
|
<http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "siphash.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* default: SipHash-2-4 */
|
||||||
|
#ifndef cROUNDS
|
||||||
|
#define cROUNDS 2
|
||||||
|
#endif
|
||||||
|
#ifndef dROUNDS
|
||||||
|
#define dROUNDS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
|
||||||
|
|
||||||
|
#define U32TO8_LE(p, v) \
|
||||||
|
(p)[0] = (uint8_t)((v)); \
|
||||||
|
(p)[1] = (uint8_t)((v) >> 8); \
|
||||||
|
(p)[2] = (uint8_t)((v) >> 16); \
|
||||||
|
(p)[3] = (uint8_t)((v) >> 24);
|
||||||
|
|
||||||
|
#define U64TO8_LE(p, v) \
|
||||||
|
U32TO8_LE((p), (uint32_t)((v))); \
|
||||||
|
U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
|
||||||
|
|
||||||
|
#define U8TO64_LE(p) \
|
||||||
|
(((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
|
||||||
|
((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
|
||||||
|
((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
|
||||||
|
((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
|
||||||
|
|
||||||
|
#define SIPROUND \
|
||||||
|
do { \
|
||||||
|
v0 += v1; \
|
||||||
|
v1 = ROTL(v1, 13); \
|
||||||
|
v1 ^= v0; \
|
||||||
|
v0 = ROTL(v0, 32); \
|
||||||
|
v2 += v3; \
|
||||||
|
v3 = ROTL(v3, 16); \
|
||||||
|
v3 ^= v2; \
|
||||||
|
v0 += v3; \
|
||||||
|
v3 = ROTL(v3, 21); \
|
||||||
|
v3 ^= v0; \
|
||||||
|
v2 += v1; \
|
||||||
|
v1 = ROTL(v1, 17); \
|
||||||
|
v1 ^= v2; \
|
||||||
|
v2 = ROTL(v2, 32); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef DEBUG_SIPHASH
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define TRACE \
|
||||||
|
do { \
|
||||||
|
printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0); \
|
||||||
|
printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1); \
|
||||||
|
printf("(%3zu) v2 %016" PRIx64 "\n", inlen, v2); \
|
||||||
|
printf("(%3zu) v3 %016" PRIx64 "\n", inlen, v3); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define TRACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Computes a SipHash value
|
||||||
|
*in: pointer to input data (read-only)
|
||||||
|
inlen: input data length in bytes (any size_t value)
|
||||||
|
*k: pointer to the key data (read-only), must be 16 bytes
|
||||||
|
*out: pointer to output data (write-only), outlen bytes must be allocated
|
||||||
|
outlen: length of the output in bytes, must be 8 or 16
|
||||||
|
*/
|
||||||
|
int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out,
|
||||||
|
const size_t outlen) {
|
||||||
|
|
||||||
|
const unsigned char *ni = (const unsigned char *)in;
|
||||||
|
const unsigned char *kk = (const unsigned char *)k;
|
||||||
|
|
||||||
|
assert((outlen == 8) || (outlen == 16));
|
||||||
|
uint64_t v0 = UINT64_C(0x736f6d6570736575);
|
||||||
|
uint64_t v1 = UINT64_C(0x646f72616e646f6d);
|
||||||
|
uint64_t v2 = UINT64_C(0x6c7967656e657261);
|
||||||
|
uint64_t v3 = UINT64_C(0x7465646279746573);
|
||||||
|
uint64_t k0 = U8TO64_LE(kk);
|
||||||
|
uint64_t k1 = U8TO64_LE(kk + 8);
|
||||||
|
uint64_t m;
|
||||||
|
int i;
|
||||||
|
const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t));
|
||||||
|
const int left = inlen & 7;
|
||||||
|
uint64_t b = ((uint64_t)inlen) << 56;
|
||||||
|
v3 ^= k1;
|
||||||
|
v2 ^= k0;
|
||||||
|
v1 ^= k1;
|
||||||
|
v0 ^= k0;
|
||||||
|
|
||||||
|
if (outlen == 16)
|
||||||
|
v1 ^= 0xee;
|
||||||
|
|
||||||
|
for (; ni != end; ni += 8) {
|
||||||
|
m = U8TO64_LE(ni);
|
||||||
|
v3 ^= m;
|
||||||
|
|
||||||
|
TRACE;
|
||||||
|
for (i = 0; i < cROUNDS; ++i)
|
||||||
|
SIPROUND;
|
||||||
|
|
||||||
|
v0 ^= m;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (left) {
|
||||||
|
case 7:
|
||||||
|
b |= ((uint64_t)ni[6]) << 48;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 6:
|
||||||
|
b |= ((uint64_t)ni[5]) << 40;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 5:
|
||||||
|
b |= ((uint64_t)ni[4]) << 32;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 4:
|
||||||
|
b |= ((uint64_t)ni[3]) << 24;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 3:
|
||||||
|
b |= ((uint64_t)ni[2]) << 16;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 2:
|
||||||
|
b |= ((uint64_t)ni[1]) << 8;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 1:
|
||||||
|
b |= ((uint64_t)ni[0]);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
v3 ^= b;
|
||||||
|
|
||||||
|
TRACE;
|
||||||
|
for (i = 0; i < cROUNDS; ++i)
|
||||||
|
SIPROUND;
|
||||||
|
|
||||||
|
v0 ^= b;
|
||||||
|
|
||||||
|
if (outlen == 16)
|
||||||
|
v2 ^= 0xee;
|
||||||
|
else
|
||||||
|
v2 ^= 0xff;
|
||||||
|
|
||||||
|
TRACE;
|
||||||
|
for (i = 0; i < dROUNDS; ++i)
|
||||||
|
SIPROUND;
|
||||||
|
|
||||||
|
b = v0 ^ v1 ^ v2 ^ v3;
|
||||||
|
U64TO8_LE(out, b);
|
||||||
|
|
||||||
|
if (outlen == 8)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
v1 ^= 0xdd;
|
||||||
|
|
||||||
|
TRACE;
|
||||||
|
for (i = 0; i < dROUNDS; ++i)
|
||||||
|
SIPROUND;
|
||||||
|
|
||||||
|
b = v0 ^ v1 ^ v2 ^ v3;
|
||||||
|
U64TO8_LE(out + 8, b);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
SipHash reference C implementation
|
||||||
|
|
||||||
|
Copyright (c) 2012-2022 Jean-Philippe Aumasson
|
||||||
|
<jeanphilippe.aumasson@gmail.com>
|
||||||
|
Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
|
||||||
|
|
||||||
|
To the extent possible under law, the author(s) have dedicated all copyright
|
||||||
|
and related and neighboring rights to this software to the public domain
|
||||||
|
worldwide. This software is distributed without any warranty.
|
||||||
|
|
||||||
|
You should have received a copy of the CC0 Public Domain Dedication along
|
||||||
|
with
|
||||||
|
this software. If not, see
|
||||||
|
<http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "siphash.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* default: SipHash-2-4 */
|
||||||
|
#ifndef cROUNDS
|
||||||
|
#define cROUNDS 2
|
||||||
|
#endif
|
||||||
|
#ifndef dROUNDS
|
||||||
|
#define dROUNDS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
|
||||||
|
|
||||||
|
#define U32TO8_LE(p, v) \
|
||||||
|
(p)[0] = (uint8_t)((v)); \
|
||||||
|
(p)[1] = (uint8_t)((v) >> 8); \
|
||||||
|
(p)[2] = (uint8_t)((v) >> 16); \
|
||||||
|
(p)[3] = (uint8_t)((v) >> 24);
|
||||||
|
|
||||||
|
#define U64TO8_LE(p, v) \
|
||||||
|
U32TO8_LE((p), (uint32_t)((v))); \
|
||||||
|
U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
|
||||||
|
|
||||||
|
#define U8TO64_LE(p) \
|
||||||
|
(((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
|
||||||
|
((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
|
||||||
|
((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
|
||||||
|
((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
|
||||||
|
|
||||||
|
#define SIPROUND \
|
||||||
|
do { \
|
||||||
|
v0 += v1; \
|
||||||
|
v1 = ROTL(v1, 13); \
|
||||||
|
v1 ^= v0; \
|
||||||
|
v0 = ROTL(v0, 32); \
|
||||||
|
v2 += v3; \
|
||||||
|
v3 = ROTL(v3, 16); \
|
||||||
|
v3 ^= v2; \
|
||||||
|
v0 += v3; \
|
||||||
|
v3 = ROTL(v3, 21); \
|
||||||
|
v3 ^= v0; \
|
||||||
|
v2 += v1; \
|
||||||
|
v1 = ROTL(v1, 17); \
|
||||||
|
v1 ^= v2; \
|
||||||
|
v2 = ROTL(v2, 32); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef DEBUG_SIPHASH
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define TRACE \
|
||||||
|
do { \
|
||||||
|
printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0); \
|
||||||
|
printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1); \
|
||||||
|
printf("(%3zu) v2 %016" PRIx64 "\n", inlen, v2); \
|
||||||
|
printf("(%3zu) v3 %016" PRIx64 "\n", inlen, v3); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define TRACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Computes a SipHash value
|
||||||
|
*in: pointer to input data (read-only)
|
||||||
|
inlen: input data length in bytes (any size_t value)
|
||||||
|
*k: pointer to the key data (read-only), must be 16 bytes
|
||||||
|
*out: pointer to output data (write-only), outlen bytes must be allocated
|
||||||
|
outlen: length of the output in bytes, must be 8 or 16
|
||||||
|
*/
|
||||||
|
int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out,
|
||||||
|
const size_t outlen) {
|
||||||
|
|
||||||
|
const unsigned char *ni = (const unsigned char *)in;
|
||||||
|
const unsigned char *kk = (const unsigned char *)k;
|
||||||
|
|
||||||
|
assert((outlen == 8) || (outlen == 16));
|
||||||
|
uint64_t v0 = UINT64_C(0x736f6d6570736575);
|
||||||
|
uint64_t v1 = UINT64_C(0x646f72616e646f6d);
|
||||||
|
uint64_t v2 = UINT64_C(0x6c7967656e657261);
|
||||||
|
uint64_t v3 = UINT64_C(0x7465646279746573);
|
||||||
|
uint64_t k0 = U8TO64_LE(kk);
|
||||||
|
uint64_t k1 = U8TO64_LE(kk + 8);
|
||||||
|
uint64_t m;
|
||||||
|
int i;
|
||||||
|
const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t));
|
||||||
|
const int left = inlen & 7;
|
||||||
|
uint64_t b = ((uint64_t)inlen) << 56;
|
||||||
|
v3 ^= k1;
|
||||||
|
v2 ^= k0;
|
||||||
|
v1 ^= k1;
|
||||||
|
v0 ^= k0;
|
||||||
|
|
||||||
|
if (outlen == 16)
|
||||||
|
v1 ^= 0xee;
|
||||||
|
|
||||||
|
for (; ni != end; ni += 8) {
|
||||||
|
m = U8TO64_LE(ni);
|
||||||
|
v3 ^= m;
|
||||||
|
|
||||||
|
TRACE;
|
||||||
|
for (i = 0; i < cROUNDS; ++i)
|
||||||
|
SIPROUND;
|
||||||
|
|
||||||
|
v0 ^= m;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (left) {
|
||||||
|
case 7:
|
||||||
|
b |= ((uint64_t)ni[6]) << 48;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 6:
|
||||||
|
b |= ((uint64_t)ni[5]) << 40;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 5:
|
||||||
|
b |= ((uint64_t)ni[4]) << 32;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 4:
|
||||||
|
b |= ((uint64_t)ni[3]) << 24;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 3:
|
||||||
|
b |= ((uint64_t)ni[2]) << 16;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 2:
|
||||||
|
b |= ((uint64_t)ni[1]) << 8;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 1:
|
||||||
|
b |= ((uint64_t)ni[0]);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
v3 ^= b;
|
||||||
|
|
||||||
|
TRACE;
|
||||||
|
for (i = 0; i < cROUNDS; ++i)
|
||||||
|
SIPROUND;
|
||||||
|
|
||||||
|
v0 ^= b;
|
||||||
|
|
||||||
|
if (outlen == 16)
|
||||||
|
v2 ^= 0xee;
|
||||||
|
else
|
||||||
|
v2 ^= 0xff;
|
||||||
|
|
||||||
|
TRACE;
|
||||||
|
for (i = 0; i < dROUNDS; ++i)
|
||||||
|
SIPROUND;
|
||||||
|
|
||||||
|
b = v0 ^ v1 ^ v2 ^ v3;
|
||||||
|
U64TO8_LE(out, b);
|
||||||
|
|
||||||
|
if (outlen == 8)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
v1 ^= 0xdd;
|
||||||
|
|
||||||
|
TRACE;
|
||||||
|
for (i = 0; i < dROUNDS; ++i)
|
||||||
|
SIPROUND;
|
||||||
|
|
||||||
|
b = v0 ^ v1 ^ v2 ^ v3;
|
||||||
|
U64TO8_LE(out + 8, b);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
SipHash reference C implementation
|
||||||
|
|
||||||
|
Copyright (c) 2012-2021 Jean-Philippe Aumasson
|
||||||
|
<jeanphilippe.aumasson@gmail.com>
|
||||||
|
Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
|
||||||
|
|
||||||
|
To the extent possible under law, the author(s) have dedicated all copyright
|
||||||
|
and related and neighboring rights to this software to the public domain
|
||||||
|
worldwide. This software is distributed without any warranty.
|
||||||
|
|
||||||
|
You should have received a copy of the CC0 Public Domain Dedication along
|
||||||
|
with
|
||||||
|
this software. If not, see
|
||||||
|
<http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out,
|
||||||
|
const size_t outlen);
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "test_hasher.h"
|
||||||
|
#include "MurmurHash3.h"
|
||||||
|
#include "siphash.h"
|
||||||
|
#include "wapp.h"
|
||||||
|
|
||||||
|
WpTestFuncResult test_murmur3(void) {
|
||||||
|
b8 result = true;
|
||||||
|
|
||||||
|
WpStr8 str = wpStr8Lit("Hello world");
|
||||||
|
WpI32Array arr = wpArray(i32, 1, 2, 3, 4, 5);
|
||||||
|
u64 num = 287324;
|
||||||
|
|
||||||
|
WpHasher hasher = wpX64Mur3HasherWithSeed(873923);
|
||||||
|
|
||||||
|
WpU8Stream str_bytes = wpStream(u8, str.buf, str.size);
|
||||||
|
WpU8Stream arr_bytes = wpStream(u8, (u8 *)arr, wpArrayCount(arr) * wpArrayItemSize(arr));
|
||||||
|
WpU8Stream num_bytes = wpStream(u8, (u8 *)&num, sizeof(u64));
|
||||||
|
|
||||||
|
u64 hash[2] = {0};
|
||||||
|
|
||||||
|
// Sring hash
|
||||||
|
WpU128 mur_hash = hasher.func(&str_bytes, hasher.ctx);
|
||||||
|
MurmurHash3_x64_128(str_bytes.data, str_bytes.count * str_bytes.item_size, hasher.ctx.murmur3, (void *)hash);
|
||||||
|
|
||||||
|
result = result && mur_hash.value[0] == hash[0] && mur_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
// Array hash
|
||||||
|
mur_hash = hasher.func(&arr_bytes, hasher.ctx);
|
||||||
|
MurmurHash3_x64_128(arr_bytes.data, arr_bytes.count * arr_bytes.item_size, hasher.ctx.murmur3, (void *)hash);
|
||||||
|
|
||||||
|
result = result && mur_hash.value[0] == hash[0] && mur_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
// Number hash
|
||||||
|
mur_hash = hasher.func(&num_bytes, hasher.ctx);
|
||||||
|
MurmurHash3_x64_128(num_bytes.data, num_bytes.count * num_bytes.item_size, hasher.ctx.murmur3, (void *)hash);
|
||||||
|
|
||||||
|
result = result && mur_hash.value[0] == hash[0] && mur_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_siphash_128(void) {
|
||||||
|
b8 result = true;
|
||||||
|
|
||||||
|
WpStr8 str = wpStr8Lit("Hello world");
|
||||||
|
WpI32Array arr = wpArray(i32, 1, 2, 3, 4, 5);
|
||||||
|
u64 num = 287324;
|
||||||
|
|
||||||
|
WpU128 key = { .value = { 238742, 671734 } };
|
||||||
|
WpHasher hasher = wpSip24HasherWithKey(key);
|
||||||
|
|
||||||
|
WpU8Stream str_bytes = wpStream(u8, str.buf, str.size);
|
||||||
|
WpU8Stream arr_bytes = wpStream(u8, (u8 *)arr, wpArrayCount(arr) * wpArrayItemSize(arr));
|
||||||
|
WpU8Stream num_bytes = wpStream(u8, (u8 *)&num, sizeof(u64));
|
||||||
|
|
||||||
|
u64 hash[2] = {0};
|
||||||
|
|
||||||
|
// Sring hash
|
||||||
|
WpU128 sip_hash = hasher.func(&str_bytes, hasher.ctx);
|
||||||
|
siphash(str_bytes.data, str_bytes.count * str_bytes.item_size, (void *)&hasher.ctx.siphash.key,
|
||||||
|
(u8 *)hash, sizeof(u64) * 2);
|
||||||
|
|
||||||
|
result = result && sip_hash.value[0] == hash[0] && sip_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
// Array hash
|
||||||
|
sip_hash = hasher.func(&arr_bytes, hasher.ctx);
|
||||||
|
siphash(arr_bytes.data, arr_bytes.count * arr_bytes.item_size, (void *)&hasher.ctx.siphash.key,
|
||||||
|
(u8 *)hash, sizeof(u64) * 2);
|
||||||
|
|
||||||
|
result = result && sip_hash.value[0] == hash[0] && sip_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
// Number hash
|
||||||
|
sip_hash = hasher.func(&num_bytes, hasher.ctx);
|
||||||
|
siphash(num_bytes.data, num_bytes.count * num_bytes.item_size, (void *)&hasher.ctx.siphash.key,
|
||||||
|
(u8 *)hash, sizeof(u64) * 2);
|
||||||
|
|
||||||
|
result = result && sip_hash.value[0] == hash[0] && sip_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "test_hasher.h"
|
||||||
|
#include "MurmurHash3.h"
|
||||||
|
#include "siphash.h"
|
||||||
|
#include "wapp.h"
|
||||||
|
|
||||||
|
WpTestFuncResult test_murmur3(void) {
|
||||||
|
b8 result = true;
|
||||||
|
|
||||||
|
WpStr8 str = wpStr8Lit("Hello world");
|
||||||
|
WpI32Array arr = wpArray(i32, 1, 2, 3, 4, 5);
|
||||||
|
u64 num = 287324;
|
||||||
|
|
||||||
|
WpHasher hasher = wpX64Mur3HasherWithSeed(873923);
|
||||||
|
|
||||||
|
WpU8Stream str_bytes = wpStream(u8, str.buf, str.size);
|
||||||
|
WpU8Stream arr_bytes = wpStream(u8, (u8 *)arr, wpArrayCount(arr) * wpArrayItemSize(arr));
|
||||||
|
WpU8Stream num_bytes = wpStream(u8, (u8 *)&num, sizeof(u64));
|
||||||
|
|
||||||
|
u64 hash[2] = {0};
|
||||||
|
|
||||||
|
// Sring hash
|
||||||
|
WpU128 mur_hash = hasher.func(&str_bytes, hasher.ctx);
|
||||||
|
MurmurHash3_x64_128(str_bytes.data, str_bytes.count * str_bytes.item_size, hasher.ctx.murmur3, (void *)hash);
|
||||||
|
|
||||||
|
result = result && mur_hash.value[0] == hash[0] && mur_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
// Array hash
|
||||||
|
mur_hash = hasher.func(&arr_bytes, hasher.ctx);
|
||||||
|
MurmurHash3_x64_128(arr_bytes.data, arr_bytes.count * arr_bytes.item_size, hasher.ctx.murmur3, (void *)hash);
|
||||||
|
|
||||||
|
result = result && mur_hash.value[0] == hash[0] && mur_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
// Number hash
|
||||||
|
mur_hash = hasher.func(&num_bytes, hasher.ctx);
|
||||||
|
MurmurHash3_x64_128(num_bytes.data, num_bytes.count * num_bytes.item_size, hasher.ctx.murmur3, (void *)hash);
|
||||||
|
|
||||||
|
result = result && mur_hash.value[0] == hash[0] && mur_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_siphash_128(void) {
|
||||||
|
b8 result = true;
|
||||||
|
|
||||||
|
WpStr8 str = wpStr8Lit("Hello world");
|
||||||
|
WpI32Array arr = wpArray(i32, 1, 2, 3, 4, 5);
|
||||||
|
u64 num = 287324;
|
||||||
|
|
||||||
|
WpU128 key = { { 238742, 671734 } };
|
||||||
|
WpHasher hasher = wpSip24HasherWithKey(key);
|
||||||
|
|
||||||
|
WpU8Stream str_bytes = wpStream(u8, str.buf, str.size);
|
||||||
|
WpU8Stream arr_bytes = wpStream(u8, (u8 *)arr, wpArrayCount(arr) * wpArrayItemSize(arr));
|
||||||
|
WpU8Stream num_bytes = wpStream(u8, (u8 *)&num, sizeof(u64));
|
||||||
|
|
||||||
|
u64 hash[2] = {0};
|
||||||
|
|
||||||
|
// Sring hash
|
||||||
|
WpU128 sip_hash = hasher.func(&str_bytes, hasher.ctx);
|
||||||
|
siphash(str_bytes.data, str_bytes.count * str_bytes.item_size, (void *)&hasher.ctx.siphash.key,
|
||||||
|
(u8 *)hash, sizeof(u64) * 2);
|
||||||
|
|
||||||
|
result = result && sip_hash.value[0] == hash[0] && sip_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
// Array hash
|
||||||
|
sip_hash = hasher.func(&arr_bytes, hasher.ctx);
|
||||||
|
siphash(arr_bytes.data, arr_bytes.count * arr_bytes.item_size, (void *)&hasher.ctx.siphash.key,
|
||||||
|
(u8 *)hash, sizeof(u64) * 2);
|
||||||
|
|
||||||
|
result = result && sip_hash.value[0] == hash[0] && sip_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
// Number hash
|
||||||
|
sip_hash = hasher.func(&num_bytes, hasher.ctx);
|
||||||
|
siphash(num_bytes.data, num_bytes.count * num_bytes.item_size, (void *)&hasher.ctx.siphash.key,
|
||||||
|
(u8 *)hash, sizeof(u64) * 2);
|
||||||
|
|
||||||
|
result = result && sip_hash.value[0] == hash[0] && sip_hash.value[1] == hash[1];
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#ifndef TEST_HASHER_H
|
||||||
|
#define TEST_HASHER_H
|
||||||
|
|
||||||
|
#include "wapp.h"
|
||||||
|
|
||||||
|
// Test Murmur3 hash implementation against the reference implementation
|
||||||
|
WpTestFuncResult test_murmur3(void);
|
||||||
|
|
||||||
|
// Test Sip hash implementation against the reference implementation
|
||||||
|
WpTestFuncResult test_siphash_128(void);
|
||||||
|
|
||||||
|
#endif // !TEST_HASHER_H
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "wapp.h"
|
||||||
|
#include "test_hashmap.h"
|
||||||
|
|
||||||
|
wp_persist inline WpU8Stream encoder(void *data);
|
||||||
|
wp_persist inline b8 key_eq(void *a, void *b);
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 0;
|
||||||
|
map = wpHashMap(WpStr8, i32, encoder, key_eq, 3);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 0;
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMapAlloc(WpStr8, i32, &arena, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 0;
|
||||||
|
map = wpHashMapAlloc(WpStr8, i32, &arena, encoder, key_eq, 3);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 0;
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_get_key_size(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashMapKeySize(&map) == sizeof(WpStr8);
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_get_value_size(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashMapValueSize(&map) == sizeof(i32);
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_find(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashLookupResult res = wpHashMapFind(WpStr8, &map, &keys[3]);
|
||||||
|
|
||||||
|
result = result && res.found && res.ref.dist_and_tag > 0;
|
||||||
|
|
||||||
|
WpStr8 key = wpStr8Lit("key0");
|
||||||
|
res = wpHashMapFind(WpStr8, &map, &key);
|
||||||
|
result = result && !res.found;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_update(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 new_value = 0;
|
||||||
|
wpHashMapUpdate(WpStr8, i32, &map, &keys[1], &new_value);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 3 &&
|
||||||
|
wpHashMapValues(i32, &map)[1] == new_value;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_insert_capped(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 3;
|
||||||
|
for (u64 i = 0; i < 3; ++i) {
|
||||||
|
result = result && wpStr8Equal(wpArrayGet(WpStr8, map.keys, i), &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_insert_or_update_capped(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertOrUpdateCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 3;
|
||||||
|
for (u64 i = 0; i < 3; ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashMapKeys(WpStr8, &map)[i], &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 new_value = 0;
|
||||||
|
wpHashMapInsertOrUpdateCapped(WpStr8, i32, &map, &keys[1], &new_value);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 3 &&
|
||||||
|
wpHashMapValues(i32, &map)[1] == new_value;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_insert_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
WpStr8Array map_keys = map.keys;
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertAlloc(WpStr8, i32, &arena, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && map.keys != map_keys && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 4;
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashMapKeys(WpStr8, &map)[i], &keys[i]) &&
|
||||||
|
wpHashMapValues(i32, &map)[i] == values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_insert_or_update_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertOrUpdateAlloc(WpStr8, i32, &arena, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 4;
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashMapKeys(WpStr8, &map)[i], &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 new_value = 0;
|
||||||
|
wpHashMapInsertOrUpdateAlloc(WpStr8, i32, &arena, &map, &keys[1], &new_value);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 4 &&
|
||||||
|
wpHashMapValues(i32, &map)[1] == new_value;
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_remove(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpHashMapRemove(WpStr8, i32, &map, &keys[0]);
|
||||||
|
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 2;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_clear(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpHashMapClear(WpStr8, i32, &map);
|
||||||
|
|
||||||
|
result = result && wpHashMapCount(&map) == 0;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline WpU8Stream encoder(void *data) {
|
||||||
|
WpStr8 *str = (WpStr8 *)data;
|
||||||
|
return wpStream(u8, str->buf, str->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline b8 key_eq(void *a, void *b) {
|
||||||
|
WpStr8 *a_str = (WpStr8 *)a;
|
||||||
|
WpStr8 *b_str = (WpStr8 *)b;
|
||||||
|
return wpStr8Equal(a_str, b_str);
|
||||||
|
}
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "wapp.h"
|
||||||
|
#include "test_hashmap.h"
|
||||||
|
|
||||||
|
wp_persist inline WpU8Stream encoder(void *data);
|
||||||
|
wp_persist inline b8 key_eq(void *a, void *b);
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 0;
|
||||||
|
map = wpHashMap(WpStr8, i32, encoder, key_eq, 3);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 0;
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMapAlloc(WpStr8, i32, &arena, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 0;
|
||||||
|
map = wpHashMapAlloc(WpStr8, i32, &arena, encoder, key_eq, 3);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 0;
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_get_key_size(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashMapKeySize(&map) == sizeof(WpStr8);
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_get_value_size(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashMapValueSize(&map) == sizeof(i32);
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_find(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashLookupResult res = wpHashMapFind(WpStr8, &map, &keys[3]);
|
||||||
|
|
||||||
|
result = result && res.found && res.ref.dist_and_tag > 0;
|
||||||
|
|
||||||
|
WpStr8 key = wpStr8Lit("key0");
|
||||||
|
res = wpHashMapFind(WpStr8, &map, &key);
|
||||||
|
result = result && !res.found;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_update(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 new_value = 0;
|
||||||
|
wpHashMapUpdate(WpStr8, i32, &map, &keys[1], &new_value);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 3 &&
|
||||||
|
wpHashMapValues(i32, &map)[1] == new_value;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_insert_capped(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 3;
|
||||||
|
for (u64 i = 0; i < 3; ++i) {
|
||||||
|
result = result && wpStr8Equal(wpArrayGet(WpStr8, map.keys, i), &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_insert_or_update_capped(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertOrUpdateCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 3;
|
||||||
|
for (u64 i = 0; i < 3; ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashMapKeys(WpStr8, &map)[i], &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 new_value = 0;
|
||||||
|
wpHashMapInsertOrUpdateCapped(WpStr8, i32, &map, &keys[1], &new_value);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 3 &&
|
||||||
|
wpHashMapValues(i32, &map)[1] == new_value;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_insert_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
WpStr8Array map_keys = (WpStr8Array)map.keys;
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertAlloc(WpStr8, i32, &arena, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && map.keys != map_keys && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 4;
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashMapKeys(WpStr8, &map)[i], &keys[i]) &&
|
||||||
|
wpHashMapValues(i32, &map)[i] == values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_insert_or_update_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertOrUpdateAlloc(WpStr8, i32, &arena, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 4;
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashMapKeys(WpStr8, &map)[i], &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 new_value = 0;
|
||||||
|
wpHashMapInsertOrUpdateAlloc(WpStr8, i32, &arena, &map, &keys[1], &new_value);
|
||||||
|
result = result && wpHashMapCapacity(&map) == 8 && wpHashMapCount(&map) == 4 &&
|
||||||
|
wpHashMapValues(i32, &map)[1] == new_value;
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_remove(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 4);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpHashMapRemove(WpStr8, i32, &map, &keys[0]);
|
||||||
|
|
||||||
|
result = result && wpHashMapCapacity(&map) == 4 && wpHashMapCount(&map) == 2;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap_clear(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashMap map = wpHashMap(WpStr8, i32, encoder, key_eq, 8);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
WpI32Array values = wpArray(i32, 1, 2, 3, 4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashMapInsertCapped(WpStr8, i32, &map, &keys[i], &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpHashMapClear(WpStr8, i32, &map);
|
||||||
|
|
||||||
|
result = result && wpHashMapCount(&map) == 0;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline WpU8Stream encoder(void *data) {
|
||||||
|
WpStr8 *str = (WpStr8 *)data;
|
||||||
|
return wpStream(u8, str->buf, str->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline b8 key_eq(void *a, void *b) {
|
||||||
|
WpStr8 *a_str = (WpStr8 *)a;
|
||||||
|
WpStr8 *b_str = (WpStr8 *)b;
|
||||||
|
return wpStr8Equal(a_str, b_str);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#ifndef TEST_HASHMAP_H
|
||||||
|
#define TEST_HASHMAP_H
|
||||||
|
|
||||||
|
#include "wapp.h"
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashmap(void);
|
||||||
|
WpTestFuncResult test_hashmap_alloc(void);
|
||||||
|
WpTestFuncResult test_hashmap_get_key_size(void);
|
||||||
|
WpTestFuncResult test_hashmap_get_value_size(void);
|
||||||
|
WpTestFuncResult test_hashmap_find(void);
|
||||||
|
WpTestFuncResult test_hashmap_update(void);
|
||||||
|
WpTestFuncResult test_hashmap_insert_capped(void);
|
||||||
|
WpTestFuncResult test_hashmap_insert_or_update_capped(void);
|
||||||
|
WpTestFuncResult test_hashmap_insert_alloc(void);
|
||||||
|
WpTestFuncResult test_hashmap_insert_or_update_alloc(void);
|
||||||
|
WpTestFuncResult test_hashmap_remove(void);
|
||||||
|
WpTestFuncResult test_hashmap_clear(void);
|
||||||
|
|
||||||
|
#endif // !TEST_HASHMAP_H
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "wapp.h"
|
||||||
|
#include "test_hashset.h"
|
||||||
|
|
||||||
|
wp_persist inline WpU8Stream encoder(void *data);
|
||||||
|
wp_persist inline b8 key_eq(void *a, void *b);
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashSetCapacity(&set) == 8 && wpHashSetCount(&set) == 0;
|
||||||
|
set = wpHashSet(WpStr8, encoder, key_eq, 3);
|
||||||
|
result = result && wpHashSetCapacity(&set) == 4 && wpHashSetCount(&set) == 0;
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSetAlloc(WpStr8, &arena, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashSetCapacity(&set) == 8 && wpHashSetCount(&set) == 0;
|
||||||
|
set = wpHashSetAlloc(WpStr8, &arena, encoder, key_eq, 3);
|
||||||
|
result = result && wpHashSetCapacity(&set) == 4 && wpHashSetCount(&set) == 0;
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_get_item_size(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashSetItemSize(&set) == sizeof(WpStr8);
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_find(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 8);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertCapped(WpStr8, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashLookupResult res = wpHashSetFind(WpStr8, &set, &keys[3]);
|
||||||
|
|
||||||
|
result = result && res.found && res.ref.dist_and_tag > 0;
|
||||||
|
|
||||||
|
WpStr8 key = wpStr8Lit("key0");
|
||||||
|
res = wpHashSetFind(WpStr8, &set, &key);
|
||||||
|
result = result && !res.found;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_insert_capped(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 4);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertCapped(WpStr8, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && wpHashSetCapacity(&set) == 4 && wpHashSetCount(&set) == 3;
|
||||||
|
for (u64 i = 0; i < 3; ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashSetItems(WpStr8, &set)[i], &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_insert_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 4);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
|
||||||
|
WpStr8Array set_keys = set.keys;
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertAlloc(WpStr8, &arena, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && set.keys != set_keys && wpHashSetCapacity(&set) == 8 && wpHashSetCount(&set) == 4;
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashSetItems(WpStr8, &set)[i], &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_remove(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 4);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertCapped(WpStr8, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpHashSetRemove(WpStr8, &set, &keys[0]);
|
||||||
|
|
||||||
|
result = result && wpHashSetCapacity(&set) == 4 && wpHashSetCount(&set) == 2;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_clear(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 8);
|
||||||
|
WpStr8Array keys = wpArray(
|
||||||
|
WpStr8,
|
||||||
|
wpStr8Lit("key1"),
|
||||||
|
wpStr8Lit("key2"),
|
||||||
|
wpStr8Lit("key3"),
|
||||||
|
wpStr8Lit("key4")
|
||||||
|
);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertCapped(WpStr8, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpHashSetClear(WpStr8, &set);
|
||||||
|
|
||||||
|
result = result && wpHashSetCount(&set) == 0;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline WpU8Stream encoder(void *data) {
|
||||||
|
WpStr8 *str = (WpStr8 *)data;
|
||||||
|
return wpStream(u8, str->buf, str->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline b8 key_eq(void *a, void *b) {
|
||||||
|
WpStr8 *a_str = (WpStr8 *)a;
|
||||||
|
WpStr8 *b_str = (WpStr8 *)b;
|
||||||
|
return wpStr8Equal(a_str, b_str);
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#include "wapp.h"
|
||||||
|
#include "test_hashset.h"
|
||||||
|
|
||||||
|
wp_persist inline WpU8Stream encoder(void *data);
|
||||||
|
wp_persist inline b8 key_eq(void *a, void *b);
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashSetCapacity(&set) == 8 && wpHashSetCount(&set) == 0;
|
||||||
|
set = wpHashSet(WpStr8, encoder, key_eq, 3);
|
||||||
|
result = result && wpHashSetCapacity(&set) == 4 && wpHashSetCount(&set) == 0;
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSetAlloc(WpStr8, &arena, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashSetCapacity(&set) == 8 && wpHashSetCount(&set) == 0;
|
||||||
|
set = wpHashSetAlloc(WpStr8, &arena, encoder, key_eq, 3);
|
||||||
|
result = result && wpHashSetCapacity(&set) == 4 && wpHashSetCount(&set) == 0;
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_get_item_size(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 8);
|
||||||
|
result = result && wpHashSetItemSize(&set) == sizeof(WpStr8);
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_find(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 8);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertCapped(WpStr8, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpHashLookupResult res = wpHashSetFind(WpStr8, &set, &keys[3]);
|
||||||
|
|
||||||
|
result = result && res.found && res.ref.dist_and_tag > 0;
|
||||||
|
|
||||||
|
WpStr8 key = wpStr8Lit("key0");
|
||||||
|
res = wpHashSetFind(WpStr8, &set, &key);
|
||||||
|
result = result && !res.found;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_insert_capped(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 4);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertCapped(WpStr8, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && wpHashSetCapacity(&set) == 4 && wpHashSetCount(&set) == 3;
|
||||||
|
for (u64 i = 0; i < 3; ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashSetItems(WpStr8, &set)[i], &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_insert_alloc(void) {
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInit(KiB(4));
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 4);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
|
||||||
|
WpStr8Array set_keys = (WpStr8Array)set.keys;
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertAlloc(WpStr8, &arena, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result && set.keys != set_keys && wpHashSetCapacity(&set) == 8 && wpHashSetCount(&set) == 4;
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
result = result && wpStr8Equal(&wpHashSetItems(WpStr8, &set)[i], &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_remove(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 4);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertCapped(WpStr8, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpHashSetRemove(WpStr8, &set, &keys[0]);
|
||||||
|
|
||||||
|
result = result && wpHashSetCapacity(&set) == 4 && wpHashSetCount(&set) == 2;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset_clear(void) {
|
||||||
|
b8 result = true;
|
||||||
|
WpHashSet set = wpHashSet(WpStr8, encoder, key_eq, 8);
|
||||||
|
WpStr8 key1 = wpStr8Lit("key1");
|
||||||
|
WpStr8 key2 = wpStr8Lit("key2");
|
||||||
|
WpStr8 key3 = wpStr8Lit("key3");
|
||||||
|
WpStr8 key4 = wpStr8Lit("key4");
|
||||||
|
WpStr8Array keys = wpArray(WpStr8, key1, key2, key3, key4);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < wpArrayCount(keys); ++i) {
|
||||||
|
wpHashSetInsertCapped(WpStr8, &set, &keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpHashSetClear(WpStr8, &set);
|
||||||
|
|
||||||
|
result = result && wpHashSetCount(&set) == 0;
|
||||||
|
|
||||||
|
return wpTesterResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline WpU8Stream encoder(void *data) {
|
||||||
|
WpStr8 *str = (WpStr8 *)data;
|
||||||
|
return wpStream(u8, str->buf, str->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_persist inline b8 key_eq(void *a, void *b) {
|
||||||
|
WpStr8 *a_str = (WpStr8 *)a;
|
||||||
|
WpStr8 *b_str = (WpStr8 *)b;
|
||||||
|
return wpStr8Equal(a_str, b_str);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
#ifndef TEST_HASHSET_H
|
||||||
|
#define TEST_HASHSET_H
|
||||||
|
|
||||||
|
#include "wapp.h"
|
||||||
|
|
||||||
|
WpTestFuncResult test_hashset(void);
|
||||||
|
WpTestFuncResult test_hashset_alloc(void);
|
||||||
|
WpTestFuncResult test_hashset_get_item_size(void);
|
||||||
|
WpTestFuncResult test_hashset_find(void);
|
||||||
|
WpTestFuncResult test_hashset_insert_capped(void);
|
||||||
|
WpTestFuncResult test_hashset_insert_alloc(void);
|
||||||
|
WpTestFuncResult test_hashset_remove(void);
|
||||||
|
WpTestFuncResult test_hashset_clear(void);
|
||||||
|
|
||||||
|
#endif // !TEST_HASHSET_H
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
#include "test_stream.h"
|
#include "test_stream.h"
|
||||||
#include "test_cpath.h"
|
#include "test_cpath.h"
|
||||||
#include "test_file.h"
|
#include "test_file.h"
|
||||||
|
#include "test_hasher.h"
|
||||||
|
#include "test_hashset.h"
|
||||||
|
#include "test_hashmap.h"
|
||||||
#include "test_shell_commander.h"
|
#include "test_shell_commander.h"
|
||||||
#include "wapp.h"
|
#include "wapp.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -43,6 +46,7 @@ int main(void) {
|
|||||||
test_i32_array_append_alloc,
|
test_i32_array_append_alloc,
|
||||||
test_i32_array_extend_alloc,
|
test_i32_array_extend_alloc,
|
||||||
test_i32_array_copy_alloc,
|
test_i32_array_copy_alloc,
|
||||||
|
test_i32_array_remove_swap_end,
|
||||||
test_i32_array_pop,
|
test_i32_array_pop,
|
||||||
test_i32_array_clear,
|
test_i32_array_clear,
|
||||||
test_queue_push,
|
test_queue_push,
|
||||||
@@ -101,6 +105,28 @@ int main(void) {
|
|||||||
test_wapp_file_close,
|
test_wapp_file_close,
|
||||||
test_wapp_file_rename,
|
test_wapp_file_rename,
|
||||||
test_wapp_file_remove,
|
test_wapp_file_remove,
|
||||||
|
test_murmur3,
|
||||||
|
test_siphash_128,
|
||||||
|
test_hashset,
|
||||||
|
test_hashset_alloc,
|
||||||
|
test_hashset_get_item_size,
|
||||||
|
test_hashset_find,
|
||||||
|
test_hashset_insert_capped,
|
||||||
|
test_hashset_insert_alloc,
|
||||||
|
test_hashset_remove,
|
||||||
|
test_hashset_clear,
|
||||||
|
test_hashmap,
|
||||||
|
test_hashmap_alloc,
|
||||||
|
test_hashmap_get_key_size,
|
||||||
|
test_hashmap_get_value_size,
|
||||||
|
test_hashmap_find,
|
||||||
|
test_hashmap_update,
|
||||||
|
test_hashmap_insert_capped,
|
||||||
|
test_hashmap_insert_or_update_capped,
|
||||||
|
test_hashmap_insert_alloc,
|
||||||
|
test_hashmap_insert_or_update_alloc,
|
||||||
|
test_hashmap_remove,
|
||||||
|
test_hashmap_clear,
|
||||||
test_commander_cmd_success,
|
test_commander_cmd_success,
|
||||||
test_commander_cmd_failure,
|
test_commander_cmd_failure,
|
||||||
test_commander_cmd_out_buf_success,
|
test_commander_cmd_out_buf_success,
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#include "test_stream.h"
|
#include "test_stream.h"
|
||||||
#include "test_cpath.h"
|
#include "test_cpath.h"
|
||||||
#include "test_file.h"
|
#include "test_file.h"
|
||||||
|
#include "test_hasher.h"
|
||||||
|
#include "test_hashset.h"
|
||||||
|
#include "test_hashmap.h"
|
||||||
#include "test_shell_commander.h"
|
#include "test_shell_commander.h"
|
||||||
#include "wapp.h"
|
#include "wapp.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -43,6 +46,7 @@ int main(void) {
|
|||||||
test_i32_array_append_alloc,
|
test_i32_array_append_alloc,
|
||||||
test_i32_array_extend_alloc,
|
test_i32_array_extend_alloc,
|
||||||
test_i32_array_copy_alloc,
|
test_i32_array_copy_alloc,
|
||||||
|
test_i32_array_remove_swap_end,
|
||||||
test_i32_array_pop,
|
test_i32_array_pop,
|
||||||
test_i32_array_clear,
|
test_i32_array_clear,
|
||||||
test_queue_push,
|
test_queue_push,
|
||||||
@@ -101,6 +105,28 @@ int main(void) {
|
|||||||
test_wapp_file_close,
|
test_wapp_file_close,
|
||||||
test_wapp_file_rename,
|
test_wapp_file_rename,
|
||||||
test_wapp_file_remove,
|
test_wapp_file_remove,
|
||||||
|
test_murmur3,
|
||||||
|
test_siphash_128,
|
||||||
|
test_hashset,
|
||||||
|
test_hashset_alloc,
|
||||||
|
test_hashset_get_item_size,
|
||||||
|
test_hashset_find,
|
||||||
|
test_hashset_insert_capped,
|
||||||
|
test_hashset_insert_alloc,
|
||||||
|
test_hashset_remove,
|
||||||
|
test_hashset_clear,
|
||||||
|
test_hashmap,
|
||||||
|
test_hashmap_alloc,
|
||||||
|
test_hashmap_get_key_size,
|
||||||
|
test_hashmap_get_value_size,
|
||||||
|
test_hashmap_find,
|
||||||
|
test_hashmap_update,
|
||||||
|
test_hashmap_insert_capped,
|
||||||
|
test_hashmap_insert_or_update_capped,
|
||||||
|
test_hashmap_insert_alloc,
|
||||||
|
test_hashmap_insert_or_update_alloc,
|
||||||
|
test_hashmap_remove,
|
||||||
|
test_hashmap_clear,
|
||||||
test_commander_cmd_success,
|
test_commander_cmd_success,
|
||||||
test_commander_cmd_failure,
|
test_commander_cmd_failure,
|
||||||
test_commander_cmd_out_buf_success,
|
test_commander_cmd_out_buf_success,
|
||||||
|
|||||||
Reference in New Issue
Block a user