55 Commits

Author SHA1 Message Date
abdelrahman 66acbaad9e Release v2.5.0
Release / release (push) Successful in 3s
2026-09-24 00:53:36 +01:00
abdelrahman 180292289d Add hash map implementation
Release / release (push) Successful in 3s
2026-09-24 00:52:43 +01:00
abdelrahman 68640dc5e2 Add hash set implementation
Release / release (push) Successful in 4s
2026-09-23 22:34:23 +01:00
Abdelrahman Said 20e890964f Add hash table for default hasher
Release / release (push) Successful in 3s
2026-09-23 00:21:51 +01:00
Abdelrahman Said c215486442 Restructure hasher implementation
Release / release (push) Successful in 3s
2026-09-23 00:02:37 +01:00
Abdelrahman Said 9881c0ac9a Update hasher data to context
Release / release (push) Successful in 4s
2026-09-22 21:47:46 +01:00
abdelrahman 17be4841e6 Update siphash comment
Release / release (push) Successful in 3s
2026-09-22 00:57:46 +01:00
abdelrahman 421728c137 Add internal hash table implementation
Release / release (push) Successful in 4s
2026-09-21 22:15:54 +01:00
abdelrahman b014ffa3b1 Add swap utility 2026-09-21 22:03:54 +01:00
abdelrahman 8da18774f0 Update array remove swap to handle deleting last index 2026-09-21 22:03:40 +01:00
abdelrahman ac5baef3b8 Switch array NULL pointer checks to debug asserts
Release / release (push) Successful in 2s
2026-09-21 07:41:46 +01:00
abdelrahman e90229db7a Reformat
Release / release (push) Successful in 3s
2026-09-21 07:38:16 +01:00
abdelrahman 4a92f55f17 Reformat
Release / release (push) Successful in 3s
2026-09-20 21:44:48 +01:00
abdelrahman 3c81feedbb Add wpArrayRemoveSwapEnd
Release / release (push) Successful in 3s
2026-09-19 22:41:10 +01:00
Abdelrahman Said 9029e21a4f Update str8 printf spec
Release / release (push) Successful in 4s
2026-09-19 11:37:55 +01:00
abdelrahman 605c1ddfae Add wpArrayZero
Release / release (push) Successful in 3s
2026-09-16 01:28:11 +01:00
Abdelrahman Said f73a870a34 Convert hasher to interface and remove spihash64
Release / release (push) Successful in 3s
2026-09-16 01:11:24 +01:00
Abdelrahman Said 8b3b1816b3 Reformat
Release / release (push) Successful in 3s
2026-09-16 00:18:01 +01:00
Abdelrahman Said f46c3ab38a Extract splitmix64 PRNG
Release / release (push) Successful in 4s
2026-09-16 00:12:50 +01:00
abdelrahman 9226891bb9 wpArrayClear memsets members to 0
Release / release (push) Successful in 3s
2026-09-13 21:14:11 +01:00
abdelrahman 6fdda743fb Fix ArenaStorageType label
Release / release (push) Successful in 2s
2026-09-13 02:32:59 +01:00
abdelrahman 575e0a52b1 Add labels to all typedef'd structs and enums
Release / release (push) Successful in 4s
2026-09-13 02:31:46 +01:00
abdelrahman 5df1a105c7 Update C++ hasher initialisers
Release / release (push) Successful in 2s
2026-09-13 00:39:52 +01:00
abdelrahman 34a1b2c1db Fix hasher initialisers
Release / release (push) Successful in 2s
2026-09-13 00:25:03 +01:00
abdelrahman f3a8045ecc Update hasher
Release / release (push) Successful in 3s
2026-09-13 00:20:18 +01:00
abdelrahman 6a3326e9a5 Add scratchpad to .gitignore
Release / release (push) Successful in 3s
2026-09-12 21:14:57 +01:00
Abdelrahman Said 222eb006e6 Add extra reference for robin hood hash tables
Release / release (push) Successful in 3s
2026-09-06 22:53:34 +01:00
abdelrahman 5e67c596b9 Remove all uses of names starting with underscore
Release / release (push) Successful in 3s
2026-09-06 18:15:23 +01:00
abdelrahman 9055c5c825 Add more xorshift utilities
Release / release (push) Successful in 2s
2026-09-06 13:40:13 +01:00
abdelrahman c83f9333de Update xorshift PRNG
Release / release (push) Successful in 4s
2026-09-06 13:31:37 +01:00
Abdelrahman Said 07e0034783 Update CHANGELOG
Release / release (push) Successful in 2s
2026-09-02 00:13:18 +01:00
Abdelrahman Said e015dfceda Add aliases for integer constants
Release / release (push) Successful in 3s
2026-09-02 00:11:23 +01:00
Abdelrahman Said 60467d56b9 Add paper for robin hood hashing
Release / release (push) Successful in 4s
2026-09-01 21:35:58 +01:00
Abdelrahman Said 2e943affb7 Add reference for open addressing/separate chaining
Release / release (push) Successful in 2s
2026-08-31 23:43:48 +01:00
Abdelrahman Said aa48942d91 Get most recent ankerl implementation
Release / release (push) Successful in 3s
2026-08-31 23:34:56 +01:00
abdelrahman 5ae4d7d6d1 Add documents
Release / release (push) Successful in 2s
2026-08-31 21:16:21 +01:00
abdelrahman 900c16415b Add implementation for siphash
Release / release (push) Successful in 4s
2026-08-31 02:15:01 +01:00
abdelrahman bca2e720ad Add Murmur3 validation
Release / release (push) Successful in 3s
2026-08-30 23:56:50 +01:00
abdelrahman 850f709a10 Update Murmur3 hasher IO
Release / release (push) Successful in 3s
2026-08-30 23:50:22 +01:00
abdelrahman 55ff77c4ea Add implementation for the murmur3 x64_128 hash
Release / release (push) Successful in 3s
2026-08-30 22:03:28 +01:00
abdelrahman d5578f009a Update stream utilities and fix peek logic
Release / release (push) Successful in 4s
2026-08-30 17:13:32 +01:00
abdelrahman b3830683f6 Print changelog contents to stdout
Release / release (push) Successful in 3s
2026-08-30 14:34:21 +01:00
abdelrahman 0060c51c12 Only extract changelog for new releases
Release / release (push) Successful in 3s
2026-08-30 14:31:11 +01:00
abdelrahman 23613d16b7 Update release workflow
Release / release (push) Successful in 4s
2026-08-30 14:20:47 +01:00
abdelrahman 8cd1d56b4a Save extracted changelog in workspace 2026-08-30 14:20:40 +01:00
abdelrahman 6b8fe820aa Remove empty line for testing
Release / release (push) Failing after 1s
2026-08-30 13:49:15 +01:00
abdelrahman 2554810306 Use python3 in release workflow
Release / release (push) Failing after 3s
2026-08-30 13:48:24 +01:00
abdelrahman 08029141d4 Extract version changelog in release process
Release / release (push) Failing after 4s
2026-08-30 13:45:40 +01:00
abdelrahman a1123b361d Include CHANGELOG file in release packages 2026-08-30 13:45:21 +01:00
abdelrahman f4d2e551b5 Add CHANGELOG 2026-08-30 12:39:03 +01:00
abdelrahman 1bbe124e3e Update VERSION
Release / release (push) Successful in 5s
2026-08-30 02:32:35 +01:00
abdelrahman c1b2e29c07 Add stream structure and utilities 2026-08-30 02:21:08 +01:00
abdelrahman a51686c8f0 Add compiler detection macros 2026-08-30 00:15:36 +01:00
Abdelrahman Said f599b5f425 Reformat
Release / release (push) Successful in 3s
2026-08-22 20:32:58 +01:00
abdelrahman 0063bb8641 Fix missing log in Makefile
Release / release (push) Successful in 4s
2026-08-17 05:24:10 +01:00
99 changed files with 4747 additions and 555 deletions
+28 -10
View File
@@ -34,6 +34,21 @@ jobs:
echo "version=$VERSION" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Extract version changelog
if: steps.tag.outputs.version
id: changelog
run: |
VERSION="${{ steps.tag.outputs.version }}"
CHANGELOG_FILE=$(python3 scripts/get_changelog.py $VERSION)
if [[ $? != 0 ]]; then
echo "No changelog found for version $VERSION"
exit 1
fi
cat "$CHANGELOG_FILE"
echo "changelog_file=$CHANGELOG_FILE" >> $GITHUB_OUTPUT
- name: Build Artifacts - name: Build Artifacts
if: steps.tag.outputs.version if: steps.tag.outputs.version
run: | run: |
@@ -46,17 +61,17 @@ jobs:
id: create_release id: create_release
run: | run: |
VERSION="${{ steps.tag.outputs.version }}" VERSION="${{ steps.tag.outputs.version }}"
RESPONSE=$(curl -s -X POST \ CHANGELOG_FILE="${{ steps.changelog.outputs.changelog_file }}"
RESPONSE=$(jq -n \
--arg tag "v$VERSION" \
--arg name "wapp-v$VERSION" \
--rawfile body "$CHANGELOG_FILE" \
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}' \
| curl -s -X POST \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
"https://git.thewizardapprentice.com/api/v1/repos/${{ gitea.repository }}/releases" \ --data-binary @- \
-d '{ "https://git.thewizardapprentice.com/api/v1/repos/${{ gitea.repository }}/releases")
"tag_name": "v'"$VERSION"'",
"name": "wapp-v'"$VERSION"'",
"body": "Automated release for wapp-v'"$VERSION"'",
"draft": false,
"prerelease": false
}')
echo "$RESPONSE" echo "$RESPONSE"
RELEASE_ID=$(echo $RESPONSE | jq -r '.id') RELEASE_ID=$(echo $RESPONSE | jq -r '.id')
@@ -78,4 +93,7 @@ jobs:
- name: Cleanup - name: Cleanup
if: steps.tag.outputs.version if: steps.tag.outputs.version
run: rm -rf dist/* run: |
CHANGELOG_FILE="${{ steps.changelog.outputs.changelog_file }}"
rm -rf dist/*
rm -f "$CHANGELOG_FILE"
+1
View File
@@ -10,5 +10,6 @@ test.*
compile_commands.json compile_commands.json
libwapp-build libwapp-build
dist dist
scratchpad
*.vs *.vs
__pycache__ __pycache__
+76
View File
@@ -0,0 +1,76 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [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
### Added
- `wpStreamHasCount`, `wpStreamPeekWithOffset` and `wpStreamConsumeCount` utilities
### Fixed
- Logic for peeking at stream contents
## [2.3.0] - 2026-08-29
### Added
- Compiler detection macros:
- `WP_PLATFORM_CLANG` for the clang compiler
- `WP_PLATFORM_CLANGPP` for the clang++ compiler
- `WP_PLATFORM_CLANG_MAJOR` Major version number for the clang/clang++ compiler
- `WP_PLATFORM_CLANG_MINOR` Minor version number for the clang/clang++ compiler
- `WP_PLATFORM_CLANG_PATCH` Patch version number for the clang/clang++ compiler
- `WP_PLATFORM_GCC` for the gcc compiler
- `WP_PLATFORM_GPP` for the g++ compiler
- `WP_PLATFORM_GCC_MAJOR` Major version number for the gcc/g++ compiler
- `WP_PLATFORM_GCC_MINOR` Minor version number for the gcc/g++ compiler
- `WP_PLATFORM_GCC_PATCH` Patch version number for the gcc/g++ compiler
- `WP_PLATFORM_MSVC` for Microsoft's Visual C++ compiler
- `WP_PLATFORM_MSVC_FULL_VERSION` Full version string for the MSVC compiler
- `WP_PLATFORM_MSVC_VERSION` Version string for the MSVC compiler
- Generic `WpStream` struct to wrap a stream of data
- `WpVoidPtrStream`, `WpC8Stream`, `WpC16Stream`, `WpC32Stream`, `WpU8Stream`, `WpU16Stream`, `WpU32Stream`, `WpU64Stream`, `WpB8Stream`, `WpI8Stream`, `WpI16Stream`, `WpI32Stream`, `WpI64Stream`, `WpF32Stream`, `WpF64Stream`, `WpF128Stream`, `WpUptrStream`, `WpIptrStream` and `WpStr8Stream` aliases for `WpStream` for readability
- Utilities for working with data streams:
- `wpStreamAtEnd`
- `wpStreamHasNext`
- `wpStreamPeek`
- `wpStreamConsume`
+5 -1
View File
@@ -121,13 +121,17 @@ help:
@$(ECHO_E) " $(GREEN)make help$(RESET) Print this help message and exit." @$(ECHO_E) " $(GREEN)make help$(RESET) Print this help message and exit."
full: LIB_SRC = src/wapp.c full: LIB_SRC = src/wapp.c
full: INCLUDES = common os base prng testing uuid full: INCLUDES = common os base log prng testing uuid
full: install full: install
base: LIB_SRC = src/base/wapp_base.c base: LIB_SRC = src/base/wapp_base.c
base: INCLUDES = common base base: INCLUDES = common base
base: install base: install
log: LIB_SRC = src/log/wapp_log.c
log: INCLUDES = common os base log
log: install
os: LIB_SRC = src/os/wapp_os.c os: LIB_SRC = src/os/wapp_os.c
os: INCLUDES = common os base os: INCLUDES = common os base
os: install os: install
+1 -1
View File
@@ -1 +1 @@
2.2.0 2.5.0
+51
View File
@@ -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/)
+1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
cp -r src wapp cp -r src wapp
cp CHANGELOG.md wapp
mkdir -p dist mkdir -p dist
+56
View File
@@ -0,0 +1,56 @@
import os
import re
import argparse
from pathlib import Path
VERSION_HEADER = re.compile(r"\[\d+.\d+.\d+\]")
SCRIPT_DIR = Path(__file__).absolute().parent.parent
def main():
parser = argparse.ArgumentParser()
parser.add_argument("version")
args = parser.parse_args()
changelog = get_changelog(args.version)
outfilename = save_changelog(args.version, changelog)
print(outfilename)
def get_changelog(version: str) -> list[str]:
changelog = SCRIPT_DIR / "CHANGELOG.md"
with changelog.open("r") as infile:
lines = infile.readlines()
start = -1
end = -1
for i, line in enumerate(lines):
if start == -1:
match = re.search(version, line)
if match is None:
continue
start = i
else:
match = VERSION_HEADER.search(line)
if match is not None:
end = i
break
if start == -1:
exit(1)
return lines[start:end] if end > -1 else lines[start:]
def save_changelog(version: str, lines: list[str]) -> str:
version_changelog = SCRIPT_DIR / f"wapp-changelog-{version}.md"
with version_changelog.open("w") as outfile:
outfile.writelines(lines)
return str(version_changelog)
if __name__ == "__main__":
main()
+120 -86
View File
@@ -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
View File
@@ -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
+37 -37
View File
@@ -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");
+32 -32
View File
@@ -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
+25
View File
@@ -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];
}
+55
View File
@@ -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
+126
View File
@@ -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;
}
+28
View File
@@ -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
+190
View File
@@ -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;
}
+29
View File
@@ -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
+83
View File
@@ -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);
}
}
+134
View File
@@ -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
+51
View File
@@ -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);
}
}
+105
View File
@@ -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
+292
View File
@@ -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");
}
}
+101
View File
@@ -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
+1 -1
View File
@@ -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,
+8 -8
View File
@@ -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);
} }
+7 -7
View File
@@ -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
+43
View File
@@ -0,0 +1,43 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "stream.h"
#include "../../common/aliases/aliases.h"
#include "../../common/assert/assert.h"
void streamValidate(const WpStream *stream, u64 item_size);
b8 wpStreamAtEnd(const WpStream *stream) {
return stream->position >= stream->count;
}
b8 streamHasCount(const WpStream *stream, u64 count) {
return stream->position + count <= stream->count;
}
void *streamPeekWithOffset(const WpStream *stream, u64 offset, u64 item_size) {
streamValidate(stream, item_size);
if (streamHasCount(stream, offset + 1)) {
u64 index = (stream->position + offset) * stream->item_size;
return (void *)(&((u8 *)(stream->data))[index]);
}
return NULL;
}
void *streamConsumeCount(WpStream *stream, u64 count, u64 item_size) {
streamValidate(stream, item_size);
if (streamHasCount(stream, count)) {
u64 index = stream->position * stream->item_size;
stream->position += count;
return (void *)(&((u8 *)(stream->data))[index]);
}
return NULL;
}
void streamValidate(const WpStream *stream, u64 item_size) {
wpDebugAssert(stream != NULL, "`stream` should not be NULL");
wpRuntimeAssert(stream->item_size == item_size, "Invalid item type provided");
}
+80
View File
@@ -0,0 +1,80 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef STREAM_H
#define STREAM_H
#include "../../common/aliases/aliases.h"
#include "../../common/platform/platform.h"
#ifdef WP_PLATFORM_CPP
BEGIN_C_LINKAGE
#endif // !WP_PLATFORM_CPP
typedef struct WpStream {
void *data;
u64 count;
u64 position;
u64 item_size;
} WpStream;
// NOTE (Abdelrahman): WpStream typedefs for readability
typedef WpStream WpVoidPtrStream;
typedef WpStream WpC8Stream;
typedef WpStream WpC16Stream;
typedef WpStream WpC32Stream;
typedef WpStream WpU8Stream;
typedef WpStream WpU16Stream;
typedef WpStream WpU32Stream;
typedef WpStream WpU64Stream;
typedef WpStream WpB8Stream;
typedef WpStream WpI8Stream;
typedef WpStream WpI16Stream;
typedef WpStream WpI32Stream;
typedef WpStream WpI64Stream;
typedef WpStream WpF32Stream;
typedef WpStream WpF64Stream;
typedef WpStream WpF128Stream;
typedef WpStream WpUptrStream;
typedef WpStream WpIptrStream;
typedef WpStream WpStr8Stream;
#ifdef WP_PLATFORM_CPP
#define wpStream(TYPE, DATA, SIZE) ([&]() { \
return WpStream{ \
DATA, \
SIZE / sizeof(TYPE), \
0, \
sizeof(TYPE) \
}; \
}())
#else
#define wpStream(TYPE, DATA, SIZE) ( \
(WpStream){ \
.data = DATA, \
.count = SIZE / sizeof(TYPE), \
.position = 0, \
.item_size = sizeof(TYPE) \
} \
)
#endif
#define wpStreamHasNext(STREAM) streamHasCount(STREAM, 1)
#define wpStreamHasCount(STREAM, COUNT) streamHasCount(STREAM, COUNT)
#define wpStreamPeek(TYPE, STREAM) ((TYPE *)streamPeekWithOffset(STREAM, 0, sizeof(TYPE)))
#define wpStreamPeekWithOffset(TYPE, STREAM, OFFSET) \
((TYPE *)streamPeekWithOffset(STREAM, OFFSET, sizeof(TYPE)))
#define wpStreamConsume(TYPE, STREAM) ((TYPE *)streamConsumeCount(STREAM, 1, sizeof(TYPE)))
#define wpStreamConsumeCount(TYPE, STREAM, COUNT) \
((TYPE *)streamConsumeCount(STREAM, COUNT, sizeof(TYPE)))
b8 wpStreamAtEnd(const WpStream *stream);
b8 streamHasCount(const WpStream *stream, u64 count);
void *streamPeekWithOffset(const WpStream *stream, u64 offset, u64 item_size);
void *streamConsumeCount(WpStream *stream, u64 count, u64 item_size);
#ifdef WP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WP_PLATFORM_CPP
#endif // !STREAM_H
+5
View File
@@ -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;
+2 -1
View File
@@ -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);
+7
View File
@@ -6,7 +6,14 @@
#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 "mem/allocator/mem_allocator.c" #include "mem/allocator/mem_allocator.c"
#include "mem/utils/mem_utils.c" #include "mem/utils/mem_utils.c"
#include "strings/str8/str8.c" #include "strings/str8/str8.c"
+7
View File
@@ -5,7 +5,14 @@
#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 "mem/allocator/mem_allocator.h" #include "mem/allocator/mem_allocator.h"
#include "mem/utils/mem_utils.h" #include "mem/utils/mem_utils.h"
#include "strings/str8/str8.h" #include "strings/str8/str8.h"
+10
View File
@@ -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;
+6 -6
View File
@@ -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", \
+9
View File
@@ -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
+34
View File
@@ -3,6 +3,7 @@
#ifndef PLATFORM_H #ifndef PLATFORM_H
#define PLATFORM_H #define PLATFORM_H
// Operating system
#if defined(__ANDROID__) #if defined(__ANDROID__)
#define WP_PLATFORM_ANDROID #define WP_PLATFORM_ANDROID
#define WP_PLATFORM_POSIX #define WP_PLATFORM_POSIX
@@ -60,6 +61,39 @@
#error "Unrecognised platform" #error "Unrecognised platform"
#endif #endif
// Compiler
#if defined(__clang__)
#define WP_PLATFORM_CLANG
#if defined(__GNUG__)
#define WP_PLATFORM_CLANGPP
#endif
#define WP_PLATFORM_CLANG_MAJOR __clang_major__
#define WP_PLATFORM_CLANG_MINOR __clang_minor__
#define WP_PLATFORM_CLANG_PATCH __clang_patchlevel__
#elif defined(__GNUC__) || defined(__GNUG__)
#define WP_PLATFORM_GCC
#if defined(__GNUG__)
#define WP_PLATFORM_GPP
#endif
#define WP_PLATFORM_GCC_MAJOR __GNUC__
#define WP_PLATFORM_GCC_MINOR __GNUC_MINOR__
#if defined(__GNUC_PATCHLEVEL__)
#define WP_PLATFORM_GCC_PATCH __GNUC_PATCHLEVEL__
#endif
#elif defined(_MSC_VER)
#define WP_PLATFORM_MSVC
#define WP_PLATFORM_MSVC_FULL_VERSION _MSC_FULL_VER
#define WP_PLATFORM_MSVC_VERSION _MSC_VER
#else
#error "Unrecognised compiler"
#endif
// Language
#ifdef __cplusplus #ifdef __cplusplus
#define WP_PLATFORM_CPP #define WP_PLATFORM_CPP
#define WP_PLATFORM_CPP_VERSION __cplusplus #define WP_PLATFORM_CPP_VERSION __cplusplus
+12 -12
View File
@@ -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 *,
+10 -2
View File
@@ -6,7 +6,11 @@
#include "../os/file/file.h" #include "../os/file/file.h"
#include "../base/strings/str8/str8.h" #include "../base/strings/str8/str8.h"
typedef enum { #ifdef WP_PLATFORM_CPP
BEGIN_C_LINKAGE
#endif // !WP_PLATFORM_CPP
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,
@@ -17,7 +21,7 @@ typedef enum {
COUNT_LOG_LEVEL, COUNT_LOG_LEVEL,
} WpLogLevel; } WpLogLevel;
typedef struct { typedef struct WpLogger {
WpStr8 name; WpStr8 name;
} WpLogger; } WpLogger;
@@ -31,4 +35,8 @@ void wpLogError(const WpLogger *logger, WpStr8 msg);
void wpLogCritical(const WpLogger *logger, WpStr8 msg); void wpLogCritical(const WpLogger *logger, WpStr8 msg);
void wpLogFatal(const WpLogger *logger, WpStr8 msg); void wpLogFatal(const WpLogger *logger, WpStr8 msg);
#ifdef WP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WP_PLATFORM_CPP
#endif // !LOG_H #endif // !LOG_H
+45 -27
View File
@@ -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 ---
+1 -1
View File
@@ -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;
+16 -16
View File
@@ -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);
+1 -1
View File
@@ -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;
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
+9 -9
View File
@@ -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);
+8 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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);
} }
+1 -1
View File
@@ -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,
+2 -2
View File
@@ -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);
} }
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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)) {
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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);
} }
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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,
+5 -5
View File
@@ -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);
+97
View File
@@ -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
+18
View File
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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"
+30 -72
View File
@@ -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
+7
View File
@@ -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
+2 -2
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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;
+13
View File
@@ -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;
+13
View File
@@ -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;
+1
View File
@@ -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);
+5 -5
View File
@@ -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);
+5 -5
View File
@@ -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);
+335
View File
@@ -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;
}
//-----------------------------------------------------------------------------
+335
View File
@@ -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;
}
//-----------------------------------------------------------------------------
+37
View File
@@ -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_
+185
View File
@@ -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;
}
+185
View File
@@ -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;
}
+22
View File
@@ -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);
+82
View File
@@ -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);
}
+82
View File
@@ -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);
}
+14
View File
@@ -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
+266
View File
@@ -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);
}
+250
View File
@@ -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);
}
+21
View File
@@ -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
+168
View File
@@ -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);
}
+158
View File
@@ -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);
}
+17
View File
@@ -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
+82
View File
@@ -0,0 +1,82 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "test_stream.h"
#include <stdio.h>
#define COUNT 3
WpTestFuncResult test_stream_at_end(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
for (u32 i = 0; i < COUNT; ++i) {
wpStreamConsume(c8, &stream);
result = result && (i == 2 ? wpStreamAtEnd(&stream) : !wpStreamAtEnd(&stream));
}
return wpTesterResult(result);
}
WpTestFuncResult test_stream_peek(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = NULL;
for (u32 i = 0; i <= COUNT; ++i) {
c = wpStreamPeek(c8, &stream);
wpStreamConsume(c8, &stream);
result = result && (i == 3 ? c == NULL : c != NULL);
}
return wpTesterResult(result);
}
WpTestFuncResult test_stream_peek_with_offset(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
u64 offset = 2;
c8 *c = wpStreamPeekWithOffset(c8, &stream, offset);
result = result && *c == characters[offset];
c = wpStreamPeekWithOffset(c8, &stream, 5);
result = result && c == NULL;
return wpTesterResult(result);
}
WpTestFuncResult test_stream_consume(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = NULL;
for (u32 i = 0; i <= COUNT; ++i) {
c = wpStreamConsume(c8, &stream);
result = result && (i == COUNT ? c == NULL : c != NULL);
}
return wpTesterResult(result);
}
WpTestFuncResult test_stream_consume_count(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = wpStreamConsumeCount(c8, &stream, COUNT);
result = result && c != NULL && wpStreamAtEnd(&stream);
c = wpStreamConsumeCount(c8, &stream, COUNT);
result = result && c == NULL;
return wpTesterResult(result);
}
+82
View File
@@ -0,0 +1,82 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "test_stream.h"
#include <stdio.h>
#define COUNT 3
WpTestFuncResult test_stream_at_end(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
for (u32 i = 0; i < COUNT; ++i) {
wpStreamConsume(c8, &stream);
result = result && (i == 2 ? wpStreamAtEnd(&stream) : !wpStreamAtEnd(&stream));
}
return wpTesterResult(result);
}
WpTestFuncResult test_stream_peek(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = NULL;
for (u32 i = 0; i <= COUNT; ++i) {
c = wpStreamPeek(c8, &stream);
wpStreamConsume(c8, &stream);
result = result && (i == 3 ? c == NULL : c != NULL);
}
return wpTesterResult(result);
}
WpTestFuncResult test_stream_peek_with_offset(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
u64 offset = 2;
c8 *c = wpStreamPeekWithOffset(c8, &stream, offset);
result = result && *c == characters[offset];
c = wpStreamPeekWithOffset(c8, &stream, 5);
result = result && c == NULL;
return wpTesterResult(result);
}
WpTestFuncResult test_stream_consume(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = NULL;
for (u32 i = 0; i <= COUNT; ++i) {
c = wpStreamConsume(c8, &stream);
result = result && (i == COUNT ? c == NULL : c != NULL);
}
return wpTesterResult(result);
}
WpTestFuncResult test_stream_consume_count(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = wpStreamConsumeCount(c8, &stream, COUNT);
result = result && c != NULL && wpStreamAtEnd(&stream);
c = wpStreamConsumeCount(c8, &stream, COUNT);
result = result && c == NULL;
return wpTesterResult(result);
}
+14
View File
@@ -0,0 +1,14 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef TEST_STREAM_H
#define TEST_STREAM_H
#include "wapp.h"
WpTestFuncResult test_stream_at_end(void);
WpTestFuncResult test_stream_peek(void);
WpTestFuncResult test_stream_peek_with_offset(void);
WpTestFuncResult test_stream_consume(void);
WpTestFuncResult test_stream_consume_count(void);
#endif // !TEST_STREAM_H
+32
View File
@@ -5,8 +5,12 @@
#include "test_str8_array.h" #include "test_str8_array.h"
#include "test_i32_array.h" #include "test_i32_array.h"
#include "test_queue.h" #include "test_queue.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>
@@ -42,11 +46,17 @@ 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,
test_queue_push_alloc, test_queue_push_alloc,
test_queue_pop, test_queue_pop,
test_stream_at_end,
test_stream_peek,
test_stream_peek_with_offset,
test_stream_consume,
test_stream_consume_count,
test_str8_lit, test_str8_lit,
test_str8_lit_ro, test_str8_lit_ro,
test_str8_buf, test_str8_buf,
@@ -95,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,
+32
View File
@@ -5,8 +5,12 @@
#include "test_str8_array.h" #include "test_str8_array.h"
#include "test_i32_array.h" #include "test_i32_array.h"
#include "test_queue.h" #include "test_queue.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>
@@ -42,11 +46,17 @@ 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,
test_queue_push_alloc, test_queue_push_alloc,
test_queue_pop, test_queue_pop,
test_stream_at_end,
test_stream_peek,
test_stream_peek_with_offset,
test_stream_consume,
test_stream_consume_count,
test_str8_lit, test_str8_lit,
test_str8_lit_ro, test_str8_lit_ro,
test_str8_buf, test_str8_buf,
@@ -95,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,