mirror of
https://github.com/flyinghead/flycast.git
synced 2026-11-07 17:11:09 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f4eefab58 | ||
|
|
7538424efb | ||
|
|
3976fe1be2 | ||
|
|
c57b2e1aa7 | ||
|
|
9cc3d1030d | ||
|
|
48e964235c | ||
|
|
e148fabeae | ||
|
|
d3b8a67cba | ||
|
|
03f2ef6df0 | ||
|
|
57cc7b4a60 | ||
|
|
cdef7f7444 | ||
|
|
30e1a858da | ||
|
|
b04f0eb530 | ||
|
|
ef3d3bd246 | ||
|
|
2ca596ae20 | ||
|
|
25a882341d | ||
|
|
75064f5683 | ||
|
|
93aaf50b4f | ||
|
|
93f463296d | ||
|
|
aff64d43d4 | ||
|
|
240be07bbb | ||
|
|
786ccf4139 | ||
|
|
56c00b0eb5 | ||
|
|
3114394019 | ||
|
|
e5f13b6858 | ||
|
|
3193d2cf5d | ||
|
|
0f18e2e167 | ||
|
|
5908b1a84a | ||
|
|
4d6168dd0b | ||
|
|
2d1c602a69 | ||
|
|
130675aae3 | ||
|
|
75d5cc4d63 | ||
|
|
5a110fd666 | ||
|
|
13436a4dda | ||
|
|
2631706fe2 | ||
|
|
ea6d5f8732 | ||
|
|
305cae496f | ||
|
|
416085980f | ||
|
|
8b35fb80b4 | ||
|
|
5c1249c55f | ||
|
|
fac44e4a2f | ||
|
|
4ea317d51f | ||
|
|
310d5e612e | ||
|
|
62778b1a68 | ||
|
|
604415b0d2 | ||
|
|
49ea1135ee | ||
|
|
46e2d52b75 | ||
|
|
44f77408e4 | ||
|
|
2860aa96f4 | ||
|
|
8b0a5fa480 | ||
|
|
b150ba2b62 | ||
|
|
48bce25820 | ||
|
|
562f78cd71 | ||
|
|
9e0573aa98 | ||
|
|
d23b3b6bc7 | ||
|
|
1d9f8ab438 | ||
|
|
df3c075fba | ||
|
|
9cdd0aab9f | ||
|
|
e4d9220f3f | ||
|
|
0bf9c64b1b | ||
|
|
4e74619d9e | ||
|
|
0414a90500 | ||
|
|
5866e97d18 | ||
|
|
387e2427b4 | ||
|
|
5187258f4b | ||
|
|
e1da1c3a55 | ||
|
|
84356e3b26 | ||
|
|
c7499df3a8 | ||
|
|
03f7a0f605 | ||
|
|
f3c838d19d | ||
|
|
d6f3ca986d | ||
|
|
b9df7d3469 | ||
|
|
bf1d4a56ae | ||
|
|
a682e20bbd | ||
|
|
5b9dd96064 | ||
|
|
a99a72589b | ||
|
|
77ed9c20de | ||
|
|
7cb0fe53d7 | ||
|
|
3db0fce9b6 | ||
|
|
6a15e7a3aa | ||
|
|
431d71de5e | ||
|
|
914fa29d31 | ||
|
|
c143cae09b | ||
|
|
a35e8214df | ||
|
|
d84108de32 | ||
|
|
1513c6cab8 | ||
|
|
34104724a6 | ||
|
|
b70c2791b2 | ||
|
|
ccdd53ee0e | ||
|
|
57a3e4ca53 | ||
|
|
b92ac1544e | ||
|
|
26d386f833 | ||
|
|
ce0060126e | ||
|
|
4389a3ffa6 | ||
|
|
b3fa453d75 | ||
|
|
32c274f407 | ||
|
|
cb2d3e3776 | ||
|
|
28f5dd983e | ||
|
|
160828a4c7 | ||
|
|
aee932808e | ||
|
|
77636391fc | ||
|
|
944af44c7f | ||
|
|
5c27648699 | ||
|
|
7ef35eaf68 | ||
|
|
bb733323ce | ||
|
|
1b6bf25e7a | ||
|
|
aa65b81f89 | ||
|
|
da9f030a0e | ||
|
|
a0e1eb0005 | ||
|
|
5cc15429cd | ||
|
|
18656f5986 | ||
|
|
536be34853 | ||
|
|
5b513cac5b | ||
|
|
5efdf58e85 | ||
|
|
a93f3697d6 | ||
|
|
b98e833c57 | ||
|
|
2e89848041 | ||
|
|
bb4ba3ed89 | ||
|
|
a5a338d408 | ||
|
|
3114344414 | ||
|
|
20ba79668f | ||
|
|
7a4f9d8667 | ||
|
|
22bff1b017 | ||
|
|
9344856c7e | ||
|
|
b2c1d134e1 | ||
|
|
160d3e7ef3 | ||
|
|
3cf4808033 | ||
|
|
1bd894f941 | ||
|
|
8dc55721d0 | ||
|
|
c94deaee9d | ||
|
|
95583583ca | ||
|
|
42752acef5 | ||
|
|
45c700ab60 | ||
|
|
a3902fc278 | ||
|
|
0606f3e63e | ||
|
|
0558c957e8 | ||
|
|
2ca9187137 | ||
|
|
5add29cbed | ||
|
|
5a1c3f80f5 | ||
|
|
a0e8e9a9df | ||
|
|
45f4378184 | ||
|
|
c7d030c2e6 | ||
|
|
2bee6b1ce4 | ||
|
|
522505273e | ||
|
|
0481f5464d | ||
|
|
7478476f9c | ||
|
|
76c3695f6e | ||
|
|
e18ada7225 | ||
|
|
f3a33642f8 | ||
|
|
2f03c1b147 | ||
|
|
b7e2f5e489 | ||
|
|
d01cbde41c | ||
|
|
11068012fe | ||
|
|
a06791780d | ||
|
|
ee1a7167f6 | ||
|
|
10aaec1619 | ||
|
|
32d8d9a8c3 | ||
|
|
553f77c675 | ||
|
|
9402981b43 | ||
|
|
9038ef6d8a | ||
|
|
1d290560e0 | ||
|
|
59e844db15 | ||
|
|
6853238c8b | ||
|
|
f0aa1abf89 | ||
|
|
cfd3677746 | ||
|
|
50a10598e4 | ||
|
|
9bfd48cf40 | ||
|
|
b72750c7d5 | ||
|
|
b9fdd5070b | ||
|
|
6c3d77b012 | ||
|
|
7fee0d2d29 | ||
|
|
dfd4dbebc4 | ||
|
|
34a5e7f47d | ||
|
|
3f8d645c42 | ||
|
|
ecd0305a60 | ||
|
|
667e3906d8 | ||
|
|
e5b1d56a7c | ||
|
|
d789b57412 | ||
|
|
825778445a | ||
|
|
20517cf0da | ||
|
|
989d3b1370 | ||
|
|
421245aeba | ||
|
|
686f08e7dd | ||
|
|
4af1d096de | ||
|
|
27a0497dd5 | ||
|
|
9ea0563a7a | ||
|
|
a46677e64e | ||
|
|
a7f2008763 | ||
|
|
53e0f12c22 | ||
|
|
34961daaec | ||
|
|
f5389bcd0b | ||
|
|
67eee05c14 | ||
|
|
bb1b1059d4 | ||
|
|
94f35ca54f | ||
|
|
1507097bcd | ||
|
|
e4599e36ed | ||
|
|
15617c1816 | ||
|
|
fb64fc418e | ||
|
|
5656370388 | ||
|
|
354d649ebd | ||
|
|
fff03f64a3 | ||
|
|
a99aa5217b | ||
|
|
89abb7925b | ||
|
|
dea8e74182 | ||
|
|
92c5892d4c | ||
|
|
21f9e9fbc2 | ||
|
|
78fa3ee09e | ||
|
|
de1584d97c | ||
|
|
a40c51e682 | ||
|
|
c860807fef | ||
|
|
b91f82c7e5 | ||
|
|
d38ce47081 | ||
|
|
5f55a9fd3f | ||
|
|
a085fd2f6d | ||
|
|
36c2f5137c | ||
|
|
5e9c168fc9 | ||
|
|
59c2343cad | ||
|
|
b42387e929 | ||
|
|
df78a781ec | ||
|
|
974dc2e233 | ||
|
|
6bf38e5085 | ||
|
|
792aa38d34 | ||
|
|
516982c66c | ||
|
|
a9fa33c17a | ||
|
|
d0584b8652 | ||
|
|
58c8a33d11 | ||
|
|
b4dcc64ef6 | ||
|
|
7531f5df20 | ||
|
|
c4d77165a6 | ||
|
|
aa95c71ead | ||
|
|
6612e3fef8 | ||
|
|
fbd52a72d4 | ||
|
|
d618abc320 | ||
|
|
b7163dda83 | ||
|
|
d259a2e2f5 | ||
|
|
e2f8de33e8 | ||
|
|
42ad5532b2 | ||
|
|
1e30f483c2 | ||
|
|
bdd2d5af7f | ||
|
|
76638df001 | ||
|
|
3efb87ba6d | ||
|
|
c9f238362d | ||
|
|
129673a84b | ||
|
|
7c1c5817d3 | ||
|
|
e394840344 | ||
|
|
fc33002284 | ||
|
|
dff967f60a | ||
|
|
a3708a7e95 | ||
|
|
1cadeb276e | ||
|
|
2b28e819e5 | ||
|
|
db846ca933 | ||
|
|
9cb7d9e5d5 | ||
|
|
93ae9d0375 | ||
|
|
e03e11b8a9 | ||
|
|
52df0133f0 | ||
|
|
d5aeb482d9 | ||
|
|
7eec648690 | ||
|
|
897e06b887 | ||
|
|
aa38771cd0 | ||
|
|
c77ddba109 | ||
|
|
cd8a88366d | ||
|
|
f892630e4b | ||
|
|
9d4d486524 | ||
|
|
d8a3ee9c3a | ||
|
|
fc6142b332 | ||
|
|
5fc84acdfb | ||
|
|
037dc3b4b9 | ||
|
|
96aac66133 | ||
|
|
4d5ced1ce6 | ||
|
|
da3cfd9d58 | ||
|
|
65aadb9dcb | ||
|
|
cec46990ea | ||
|
|
2e5309bfa3 | ||
|
|
742090bb1f | ||
|
|
f3a64e5891 | ||
|
|
32ccb754ff | ||
|
|
32d11dd89c | ||
|
|
760813e45a | ||
|
|
e221f6fed2 |
No files matched your search
@@ -4,6 +4,7 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Android
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -69,20 +70,16 @@ jobs:
|
||||
mv libflycast.so.sym symbols/libflycast.so/$BUILD_ID
|
||||
done
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
- name: Setup Rclone
|
||||
uses: AnimMouse/setup-rclone@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
rclone_config: ${{ secrets.RCLONE_CONFIG }}
|
||||
|
||||
- name: Upload to S3
|
||||
run: |
|
||||
cp shell/android-studio/flycast/build/outputs/bundle/release/*.aab shell/android-studio/flycast/build/outputs/apk/release/
|
||||
aws s3 sync shell/android-studio/flycast/build/outputs/apk/release s3://flycast-builds/android/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --exclude='*.json' --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
rclone copy shell/android-studio/flycast/build/outputs/apk/release scaleway:flycast-builds/android/${GITHUB_REF#refs/}-$GITHUB_SHA --exclude '*.json'
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
|
||||
- name: Setup Sentry CLI
|
||||
uses: mathieu-bour/setup-sentry-cli@v2
|
||||
|
||||
@@ -13,14 +13,14 @@ jobs:
|
||||
architecture: [ arm64, x86-64 ]
|
||||
include:
|
||||
- operating_system: freebsd
|
||||
version: '14.1'
|
||||
pkginstall: sudo pkg install -y alsa-lib ccache cmake evdev-proto git libao libevdev libudev-devd libzip lua54 miniupnpc ninja pkgconf pulseaudio sdl2
|
||||
version: '14.2'
|
||||
pkginstall: sudo pkg install -y alsa-lib ccache cmake evdev-proto git libao libevdev libudev-devd libzip lua54 miniupnpc ninja pkgconf pulseaudio sdl2 libcdio
|
||||
- operating_system: netbsd
|
||||
version: '10.0'
|
||||
pkginstall: sudo pkgin update && sudo pkgin -y install alsa-lib ccache cmake gcc12 git libao libzip lua54 miniupnpc ninja-build pkgconf pulseaudio SDL2 && export PATH=/usr/pkg/gcc12/bin:$PATH
|
||||
version: '10.1'
|
||||
pkginstall: sudo pkgin update && sudo pkgin -y install alsa-lib ccache cmake gcc12 git libao libzip lua54 miniupnpc ninja-build pkgconf pulseaudio SDL2 libcdio && export PATH=/usr/pkg/gcc12/bin:$PATH
|
||||
- operating_system: openbsd
|
||||
version: '7.5'
|
||||
pkginstall: sudo pkg_add ccache cmake git libao libzip miniupnpc ninja pkgconf pulseaudio sdl2
|
||||
version: '7.6'
|
||||
pkginstall: sudo pkg_add ccache cmake git libao libzip miniupnpc ninja pkgconf pulseaudio sdl2 libcdio
|
||||
exclude:
|
||||
- architecture: arm64
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
key: ccache-${{ matrix.operating_system }}-${{ matrix.architecture }}-${{ github.sha }}
|
||||
restore-keys: ccache-${{ matrix.operating_system }}-${{ matrix.architecture }}-
|
||||
|
||||
- uses: cross-platform-actions/[email protected]5.0
|
||||
- uses: cross-platform-actions/[email protected]7.0
|
||||
with:
|
||||
operating_system: ${{ matrix.operating_system }}
|
||||
architecture: ${{ matrix.architecture }}
|
||||
@@ -44,5 +44,5 @@ jobs:
|
||||
environment_variables: CCACHE_DIR
|
||||
run: |
|
||||
${{ matrix.pkginstall }}
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -G Ninja
|
||||
cmake -B build -DUSE_LIBCDIO=ON -DCMAKE_BUILD_TYPE=Release -G Ninja
|
||||
cmake --build build --config Release
|
||||
+16
-18
@@ -20,11 +20,11 @@ jobs:
|
||||
- {name: i686-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DUSE_DISCORD=ON, destDir: osx, buildType: RelWithDebInfo}
|
||||
- {name: apple-ios, os: macos-latest, shell: sh, cmakeArgs: -DCMAKE_SYSTEM_NAME=iOS -G Xcode, destDir: ios, buildType: Release}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-20.04, shell: sh, cmakeArgs: -G Ninja -DUSE_DISCORD=ON, destDir: linux, buildType: RelWithDebInfo}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-22.04, shell: sh, cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: linux, buildType: RelWithDebInfo}
|
||||
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja -DUSE_DISCORD=ON, buildType: Release}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja -DUSE_DISCORD=ON, destDir: win, buildType: RelWithDebInfo}
|
||||
- {name: libretro-x86_64-pc-linux-gnu, os: ubuntu-latest, shell: sh, cmakeArgs: -DLIBRETRO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -G Ninja, buildType: Release}
|
||||
- {name: libretro-x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -DLIBRETRO=ON -G Ninja, buildType: Release}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: win, buildType: RelWithDebInfo}
|
||||
- {name: libretro-x86_64-pc-linux-gnu, os: ubuntu-22.04, shell: sh, cmakeArgs: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -G Ninja, buildType: Release}
|
||||
- {name: libretro-x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -G Ninja, buildType: Release}
|
||||
|
||||
steps:
|
||||
- name: Set up build environment (macOS)
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
# Unlink and re-link to prevent errors when github mac runner images install python outside of brew. See https://github.com/actions/setup-python/issues/577
|
||||
brew list -1 | grep python | while read formula; do brew unlink $formula; brew link --overwrite $formula; done
|
||||
brew update || :
|
||||
brew install libao ldid ninja pulseaudio
|
||||
brew install libao ldid pulseaudio
|
||||
brew uninstall --ignore-dependencies zstd
|
||||
VULKAN_VER=1.3.261.1 && aria2c https://sdk.lunarg.com/sdk/download/$VULKAN_VER/mac/vulkansdk-macos-$VULKAN_VER.dmg
|
||||
hdiutil attach ./vulkansdk-macos-*.dmg -mountpoint /Volumes/VulkanSDK
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
run: |
|
||||
sudo add-apt-repository ppa:christianrauch/libdecoration
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ccache libao-dev libasound2-dev libevdev-dev libgl1-mesa-dev liblua5.3-dev libminiupnpc-dev libpulse-dev libsdl2-dev libudev-dev libzip-dev ninja-build libcurl4-openssl-dev
|
||||
sudo apt-get -y install ccache libao-dev libasound2-dev libevdev-dev libgl1-mesa-dev liblua5.3-dev libminiupnpc-dev libpulse-dev libsdl2-dev libudev-dev libzip-dev ninja-build libcurl4-openssl-dev libcdio-dev libfuse2
|
||||
sudo apt-get -y install libwayland-dev libdecor-0-dev libaudio-dev libjack-dev libsndio-dev libsamplerate0-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxkbcommon-dev libdrm-dev libgbm-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
install: git make mingw-w64-x86_64-ccache mingw-w64-x86_64-cmake mingw-w64-x86_64-lua mingw-w64-x86_64-ninja mingw-w64-x86_64-SDL2 mingw-w64-x86_64-toolchain
|
||||
install: git make mingw-w64-x86_64-ccache mingw-w64-x86_64-cmake mingw-w64-x86_64-lua mingw-w64-x86_64-ninja mingw-w64-x86_64-SDL2 mingw-w64-x86_64-toolchain mingw-w64-x86_64-libcdio
|
||||
if: matrix.config.shell == 'msys2 {0}'
|
||||
|
||||
- name: Set up build environment (Windows, Visual Studio)
|
||||
@@ -129,7 +129,9 @@ jobs:
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: flycast-${{ matrix.config.name }}
|
||||
path: artifact/bin
|
||||
path: |
|
||||
artifact/bin
|
||||
artifact/lib/libretro
|
||||
|
||||
- name: Package app (macos)
|
||||
run: |
|
||||
@@ -143,19 +145,15 @@ jobs:
|
||||
rm artifact/bin/flycast.exe
|
||||
if: matrix.config.name == 'x86_64-w64-mingw32'
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
- name: Setup Rclone
|
||||
uses: AnimMouse/setup-rclone@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
rclone_config: ${{ secrets.RCLONE_CONFIG }}
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync artifact/bin s3://flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
run: rclone copy artifact/bin scaleway:flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
|
||||
- name: Setup Sentry CLI
|
||||
uses: mathieu-bour/setup-sentry-cli@v2
|
||||
@@ -179,4 +177,4 @@ jobs:
|
||||
env:
|
||||
SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }}
|
||||
if: ${{ env.SENTRY_TOKEN != '' && (matrix.config.name == 'x86_64-w64-mingw32' || matrix.config.name == 'apple-darwin' || matrix.config.name == 'x86_64-pc-linux-gnu') }}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
name: Switch ${{ matrix.config.name }}
|
||||
runs-on: ubuntu-latest
|
||||
container: devkitpro/devkita64:latest
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
- name: Set up build environment
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install awscli ccache
|
||||
sudo apt-get -y install ccache
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -48,15 +48,12 @@ jobs:
|
||||
run: zip -m artifact/bin/flycast.nro.zip artifact/bin/flycast.nro
|
||||
if: hashFiles('artifact/bin/flycast.nro') != ''
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
- name: Setup Rclone
|
||||
uses: AnimMouse/setup-rclone@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
rclone_config: ${{ secrets.RCLONE_CONFIG }}
|
||||
version: v1.69.1
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync artifact/bin s3://flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
run: rclone copy artifact/bin scaleway:flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
@@ -4,6 +4,7 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: UWP
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
@@ -39,16 +40,12 @@ jobs:
|
||||
name: flycast-uwp
|
||||
path: build/artifact
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
- name: Setup Rclone
|
||||
uses: AnimMouse/setup-rclone@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
rclone_config: ${{ secrets.RCLONE_CONFIG }}
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync build/artifact s3://flycast-builds/xbox/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
run: rclone copy build/artifact scaleway:flycast-builds/xbox/${GITHUB_REF#refs/}-$GITHUB_SHA
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
@@ -17,3 +17,6 @@ cmake-build-*/
|
||||
# Dependencies from .gitmodules
|
||||
core/deps/breakpad/
|
||||
core/deps/glslang/
|
||||
.cache/
|
||||
compile_commands.json
|
||||
CMakeUserPresets.json
|
||||
+5
-3
@@ -9,12 +9,12 @@
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CORENAME: flycast
|
||||
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_BUILD_TYPE=Release
|
||||
CORE_ARGS: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
.core-defs-linux:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release
|
||||
CORE_ARGS: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
.core-defs-osx-x64:
|
||||
extends: .core-defs
|
||||
@@ -36,7 +36,7 @@
|
||||
.core-defs-android:
|
||||
extends: .core-defs
|
||||
script:
|
||||
- cmake $CORE_ARGS -DANDROID_PLATFORM=android-$API_LEVEL -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_static -DANDROID_ABI=$ANDROID_ABI -DANDROID_ARM_MODE=arm "$CMAKE_SOURCE_ROOT" -B$BUILD_DIR
|
||||
- cmake -DLIBRETRO=ON -DCMAKE_BUILD_TYPE=Release -DANDROID_PLATFORM=android-$API_LEVEL -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_static -DANDROID_ABI=$ANDROID_ABI -DANDROID_ARM_MODE=arm "$CMAKE_SOURCE_ROOT" -B$BUILD_DIR
|
||||
- cmake --build $BUILD_DIR --target ${CORENAME}_libretro --config Release -- -j $NUMPROC
|
||||
- mv $BUILD_DIR/${CORENAME}_libretro.so $LIBNAME
|
||||
- if [ $STRIP_CORE_LIB -eq 1 ]; then $NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip $LIBNAME; fi
|
||||
@@ -120,6 +120,8 @@ libretro-build-osx-x64:
|
||||
extends:
|
||||
- .libretro-osx-cmake-x86
|
||||
- .core-defs-osx-x64
|
||||
tags:
|
||||
- mac-apple-silicon
|
||||
|
||||
# MacOS arm 64-bit
|
||||
libretro-build-osx-arm64:
|
||||
|
||||
+4
-1
@@ -3,7 +3,7 @@
|
||||
url = https://github.com/libsdl-org/SDL.git
|
||||
[submodule "core/deps/libchdr"]
|
||||
path = core/deps/libchdr
|
||||
url = https://github.com/rtissera/libchdr.git
|
||||
url = https://github.com/flyinghead/libchdr.git
|
||||
ignore = dirty
|
||||
[submodule "core/deps/luabridge"]
|
||||
path = core/deps/luabridge
|
||||
@@ -41,3 +41,6 @@
|
||||
[submodule "core/deps/googletest"]
|
||||
path = core/deps/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
[submodule "core/deps/asio"]
|
||||
path = core/deps/asio
|
||||
url = https://github.com/flyinghead/asio.git
|
||||
+142
-47
@@ -21,6 +21,7 @@ if(APPLE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum macOS deployment version")
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "")
|
||||
endif()
|
||||
set(ZLIB_LIBRARY "-lz" CACHE STRING "Use generic linker flag for Xcode to support multiple SDKs")
|
||||
endif()
|
||||
|
||||
if(LIBRETRO)
|
||||
@@ -58,6 +59,7 @@ option(USE_GLES2 "Use GLES2 API" OFF)
|
||||
option(USE_HOST_GLSLANG "Use host glslang" OFF)
|
||||
option(USE_HOST_LIBZIP "Use host libzip" ON)
|
||||
option(USE_HOST_SDL "Use host SDL library" ${USE_HOST_SDL_DEFAULT})
|
||||
option(USE_HOST_LIBCHDR "Use host libchdr" OFF)
|
||||
option(USE_OPENMP "Use OpenMP if available" ON)
|
||||
option(USE_VULKAN "Build with Vulkan support" ON)
|
||||
option(USE_DX9 "Build with Direct3D 9 support" ON)
|
||||
@@ -65,11 +67,17 @@ option(USE_DX11 "Build with Direct3D 11 support" ON)
|
||||
option(LIBRETRO "Build libretro core" OFF)
|
||||
option(USE_OPENGL "Use OpenGL API" ON)
|
||||
option(USE_VIDEOCORE "RPI: use the legacy Broadcom GLES libraries" OFF)
|
||||
option(USE_ALSA "Build with ALSA support" ON)
|
||||
option(USE_LIBAO "Build with AO support" ON)
|
||||
option(USE_OSS "Build with OSS support" OFF)
|
||||
option(USE_PULSEAUDIO "Build with PulseAudio support" ON)
|
||||
option(USE_BREAKPAD "Build and link with breakpad library" ON)
|
||||
option(USE_LUA "Build with Lua support" ON)
|
||||
option(ENABLE_GDB_SERVER "Build with GDB debugging support" OFF)
|
||||
option(ENABLE_DC_PROFILER "Build with support for target machine (SH4) profiler" OFF)
|
||||
option(ENABLE_FC_PROFILER "Build with support for host app (Flycast) profiler" OFF)
|
||||
option(USE_DISCORD "Use Discord Presence API" OFF)
|
||||
option(USE_LIBCDIO "Use libcdio for CDROM access" OFF)
|
||||
|
||||
if(IOS AND NOT LIBRETRO)
|
||||
set(USE_VULKAN OFF CACHE BOOL "Force vulkan off" FORCE)
|
||||
@@ -139,6 +147,13 @@ if(NINTENDO_SWITCH)
|
||||
if(USE_GLES)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE GLES)
|
||||
endif()
|
||||
# asio
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE
|
||||
ASIO_DISABLE_LOCAL_SOCKETS
|
||||
ASIO_DISABLE_SERIAL_PORT
|
||||
ESHUTDOWN=110
|
||||
SA_RESTART=0
|
||||
SA_NOCLDWAIT=0)
|
||||
|
||||
elseif(LIBRETRO)
|
||||
add_library(${PROJECT_NAME} SHARED core/emulator.cpp)
|
||||
@@ -212,6 +227,10 @@ else()
|
||||
add_executable(${PROJECT_NAME} core/emulator.cpp)
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
CMAKE_CXX_STANDARD 20
|
||||
CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(WINDOWS_STORE)
|
||||
set(USE_OPENGL OFF)
|
||||
set(USE_VULKAN OFF)
|
||||
@@ -229,7 +248,7 @@ else()
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-Wall>)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_OSX_SYSROOT} MATCHES "\/MacOSX.platform\/Developer\/SDKs")
|
||||
if(APPLE AND NOT IOS)
|
||||
set(TARGET_MAC ON)
|
||||
endif()
|
||||
|
||||
@@ -247,6 +266,7 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE
|
||||
$<$<BOOL:${MSVC}>:NOMINMAX>
|
||||
$<$<BOOL:${TEST_AUTOMATION}>:TEST_AUTOMATION>
|
||||
$<$<BOOL:${WINDOWS_STORE}>:NOCRYPT>
|
||||
$<$<BOOL:${WINDOWS_STORE}>:_WIN32_WINNT=0x0A00>
|
||||
$<$<OR:$<BOOL:${MINGW}>,$<BOOL:${MSVC}>>:_USE_MATH_DEFINES>)
|
||||
|
||||
if(UNIX AND NOT ANDROID AND NOT APPLE)
|
||||
@@ -258,7 +278,7 @@ if(NOT "${SENTRY_UPLOAD_URL}" STREQUAL "")
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE SENTRY_UPLOAD="${SENTRY_UPLOAD_URL}")
|
||||
endif()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core core/deps core/deps/stb core/deps/json)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core core/deps core/deps/stb core/deps/json core/deps/asio/asio/include)
|
||||
if(LIBRETRO)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE shell/libretro)
|
||||
endif()
|
||||
@@ -356,7 +376,8 @@ if(USE_OPENMP)
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
if(MINGW)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE "-static -lgomp -lpthread")
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE -lpthread)
|
||||
target_link_options(${PROJECT_NAME} PRIVATE -fopenmp -static)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -fopenmp)
|
||||
elseif(ANDROID)
|
||||
# Reference: https://android.googlesource.com/platform/ndk/+/refs/heads/master/tests/device/openmp/CMakeLists.txt
|
||||
@@ -411,11 +432,17 @@ if(USE_VULKAN)
|
||||
endif()
|
||||
|
||||
if(NOT LIBRETRO)
|
||||
find_package(ALSA)
|
||||
if(ALSA_FOUND AND NOT ANDROID)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_ALSA)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${ALSA_INCLUDE_DIRS})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${ALSA_LIBRARIES})
|
||||
if(USE_OSS)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_OSS)
|
||||
endif()
|
||||
|
||||
if(USE_ALSA)
|
||||
find_package(ALSA)
|
||||
if(ALSA_FOUND AND NOT ANDROID)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_ALSA)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${ALSA_INCLUDE_DIRS})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${ALSA_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
@@ -448,7 +475,18 @@ if(NOT LIBRETRO)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_SDL USE_SDL_AUDIO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/sdl/sdl.cpp core/sdl/sdl.h core/sdl/sdl_gamepad.h core/sdl/sdl_keyboard.h)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/sdl/sdl.cpp
|
||||
core/sdl/sdl.h
|
||||
core/sdl/sdl_gamepad.h
|
||||
core/sdl/sdl_keyboard.h
|
||||
core/sdl/sdl_keyboard_mac.h
|
||||
core/sdl/dreamlink.cpp
|
||||
core/sdl/dreamlink.h
|
||||
core/sdl/dreampicoport.cpp
|
||||
core/sdl/dreampicoport.h
|
||||
core/sdl/dreamconn.cpp
|
||||
core/sdl/dreamconn.h)
|
||||
|
||||
if((UNIX AND NOT APPLE) OR NINTENDO_SWITCH)
|
||||
find_package(CURL REQUIRED)
|
||||
@@ -462,37 +500,52 @@ if(NOT LIBRETRO)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ZLIB::ZLIB)
|
||||
endif()
|
||||
|
||||
find_package(Lua 5.2)
|
||||
if(NOT APPLE AND LUA_FOUND)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_LUA)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${LUA_INCLUDE_DIR} core/deps/luabridge/Source)
|
||||
list(TRANSFORM LUA_LIBRARIES REPLACE "\.dll" "")
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${LUA_LIBRARIES})
|
||||
if(USE_LUA)
|
||||
find_package(Lua 5.2)
|
||||
if(NOT APPLE AND LUA_FOUND)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_LUA)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${LUA_INCLUDE_DIR} core/deps/luabridge/Source)
|
||||
list(TRANSFORM LUA_LIBRARIES REPLACE "\.dll" "")
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${LUA_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(core/deps/libchdr EXCLUDE_FROM_ALL)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE chdr-static)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/libchdr/include)
|
||||
find_package(PkgConfig)
|
||||
|
||||
if(NOT WITH_SYSTEM_ZLIB)
|
||||
set(ZLIB_RELATIVE_PATH "core/deps/libchdr/deps/zlib-1.3.1")
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/${ZLIB_RELATIVE_PATH}" "${CMAKE_CURRENT_BINARY_DIR}/${ZLIB_RELATIVE_PATH}")
|
||||
option(ZLIB_BUILD_EXAMPLES "Enable Zlib Examples" OFF)
|
||||
add_subdirectory("core/deps/libchdr/deps/zlib-1.3.1" EXCLUDE_FROM_ALL)
|
||||
set_target_properties(zlibstatic PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE zlibstatic)
|
||||
# help libzip find the package
|
||||
set(ZLIB_FOUND TRUE)
|
||||
set(ZLIB_RELATIVE_PATH "core/deps/libchdr/deps/zlib-1.3.1")
|
||||
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${ZLIB_RELATIVE_PATH}" "${CMAKE_CURRENT_BINARY_DIR}/${ZLIB_RELATIVE_PATH}")
|
||||
|
||||
cmake_policy(SET CMP0026 OLD)
|
||||
get_target_property(ZLIB_LIBRARY_RELEASE zlibstatic LOCATION)
|
||||
get_target_property(ZLIB_LIBRARY_DEBUG zlibstatic LOCATION_Debug)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig)
|
||||
if(PKG_CONFIG_FOUND AND USE_HOST_LIBCHDR)
|
||||
pkg_check_modules(LIBCHDR IMPORTED_TARGET libchdr)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::LIBCHDR)
|
||||
else()
|
||||
option(ZSTD_BUILD_SHARED "BUILD SHARED LIBRARIES" OFF)
|
||||
option(ZSTD_BUILD_PROGRAMS "BUILD PROGRAMS" OFF)
|
||||
option(ZSTD_LEGACY_SUPPORT "LEGACY SUPPORT" OFF)
|
||||
add_subdirectory(core/deps/libchdr/deps/zstd-1.5.6/build/cmake EXCLUDE_FROM_ALL)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE libzstd_static)
|
||||
|
||||
option(WITH_SYSTEM_ZSTD "Use system provided zstd library" ON)
|
||||
add_subdirectory(core/deps/libchdr EXCLUDE_FROM_ALL)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE chdr-static)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/libchdr/include)
|
||||
endif()
|
||||
|
||||
if(PKG_CONFIG_FOUND AND NOT ANDROID AND NOT APPLE AND NOT LIBRETRO)
|
||||
pkg_check_modules(AO IMPORTED_TARGET ao)
|
||||
if(AO_FOUND)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_LIBAO)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::AO)
|
||||
if(USE_LIBAO)
|
||||
pkg_check_modules(AO IMPORTED_TARGET ao)
|
||||
if(AO_FOUND)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_LIBAO)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::AO)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT SDL2_FOUND)
|
||||
@@ -509,10 +562,12 @@ if(PKG_CONFIG_FOUND AND NOT ANDROID AND NOT APPLE AND NOT LIBRETRO)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
pkg_check_modules(LIBPULSE IMPORTED_TARGET libpulse)
|
||||
if(LIBPULSE_FOUND)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_PULSEAUDIO)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::LIBPULSE)
|
||||
if(USE_PULSEAUDIO)
|
||||
pkg_check_modules(LIBPULSE IMPORTED_TARGET libpulse)
|
||||
if(LIBPULSE_FOUND)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_PULSEAUDIO)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::LIBPULSE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_HOST_LIBZIP)
|
||||
@@ -627,10 +682,6 @@ if(NOT MINIUPNP_FOUND)
|
||||
endif()
|
||||
|
||||
if(NOT LIBZIP_FOUND OR NINTENDO_SWITCH)
|
||||
cmake_policy(SET CMP0026 OLD)
|
||||
set(zstd_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/core/deps/libchdr/deps/zstd-1.5.6/lib")
|
||||
get_target_property(zstd_STATIC_LIBRARY libzstd_static LOCATION)
|
||||
|
||||
option(ENABLE_COMMONCRYPTO "Enable use of CommonCrypto" OFF)
|
||||
option(ENABLE_GNUTLS "Enable use of GnuTLS" OFF)
|
||||
option(ENABLE_MBEDTLS "Enable use of mbed TLS" OFF)
|
||||
@@ -649,6 +700,28 @@ if(NOT LIBZIP_FOUND OR NINTENDO_SWITCH)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE libzip::zip)
|
||||
endif()
|
||||
|
||||
if(USE_LIBCDIO)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(CDIO IMPORTED_TARGET libcdio)
|
||||
if(CDIO_FOUND)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_LIBCDIO)
|
||||
if(MINGW)
|
||||
# Force static link
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE "-l:libcdio.a -l:libiconv.a -lwinmm")
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::CDIO)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if(NOT CDIO_FOUND)
|
||||
find_package(libcdio)
|
||||
if(TARGET libcdio::libcdio)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_LIBCDIO)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE libcdio::libcdio)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/dirent)
|
||||
endif()
|
||||
@@ -791,6 +864,9 @@ if(LIBRETRO)
|
||||
if(APPLE)
|
||||
target_sources(${PROJECT_NAME} PRIVATE shell/libretro/oslib_apple.mm)
|
||||
endif()
|
||||
if(WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE mswsock)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
@@ -1029,22 +1105,23 @@ if(NOT LIBRETRO)
|
||||
fonts/Roboto-Medium.ttf.zip
|
||||
fonts/Roboto-Regular.ttf.zip
|
||||
fonts/fa-solid-900.ttf.zip)
|
||||
if(ANDROID)
|
||||
if(ANDROID OR IOS)
|
||||
cmrc_add_resources(flycast-resources
|
||||
WHENCE resources
|
||||
resources/picture/buttons.png)
|
||||
resources/picture/buttons.png
|
||||
resources/picture/buttons-arcade.png)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/imgread/cdi.cpp
|
||||
core/imgread/cdio.cpp
|
||||
core/imgread/chd.cpp
|
||||
core/imgread/common.cpp
|
||||
core/imgread/common.h
|
||||
core/imgread/cue.cpp
|
||||
core/imgread/gdi.cpp
|
||||
core/imgread/ImgReader.cpp
|
||||
core/imgread/ioctl.cpp
|
||||
core/imgread/iso9660.h
|
||||
core/imgread/isofs.cpp
|
||||
core/imgread/isofs.h)
|
||||
@@ -1125,7 +1202,11 @@ target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/network/output.cpp
|
||||
core/network/output.h
|
||||
core/network/picoppp.cpp
|
||||
core/network/picoppp.h)
|
||||
core/network/picoppp.h
|
||||
core/network/netservice.cpp
|
||||
core/network/netservice.h
|
||||
core/network/dcnet.cpp
|
||||
core/network/dcnet.h)
|
||||
|
||||
if(ANDROID)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
@@ -1301,6 +1382,8 @@ target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/rend/tileclip.h
|
||||
core/rend/TexCache.cpp
|
||||
core/rend/TexCache.h
|
||||
core/rend/texconv.cpp
|
||||
core/rend/texconv.h
|
||||
core/rend/norend/norend.cpp)
|
||||
if(NOT LIBRETRO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
@@ -1310,8 +1393,8 @@ if(NOT LIBRETRO)
|
||||
core/ui/gui.cpp
|
||||
core/ui/gui.h
|
||||
core/ui/gui_achievements.cpp
|
||||
core/ui/gui_android.cpp
|
||||
core/ui/gui_android.h
|
||||
core/ui/vgamepad.cpp
|
||||
core/ui/vgamepad.h
|
||||
core/ui/gui_chat.h
|
||||
core/ui/gui_cheats.cpp
|
||||
core/ui/gui_util.cpp
|
||||
@@ -1617,6 +1700,10 @@ if(NOT LIBRETRO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
shell/android-studio/flycast/src/main/jni/src/Android.cpp
|
||||
shell/android-studio/flycast/src/main/jni/src/android_gamepad.h
|
||||
shell/android-studio/flycast/src/main/jni/src/android_storage.h
|
||||
shell/android-studio/flycast/src/main/jni/src/http_client.h
|
||||
shell/android-studio/flycast/src/main/jni/src/jni_util.h
|
||||
shell/android-studio/flycast/src/main/jni/src/android_input.cpp
|
||||
shell/android-studio/flycast/src/main/jni/src/android_keyboard.h)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE android log)
|
||||
@@ -1641,6 +1728,8 @@ if(NOT LIBRETRO)
|
||||
shell/apple/emulator-ios/emulator/FlycastViewController.mm
|
||||
shell/apple/emulator-ios/emulator/PadViewController.h
|
||||
shell/apple/emulator-ios/emulator/PadViewController.mm
|
||||
shell/apple/emulator-ios/emulator/EditPadViewController.h
|
||||
shell/apple/emulator-ios/emulator/EditPadViewController.mm
|
||||
shell/apple/emulator-ios/emulator/EmulatorView.h
|
||||
shell/apple/emulator-ios/emulator/EmulatorView.mm
|
||||
shell/apple/emulator-ios/emulator/main.m
|
||||
@@ -1655,7 +1744,8 @@ if(NOT LIBRETRO)
|
||||
shell/apple/emulator-ios/emulator/Images.xcassets
|
||||
shell/apple/emulator-ios/emulator/FlycastStoryboard.storyboard
|
||||
shell/apple/emulator-ios/emulator/LaunchScreen.storyboard
|
||||
shell/apple/emulator-ios/emulator/PadViewController.xib)
|
||||
shell/apple/emulator-ios/emulator/PadViewController.xib
|
||||
shell/apple/emulator-ios/emulator/EditPadViewController.xib)
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${IOS_RESOURCES})
|
||||
source_group("Resources" FILES ${IOS_RESOURCES})
|
||||
set_source_files_properties(${IOS_RESOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
@@ -1817,7 +1907,7 @@ if(NOT LIBRETRO)
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE shell/windows/flycast.rc)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE dsound winmm ws2_32 wsock32 xinput9_1_0 cfgmgr32 wininet)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE dsound winmm ws2_32 wsock32 xinput9_1_0 cfgmgr32 wininet psapi)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -1839,7 +1929,10 @@ if(BUILD_TESTING)
|
||||
tests/src/serialize_test.cpp
|
||||
tests/src/AicaArmTest.cpp
|
||||
tests/src/Sh4InterpreterTest.cpp
|
||||
tests/src/MmuTest.cpp)
|
||||
tests/src/MmuTest.cpp
|
||||
tests/src/util/PeriodicThreadTest.cpp
|
||||
tests/src/util/TsQueueTest.cpp
|
||||
tests/src/util/WorkerThreadTest.cpp)
|
||||
endif()
|
||||
|
||||
if(NINTENDO_SWITCH)
|
||||
@@ -1864,6 +1957,8 @@ if(IOS)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>-${CMAKE_OSX_SYSROOT}/Flycast.ipa" TYPE BIN)
|
||||
elseif(NINTENDO_SWITCH AND NOT LIBRETRO)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/flycast.nro DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
elseif(LIBRETRO)
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}/libretro")
|
||||
else()
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"version": 2,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "clang",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "build-clang",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gcc",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "build-gcc",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml)
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/bsd.yml)
|
||||
|
||||

|
||||
<img src="shell/linux/flycast.png" alt="flycast logo" width="150"/>
|
||||
|
||||
**Flycast** is a multi-platform Sega Dreamcast, Naomi, Naomi 2, and Atomiswave emulator derived from [**reicast**](https://github.com/skmp/reicast-emulator).
|
||||
|
||||
|
||||
@@ -37,8 +37,9 @@
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
#include <xxhash.h>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include "util/worker_thread.h"
|
||||
#include "util/periodic_thread.h"
|
||||
|
||||
namespace achievements
|
||||
{
|
||||
@@ -74,10 +75,8 @@ private:
|
||||
std::string getOrDownloadImage(const char *url);
|
||||
std::pair<std::string, bool> getCachedImage(const char *url);
|
||||
void diskChange();
|
||||
void asyncTask(std::function<void()> f);
|
||||
void startThread();
|
||||
void stopThread();
|
||||
void backgroundThread();
|
||||
void asyncTask(std::function<void()>&& f);
|
||||
void stopThreads();
|
||||
|
||||
static void clientLoginWithTokenCallback(int result, const char *error_message, rc_client_t *client, void *userdata);
|
||||
static void clientLoginWithPasswordCallback(int result, const char *error_message, rc_client_t *client, void *userdata);
|
||||
@@ -112,11 +111,12 @@ private:
|
||||
std::string cachePath;
|
||||
std::unordered_map<u64, std::string> cacheMap;
|
||||
std::mutex cacheMutex;
|
||||
std::vector<std::function<void()>> tasks;
|
||||
std::mutex taskMutex;
|
||||
std::thread taskThread;
|
||||
cResetEvent resetEvent;
|
||||
bool threadRunning = false;
|
||||
WorkerThread taskThread {"RA-background"};
|
||||
|
||||
PeriodicThread idleThread { "RA-idle", [this]() {
|
||||
if (active)
|
||||
rc_client_idle(rc_client);
|
||||
}};
|
||||
};
|
||||
|
||||
bool init() {
|
||||
@@ -176,6 +176,7 @@ Achievements::Achievements()
|
||||
EventManager::listen(Event::Pause, emuEventCallback, this);
|
||||
EventManager::listen(Event::Resume, emuEventCallback, this);
|
||||
EventManager::listen(Event::DiskChange, emuEventCallback, this);
|
||||
idleThread.setPeriod(1000);
|
||||
}
|
||||
|
||||
Achievements::~Achievements()
|
||||
@@ -188,44 +189,13 @@ Achievements::~Achievements()
|
||||
term();
|
||||
}
|
||||
|
||||
void Achievements::asyncTask(std::function<void()> f)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> _(taskMutex);
|
||||
tasks.emplace_back(f);
|
||||
}
|
||||
resetEvent.Set();
|
||||
void Achievements::asyncTask(std::function<void()>&& f) {
|
||||
taskThread.run(std::move(f));
|
||||
}
|
||||
|
||||
void Achievements::startThread()
|
||||
{
|
||||
threadRunning = true;
|
||||
taskThread = std::thread(&Achievements::backgroundThread, this);
|
||||
}
|
||||
|
||||
void Achievements::stopThread()
|
||||
{
|
||||
threadRunning = false;
|
||||
resetEvent.Set();
|
||||
if (taskThread.joinable())
|
||||
taskThread.join();
|
||||
}
|
||||
|
||||
void Achievements::backgroundThread()
|
||||
{
|
||||
ThreadName _("RA-background");
|
||||
while (threadRunning)
|
||||
{
|
||||
if (!resetEvent.Wait(1000) && active && paused)
|
||||
rc_client_idle(rc_client);
|
||||
std::vector<std::function<void()>> localTasks;
|
||||
{
|
||||
std::lock_guard<std::mutex> _(taskMutex);
|
||||
std::swap(tasks, localTasks);
|
||||
}
|
||||
for (auto& f : localTasks)
|
||||
f();
|
||||
}
|
||||
void Achievements::stopThreads() {
|
||||
taskThread.stop();
|
||||
idleThread.stop();
|
||||
}
|
||||
|
||||
bool Achievements::init()
|
||||
@@ -243,7 +213,6 @@ bool Achievements::init()
|
||||
//rc_client_set_unofficial_enabled(rc_client, 0);
|
||||
//rc_client_set_spectator_mode_enabled(rc_client, 0);
|
||||
loadCache();
|
||||
startThread();
|
||||
|
||||
if (!config::AchievementsUserName.get().empty() && !config::AchievementsToken.get().empty())
|
||||
{
|
||||
@@ -301,7 +270,7 @@ void Achievements::loadCache()
|
||||
}
|
||||
|
||||
static u64 hashUrl(const char *url) {
|
||||
return XXH64(url, strlen(url), 13);
|
||||
return XXH3_64bits(url, strlen(url));
|
||||
}
|
||||
|
||||
std::pair<std::string, bool> Achievements::getCachedImage(const char *url)
|
||||
@@ -357,7 +326,7 @@ void Achievements::term()
|
||||
if (rc_client == nullptr)
|
||||
return;
|
||||
unloadGame();
|
||||
stopThread();
|
||||
stopThreads();
|
||||
rc_client_destroy(rc_client);
|
||||
rc_client = nullptr;
|
||||
}
|
||||
@@ -779,8 +748,7 @@ std::string Achievements::getGameHash()
|
||||
{
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
const u32 diskType = libGDR_GetDiscType();
|
||||
if (diskType == NoDisk || diskType == Open)
|
||||
if (!gdr::isLoaded())
|
||||
return {};
|
||||
// Reopen the disk locally to avoid threading issues (CHD)
|
||||
try {
|
||||
@@ -814,15 +782,19 @@ std::string Achievements::getGameHash()
|
||||
return hash;
|
||||
}
|
||||
|
||||
void Achievements::pauseGame() {
|
||||
void Achievements::pauseGame()
|
||||
{
|
||||
paused = true;
|
||||
if (active)
|
||||
idleThread.start();
|
||||
}
|
||||
|
||||
void Achievements::resumeGame()
|
||||
{
|
||||
paused = false;
|
||||
if (config::EnableAchievements)
|
||||
if (config::EnableAchievements && !settings.naomi.slave)
|
||||
{
|
||||
idleThread.stop();
|
||||
loadGame();
|
||||
if (settings.raHardcoreMode && !config::AchievementsHardcoreMode)
|
||||
{
|
||||
@@ -956,15 +928,15 @@ void Achievements::unloadGame()
|
||||
paused = false;
|
||||
EventManager::unlisten(Event::VBlank, emuEventCallback, this);
|
||||
// wait for all async tasks before unloading the game
|
||||
stopThread();
|
||||
startThread();
|
||||
stopThreads();
|
||||
rc_client_unload_game(rc_client);
|
||||
settings.raHardcoreMode = false;
|
||||
}
|
||||
|
||||
void Achievements::diskChange()
|
||||
{
|
||||
if (!active)
|
||||
if (!active || settings.content.path.empty())
|
||||
// Don't unload the game when the lid is open while swapping disks
|
||||
return;
|
||||
std::string hash = getGameHash();
|
||||
if (hash == "") {
|
||||
|
||||
@@ -19,17 +19,20 @@ public:
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
if (wait)
|
||||
if (wait && last_time.time_since_epoch() != the_clock::duration::zero())
|
||||
{
|
||||
if (last_time.time_since_epoch() != the_clock::duration::zero())
|
||||
{
|
||||
auto fduration = std::chrono::nanoseconds(1000000000L * samples / 44100);
|
||||
auto duration = fduration - (the_clock::now() - last_time);
|
||||
auto fduration = std::chrono::nanoseconds(1'000'000'000LL * samples / 44100);
|
||||
auto duration = fduration - (the_clock::now() - last_time);
|
||||
if (duration > std::chrono::nanoseconds::zero())
|
||||
std::this_thread::sleep_for(duration);
|
||||
last_time += fduration;
|
||||
}
|
||||
else
|
||||
if (duration < -std::chrono::milliseconds(67))
|
||||
// if ~4 frames ahead, reset time (fast forward detection)
|
||||
last_time = the_clock::now();
|
||||
else
|
||||
last_time += fduration;
|
||||
}
|
||||
else {
|
||||
last_time = the_clock::now();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -10,29 +10,87 @@ class OSSAudioBackend : public AudioBackend
|
||||
int audioFD = -1;
|
||||
int recordFD = -1;
|
||||
|
||||
static int openDevice(int flags)
|
||||
{
|
||||
const char* path = "/dev/dsp";
|
||||
int fd = open(path, flags);
|
||||
|
||||
if (fd < 0)
|
||||
ERROR_LOG(AUDIO, "OSS: open(%s) failed: %s", path, strerror(errno));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static bool setRate(int fd, int rate)
|
||||
{
|
||||
int tmp = rate;
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: ioctl(SNDCTL_DSP_SPEED) failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tmp != rate)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: sample rate unsupported: %d => %d", rate, tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool setChannels(int fd, int channels)
|
||||
{
|
||||
int tmp = channels;
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: ioctl(SNDCTL_DSP_CHANNELS) failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tmp != channels)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: channels unsupported: %d => %d", channels, tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool setFormat(int fd, int format)
|
||||
{
|
||||
int tmp = format;
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: ioctl(SNDCTL_DSP_SETFMT) failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tmp != format)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: sample format unsupported: %#.8x => %#.8x", format, tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
OSSAudioBackend()
|
||||
: AudioBackend("oss", "Open Sound System") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
audioFD = open("/dev/dsp", O_WRONLY);
|
||||
if (audioFD < 0)
|
||||
audioFD = openDevice(O_WRONLY);
|
||||
|
||||
if (audioFD < 0 || !setRate(audioFD, 44100) || !setChannels(audioFD, 2) || !setFormat(audioFD, AFMT_S16_LE))
|
||||
{
|
||||
WARN_LOG(AUDIO, "Couldn't open /dev/dsp.");
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(AUDIO, "sound enabled, dsp opened for write");
|
||||
int tmp=44100;
|
||||
int err_ret;
|
||||
err_ret=ioctl(audioFD,SNDCTL_DSP_SPEED,&tmp);
|
||||
INFO_LOG(AUDIO, "set Frequency to %i, return %i (rate=%i)", 44100, err_ret, tmp);
|
||||
int channels=2;
|
||||
err_ret=ioctl(audioFD, SNDCTL_DSP_CHANNELS, &channels);
|
||||
INFO_LOG(AUDIO, "set dsp to stereo (%i => %i)", channels, err_ret);
|
||||
int format=AFMT_S16_LE;
|
||||
err_ret=ioctl(audioFD, SNDCTL_DSP_SETFMT, &format);
|
||||
INFO_LOG(AUDIO, "set dsp to %s audio (%i/%i => %i)", "16bits signed", AFMT_S16_LE, format, err_ret);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -54,34 +112,11 @@ public:
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
recordFD = open("/dev/dsp", O_RDONLY);
|
||||
if (recordFD < 0)
|
||||
recordFD = openDevice(O_RDONLY);
|
||||
|
||||
if (recordFD < 0 || !setRate(recordFD, sampling_freq) || !setChannels(recordFD, 1) || !setFormat(recordFD, AFMT_S16_NE /* Native 16 bits */ ))
|
||||
{
|
||||
INFO_LOG(AUDIO, "OSS: can't open default audio capture device");
|
||||
return false;
|
||||
}
|
||||
int tmp = AFMT_S16_NE; // Native 16 bits
|
||||
if (ioctl(recordFD, SNDCTL_DSP_SETFMT, &tmp) == -1 || tmp != AFMT_S16_NE)
|
||||
{
|
||||
INFO_LOG(AUDIO, "OSS: can't set sample format");
|
||||
close(recordFD);
|
||||
recordFD = -1;
|
||||
return false;
|
||||
}
|
||||
tmp = 1;
|
||||
if (ioctl(recordFD, SNDCTL_DSP_CHANNELS, &tmp) == -1)
|
||||
{
|
||||
INFO_LOG(AUDIO, "OSS: can't set channel count");
|
||||
close(recordFD);
|
||||
recordFD = -1;
|
||||
return false;
|
||||
}
|
||||
tmp = sampling_freq;
|
||||
if (ioctl(recordFD, SNDCTL_DSP_SPEED, &tmp) == -1)
|
||||
{
|
||||
INFO_LOG(AUDIO, "OSS: can't set sample rate");
|
||||
close(recordFD);
|
||||
recordFD = -1;
|
||||
termRecord();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "audiostream.h"
|
||||
#include "cfg/option.h"
|
||||
#include "emulator.h"
|
||||
|
||||
static void registerForEvents();
|
||||
|
||||
struct SoundFrame { s16 l; s16 r; };
|
||||
|
||||
@@ -60,6 +63,7 @@ void WriteSample(s16 r, s16 l)
|
||||
|
||||
void InitAudio()
|
||||
{
|
||||
registerForEvents();
|
||||
TermAudio();
|
||||
|
||||
std::string slug = config::AudioBackend;
|
||||
@@ -138,3 +142,19 @@ void StopAudioRecording()
|
||||
currentBackend->termRecord();
|
||||
audio_recording_started = false;
|
||||
}
|
||||
|
||||
static void registerForEvents()
|
||||
{
|
||||
static bool done;
|
||||
if (done)
|
||||
return;
|
||||
done = true;
|
||||
// Empty the audio buffer when loading a state or terminating the game
|
||||
const auto& callback = [](Event, void *) {
|
||||
writePtr = 0;
|
||||
};
|
||||
EventManager::listen(Event::Terminate, callback);
|
||||
EventManager::listen(Event::LoadState, callback);
|
||||
}
|
||||
|
||||
|
||||
+14
-9
@@ -15,12 +15,8 @@
|
||||
//HOST_CPU
|
||||
#define CPU_X86 0x20000001
|
||||
#define CPU_ARM 0x20000002
|
||||
#define CPU_MIPS 0x20000003
|
||||
#define CPU_ARM64 0x20000003
|
||||
#define CPU_X64 0x20000004
|
||||
#define CPU_GENERIC 0x20000005 //used for pnacl, emscripten, etc
|
||||
#define CPU_PPC 0x20000006
|
||||
#define CPU_PPC64 0x20000007
|
||||
#define CPU_ARM64 0x20000008
|
||||
|
||||
//FEAT_SHREC, FEAT_AREC, FEAT_DSPREC
|
||||
#define DYNAREC_NONE 0x40000001
|
||||
@@ -36,10 +32,19 @@
|
||||
#define HOST_CPU CPU_ARM
|
||||
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||
#define HOST_CPU CPU_ARM64
|
||||
#elif defined(__mips__)
|
||||
#define HOST_CPU CPU_MIPS
|
||||
#else
|
||||
#define HOST_CPU CPU_GENERIC
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_OS_SIMULATOR
|
||||
// iOS simulator
|
||||
#define TARGET_NO_REC
|
||||
#endif
|
||||
#if defined(TARGET_MAC) && HOST_CPU == CPU_ARM64
|
||||
#define TARGET_ARM_MAC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_NO_REC)
|
||||
@@ -100,7 +105,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(LIBRETRO) && !defined(TARGET_NO_EXCEPTIONS)
|
||||
#if !defined(LIBRETRO)
|
||||
#define USE_GGPO
|
||||
#endif
|
||||
|
||||
|
||||
@@ -130,3 +130,12 @@ void cfgSetAutoSave(bool autoSave)
|
||||
if (autoSave)
|
||||
saveConfigFile();
|
||||
}
|
||||
|
||||
void cfgSaveFloat(const std::string& section, const std::string& key, float value)
|
||||
{
|
||||
cfgdb.set_float(section, key, value);
|
||||
}
|
||||
float cfgLoadFloat(const std::string& section, const std::string& key, float def)
|
||||
{
|
||||
return cfgdb.get_float(section, key, def);
|
||||
}
|
||||
@@ -11,6 +11,8 @@ std::string cfgLoadStr(const std::string& section, const std::string& key, const
|
||||
void cfgSaveStr(const std::string& section, const std::string& key, const std::string& value);
|
||||
void cfgSaveBool(const std::string& section, const std::string& key, bool value);
|
||||
bool cfgLoadBool(const std::string& section, const std::string& key, bool def);
|
||||
void cfgSaveFloat(const std::string& section, const std::string& key, float value);
|
||||
float cfgLoadFloat(const std::string& section, const std::string& key, float def);
|
||||
void cfgSetVirtual(const std::string& section, const std::string& key, const std::string& value);
|
||||
bool cfgIsVirtual(const std::string& section, const std::string& key);
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ bool ConfigEntry::get_bool()
|
||||
}
|
||||
}
|
||||
|
||||
float ConfigEntry::get_float()
|
||||
{
|
||||
return atof(this->value.c_str());
|
||||
}
|
||||
|
||||
/* ConfigSection */
|
||||
|
||||
bool ConfigSection::has_entry(const std::string& name)
|
||||
@@ -192,6 +197,15 @@ bool ConfigFile::get_bool(const std::string& section_name, const std::string& en
|
||||
}
|
||||
}
|
||||
|
||||
float ConfigFile::get_float(const std::string& section_name, const std::string& entry_name, float default_value)
|
||||
{
|
||||
ConfigEntry* entry = get_entry(section_name, entry_name);
|
||||
if (entry == nullptr)
|
||||
return default_value;
|
||||
else
|
||||
return entry->get_float();
|
||||
}
|
||||
|
||||
void ConfigFile::set(const std::string& section_name, const std::string& entry_name, const std::string& value, bool is_virtual)
|
||||
{
|
||||
ConfigSection* section = this->get_section(section_name, is_virtual);
|
||||
@@ -222,6 +236,13 @@ void ConfigFile::set_bool(const std::string& section_name, const std::string& en
|
||||
this->set(section_name, entry_name, str_value, is_virtual);
|
||||
}
|
||||
|
||||
void ConfigFile::set_float(const std::string& section_name, const std::string& entry_name, float value, bool is_virtual)
|
||||
{
|
||||
std::stringstream str_value;
|
||||
str_value << value;
|
||||
this->set(section_name, entry_name, str_value.str(), is_virtual);
|
||||
}
|
||||
|
||||
void ConfigFile::parse(FILE* file)
|
||||
{
|
||||
if (file == nullptr)
|
||||
|
||||
@@ -13,6 +13,7 @@ struct ConfigEntry {
|
||||
int get_int();
|
||||
bool get_bool();
|
||||
int64_t get_int64();
|
||||
float get_float();
|
||||
};
|
||||
|
||||
struct ConfigSection {
|
||||
@@ -45,11 +46,13 @@ struct ConfigFile {
|
||||
int get_int(const std::string& section_name, const std::string& entry_name, int default_value = 0);
|
||||
int64_t get_int64(const std::string& section_name, const std::string& entry_name, int64_t default_value = 0);
|
||||
bool get_bool(const std::string& section_name, const std::string& entry_name, bool default_value = false);
|
||||
float get_float(const std::string& section_name, const std::string& entry_name, float default_value = 0.f);
|
||||
/* setting values */
|
||||
void set(const std::string& section_name, const std::string& entry_name, const std::string& value, bool is_virtual = false);
|
||||
void set_int(const std::string& section_name, const std::string& entry_name, int value, bool is_virtual = false);
|
||||
void set_int64(const std::string& section_name, const std::string& entry_name, int64_t value, bool is_virtual = false);
|
||||
void set_bool(const std::string& section_name, const std::string& entry_name, bool value, bool is_virtual = false);
|
||||
void set_float(const std::string& section_name, const std::string& entry_name, float value, bool is_virtual = false);
|
||||
|
||||
void delete_section(const std::string& section_name);
|
||||
void delete_entry(const std::string& section_name, const std::string& entry_name);
|
||||
|
||||
+18
-10
@@ -105,7 +105,11 @@ Option<int> TextureFiltering("rend.TextureFiltering", 0); // Default
|
||||
Option<bool> ThreadedRendering("rend.ThreadedRendering", true);
|
||||
Option<bool> DupeFrames("rend.DupeFrames", false);
|
||||
Option<int> PerPixelLayers("rend.PerPixelLayers", 32);
|
||||
#ifdef TARGET_UWP
|
||||
Option<bool> NativeDepthInterpolation("rend.NativeDepthInterpolation", true);
|
||||
#else
|
||||
Option<bool> NativeDepthInterpolation("rend.NativeDepthInterpolation", false);
|
||||
#endif
|
||||
Option<bool> EmulateFramebuffer("rend.EmulateFramebuffer", false);
|
||||
Option<bool> FixUpscaleBleedingEdge("rend.FixUpscaleBleedingEdge", true);
|
||||
Option<bool> CustomGpuDriver("rend.CustomGpuDriver", false);
|
||||
@@ -135,6 +139,7 @@ Option<bool, false> DiscordPresence("DiscordPresence", true);
|
||||
#if defined(__ANDROID__) && !defined(LIBRETRO)
|
||||
Option<bool, false> UseSafFilePicker("UseSafFilePicker", true);
|
||||
#endif
|
||||
OptionString LogServer("LogServer", "", "log");
|
||||
|
||||
// Profiler
|
||||
Option<bool> ProfilerEnabled("Profiler.Enabled");
|
||||
@@ -161,6 +166,8 @@ Option<int> GGPOChatTimeout("GGPOChatTimeout", 10, "network");
|
||||
Option<bool> NetworkOutput("NetworkOutput", false, "network");
|
||||
Option<int> MultiboardSlaves("MultiboardSlaves", 1, "network");
|
||||
Option<bool> BattleCableEnable("BattleCable", false, "network");
|
||||
Option<bool> UseDCNet("DCNet", false, "network");
|
||||
OptionString ISPUsername("ISPUsername", "flycast1", "network");
|
||||
|
||||
#ifdef USE_OMX
|
||||
Option<int> OmxAudioLatency("audio_latency", 100, "omx");
|
||||
@@ -179,23 +186,24 @@ std::array<Option<MapleDeviceType>, 4> MapleMainDevices {
|
||||
Option<MapleDeviceType>("device3", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device4", MDT_None, "input"),
|
||||
};
|
||||
std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices {
|
||||
Option<MapleDeviceType>("device1.1", MDT_SegaVMU, "input"),
|
||||
Option<MapleDeviceType>("device1.2", MDT_SegaVMU, "input"),
|
||||
std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices {{
|
||||
{{Option<MapleDeviceType>("device1.1", MDT_SegaVMU, "input"),
|
||||
Option<MapleDeviceType>("device1.2", MDT_SegaVMU, "input")}},
|
||||
|
||||
Option<MapleDeviceType>("device2.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device2.2", MDT_None, "input"),
|
||||
{{Option<MapleDeviceType>("device2.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device2.2", MDT_None, "input")}},
|
||||
|
||||
Option<MapleDeviceType>("device3.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device3.2", MDT_None, "input"),
|
||||
{{Option<MapleDeviceType>("device3.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device3.2", MDT_None, "input")}},
|
||||
|
||||
Option<MapleDeviceType>("device4.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device4.2", MDT_None, "input"),
|
||||
};
|
||||
{{Option<MapleDeviceType>("device4.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device4.2", MDT_None, "input")}},
|
||||
}};
|
||||
Option<bool> PerGameVmu("PerGameVmu", false, "config");
|
||||
#ifdef _WIN32
|
||||
Option<bool, false> UseRawInput("RawInput", false, "input");
|
||||
#endif
|
||||
Option<bool> UsePhysicalVmuMemory("UsePhysicalVmuMemory", false);
|
||||
|
||||
#ifdef USE_LUA
|
||||
Option<std::string, false> LuaFileName("LuaFileName", "flycast.lua");
|
||||
|
||||
+6
-8
@@ -202,11 +202,7 @@ protected:
|
||||
std::enable_if_t<std::is_same_v<float, U>, T>
|
||||
doLoad(const std::string& section, const std::string& name) const
|
||||
{
|
||||
std::string strValue = cfgLoadStr(section, name, "");
|
||||
if (strValue.empty())
|
||||
return value;
|
||||
else
|
||||
return (float)atof(strValue.c_str());
|
||||
return cfgLoadFloat(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
@@ -301,9 +297,7 @@ protected:
|
||||
std::enable_if_t<std::is_same_v<float, U>>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "%f", value);
|
||||
cfgSaveStr(section, name, buf);
|
||||
cfgSaveFloat(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
@@ -501,6 +495,7 @@ extern Option<bool, false> DiscordPresence;
|
||||
#if defined(__ANDROID__) && !defined(LIBRETRO)
|
||||
extern Option<bool, false> UseSafFilePicker;
|
||||
#endif
|
||||
extern OptionString LogServer;
|
||||
|
||||
// Profiling
|
||||
extern Option<bool> ProfilerEnabled;
|
||||
@@ -527,6 +522,8 @@ extern Option<int> GGPOChatTimeout;
|
||||
extern Option<bool> NetworkOutput;
|
||||
extern Option<int> MultiboardSlaves;
|
||||
extern Option<bool> BattleCableEnable;
|
||||
extern Option<bool> UseDCNet;
|
||||
extern OptionString ISPUsername;
|
||||
|
||||
#ifdef USE_OMX
|
||||
extern Option<int> OmxAudioLatency;
|
||||
@@ -546,6 +543,7 @@ extern Option<bool, false> UseRawInput;
|
||||
#else
|
||||
constexpr bool UseRawInput = false;
|
||||
#endif
|
||||
extern Option<bool> UsePhysicalVmuMemory;
|
||||
|
||||
#ifdef USE_LUA
|
||||
extern Option<std::string, false> LuaFileName;
|
||||
|
||||
+132
-6
@@ -83,7 +83,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "T30006M", nullptr, { 0x4CF42C, 0x4CF45C, 0x3E1A36, 0x3E1A34, 0x3E1A3C, 0x3E1A54, 0x3E1A5C },
|
||||
{ 0x43F00000, 0x3F400000, 0x08010000, 0, 0, 0, 0 } },
|
||||
{ "MK-5103750", nullptr, { 0x1FE270 }, { 0x43700000 } }, // Daytona USA (PAL)
|
||||
{ "MK-51037", nullptr, { 0x1FC6D0 }, { 0x43700000 } }, // Daytona USA (USA)
|
||||
// breaks online connection { "MK-51037", nullptr, { 0x1FC6D0 }, { 0x43700000 } }, // Daytona USA (USA)
|
||||
{ "T9501N-50", nullptr, { 0x9821D4 }, { 0x3F400000 } }, // Deadly Skies (PAL)
|
||||
{ "T8116D 50", nullptr, { 0x2E5530 }, { 0x43700000 } }, // Dead or Alive 2 (PAL)
|
||||
{ "T3601N", nullptr, { 0x2F0670 }, { 0x43700000 } }, // Dead or Alive 2 (USA)
|
||||
@@ -165,8 +165,8 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ 0x43F00000, 0x3F400000, 0x3F800000 } }, // Napple Tale: Arsia in Daydream (JP)
|
||||
//crash { "MK-51178", nullptr, { 0x23AF00, 0x23B160, 0x144D40, 0x2105B4, 0x705B40 },
|
||||
// { 0xBFAAAAAB, 0xBFAAAAAB, 0xBFAAAAAB, 0xBFAAAAAB, 0x44558000 } }, // NBA 2K2
|
||||
{ "T9504M", nullptr, { 0xCDE848, 0xCDE844 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (USA)
|
||||
{ "T-9502D-50", nullptr, { 0xBDE9B0, 0xBDE9C4 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (PAL)
|
||||
// { "T9504M", nullptr, { 0xCDE848, 0xCDE844 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (USA)
|
||||
// { "T-9502D-50", nullptr, { 0xBDE9B0, 0xBDE9C4 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (PAL)
|
||||
{ "MK-5110250", nullptr, { 0x87B5A4 }, { 0x43700000 } }, // Outtrigger (PAL)
|
||||
{ "HDR-0118", nullptr, { 0x83E284 }, { 0x43700000 } }, // Outtrigger (JP)
|
||||
{ "T15103D 50", nullptr, { 0x1EEE78 }, { 0x3F400000 } }, // PenPen (PAL)
|
||||
@@ -481,6 +481,68 @@ void CheatManager::reset(const std::string& gameId)
|
||||
else if (gameId == "SAMURAI SPIRITS 6" || gameId == "T0002M") {
|
||||
cheats.emplace_back(Cheat::Type::setValue, "fix depth", true, 16, 0x0003e602, 0x0009, true); // nop (shift by 8 bits instead of 10)
|
||||
}
|
||||
else if (gameId == "T-8107N") { // Fur Fighters (US)
|
||||
// force logging on to use more cycles
|
||||
cheats.emplace_back(Cheat::Type::setValue, "enable logging", true, 32, 0x00314248, 1, true);
|
||||
}
|
||||
else if (gameId == "T-8113D-50") { // Fur Fighters (EU)
|
||||
// force logging on to use more cycles
|
||||
cheats.emplace_back(Cheat::Type::setValue, "enable logging", true, 32, 0x00314228, 1, true);
|
||||
}
|
||||
// Dricas auth bypass
|
||||
else if (gameId == "T6807M") // Aero Dancing i
|
||||
{
|
||||
// modem
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0004b7a0, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0004b7a0, 0xe000000b, true); // rts, _mov #0, r0
|
||||
// BBA
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bba bypass auth ifeq", true, 32, 0x0004af5c, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bba bypass dricas auth", true, 32, 0x0004af5c, 0xe000000b, true);
|
||||
// IP check
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "ip check ifeq", true, 32, 0x00020860, 0x4f222fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "ip check ok", true, 32, 0x00020860, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T6809M") // Aero Dancing i - Jikai Saku Made Matemasen
|
||||
{
|
||||
// modem
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0004b940, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0004b940, 0xe000000b, true);
|
||||
// BBA
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bba bypass auth ifeq", true, 32, 0x0004f848, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bba bypass dricas auth", true, 32, 0x0004f848, 0xe000000b, true);
|
||||
// IP check
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "ip check ifeq", true, 32, 0x00020980, 0x4f222fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "ip check ok", true, 32, 0x00020980, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T6805M") { // Aero Dancing F - Todoroki Tsubasa no Hatsu Hikou
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0003ed10, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0003ed10, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "HDR-0106") { // Daytona USA (JP)
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0003ad30, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0003ad30, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "HDR-0073") { // Sega Tetris
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x000a56f8, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x000a56f8, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T44501M") { // Golf Shiyou Yo 2
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0013f150, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0013f150, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "HDR-0124") { // Hundred Swords
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x006558ac, 0x1f414f22, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x006558ac, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T43903M") { // Culdcept II
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x00800524, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x00800524, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T40214N") { // The Next Tetris (US)
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass speed ifeq", true, 32, 0x0016d5d4, 0x2f862fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass speed check", true, 32, 0x0016d5d4, 0xe001000b, true);
|
||||
}
|
||||
|
||||
if (cheats.size() > cheatCount)
|
||||
setActive(true);
|
||||
}
|
||||
@@ -672,6 +734,42 @@ static std::vector<u32> parseCodes(const std::string& s)
|
||||
return codes;
|
||||
}
|
||||
|
||||
// Decrypt (some) Action Replay/Gameshark/Codebreaker/Xploder encrypted codes
|
||||
// Master codes change the encryption method and thus are not supported (07xxxxxx)
|
||||
// Taken from DCcrypt
|
||||
constexpr u32 Seeds[16] = {
|
||||
0xA53A8888,
|
||||
0xA1427921, 0xAC9528B1, 0xC5892354, 0x49671B12,
|
||||
0xACC56121, 0xACB5381E, 0x765436E1, 0x9F2C3E54,
|
||||
0x1133E312, 0xAC5E7894, 0xE9F208B1, 0x4E87DCFE,
|
||||
0x43174312, 0x1D7A6C99, 0x874224A2
|
||||
};
|
||||
|
||||
static u32 decryptCode(u32 v)
|
||||
{
|
||||
constexpr u32 something = 6;
|
||||
|
||||
if ((v & 0xf0000000) == 0)
|
||||
return v;
|
||||
u32 seed = Seeds[v >> 28];
|
||||
if (something & 4)
|
||||
v = (((v << 1) & 0x0FFFFFFE) | ((v >> 27) & 1));
|
||||
if (something & 2) {
|
||||
v = (((v << 1) & 0x0FFFFFFE) | ((v >> 27) & 1));
|
||||
v = (((v << 8) & 0x0FFFFF00) | ((v >> 20) & 0xFF));
|
||||
}
|
||||
if (something & 1)
|
||||
seed >>= 4;
|
||||
u32 ret = (seed & 0x0FFFFFFF) ^ v;
|
||||
//if ((ret & 0x0FF00000) != 0x07100000)
|
||||
// something = (ret & 0x0f) + 6;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 decryptArg(u32 v) {
|
||||
return (((v + 0x543700D0) >> 29) | ((v + 0x543700D0) * 8)) ^ Seeds[0];
|
||||
}
|
||||
|
||||
void CheatManager::addGameSharkCheat(const std::string& name, const std::string& s)
|
||||
{
|
||||
std::vector<u32> codes = parseCodes(s);
|
||||
@@ -687,6 +785,22 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||
Cheat cheat{};
|
||||
cheat.description = name;
|
||||
u32 code = (codes[i] & 0xff000000) >> 24;
|
||||
if (code & 0xf0)
|
||||
{
|
||||
// encrypted code
|
||||
codes[i] = decryptCode(codes[i]);
|
||||
code = (codes[i] & 0xff000000) >> 24;
|
||||
if (code == 4 && i + 2 < codes.size()) {
|
||||
// following args are also encrypted
|
||||
codes[i + 1] = decryptArg(codes[i + 1]);
|
||||
codes[i + 2] = decryptArg(codes[i + 2]);
|
||||
}
|
||||
else if (code == 0xd && i + 2 < codes.size()) {
|
||||
// following arg is also encrypted
|
||||
codes[i + 1] = decryptArg(codes[i + 1]);
|
||||
}
|
||||
// TODO Which ops have encrypted args (3, 5, E, F)? Couldn't find any
|
||||
}
|
||||
switch (code)
|
||||
{
|
||||
case 0:
|
||||
@@ -800,9 +914,17 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
// TODO 7 change decryption type
|
||||
// TODO 0xb delay applying codes
|
||||
// TODO 0xc global enable test
|
||||
|
||||
case 7:
|
||||
// change decryption type: 071000XX (example: 07100005)
|
||||
throw FlycastException("Master codes aren't supported");
|
||||
|
||||
// TODO 0xb delay applying codes: 0b0xxxxx
|
||||
// Delay putting on codes for xxxxx cycles. Default 1000 (0x3e7)
|
||||
// TODO 0xc global enable test: 0cxxxxxx vvvvvvvv
|
||||
// If the value at address 8Cxxxxxx is equal to vvvvvvvv, execute ALL codes;
|
||||
// otherwise no codes are executed. Useful for waiting until game has loaded.
|
||||
|
||||
case 0xd:
|
||||
{
|
||||
// enable next code if eq/neq/lt/gt
|
||||
@@ -860,6 +982,10 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||
conditionCheat = cheat;
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO 0xF: 0F-XXXXXX 0000YYYY
|
||||
// 16-Bit Write Once Immediately. (Activator code)
|
||||
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "emulator.h"
|
||||
#include "hw/sh4/sh4_if.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "hw/sh4/sh4_interpreter.h"
|
||||
#include "hw/sh4/dyna/shil.h"
|
||||
#include "cfg/option.h"
|
||||
#include <array>
|
||||
#include <signal.h>
|
||||
@@ -122,9 +122,9 @@ public:
|
||||
for (u32 i = 0; i < Sh4RegList.size(); i++)
|
||||
{
|
||||
if (Sh4RegList[i] == reg_sr_status)
|
||||
allregs[i] = sh4_sr_GetFull();
|
||||
allregs[i] = Sh4cntx.sr.getFull();
|
||||
else if (Sh4RegList[i] != NoReg)
|
||||
allregs[i] = *GetRegPtr(Sh4RegList[i]);
|
||||
allregs[i] = *GetRegPtr(Sh4cntx, Sh4RegList[i]);
|
||||
}
|
||||
*regs = &allregs[0];
|
||||
return allregs.size();
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
{
|
||||
for (u32 i = 0; i < Sh4RegList.size(); i++)
|
||||
if (Sh4RegList[i] != NoReg)
|
||||
*GetRegPtr(Sh4RegList[i]) = regs[i];
|
||||
*GetRegPtr(Sh4cntx, Sh4RegList[i]) = regs[i];
|
||||
}
|
||||
|
||||
u32 readReg(u32 regNum)
|
||||
@@ -143,9 +143,9 @@ public:
|
||||
return 0;
|
||||
Sh4RegType reg = Sh4RegList[regNum];
|
||||
if (reg == reg_sr_status)
|
||||
return sh4_sr_GetFull();
|
||||
return Sh4cntx.sr.getFull();
|
||||
if (reg != NoReg)
|
||||
return *GetRegPtr(reg);
|
||||
return *GetRegPtr(Sh4cntx, reg);
|
||||
return 0;
|
||||
}
|
||||
void writeReg(u32 regNum, u32 value)
|
||||
@@ -154,9 +154,9 @@ public:
|
||||
return;
|
||||
Sh4RegType reg = Sh4RegList[regNum];
|
||||
if (reg == reg_sr_status)
|
||||
sh4_sr_SetFull(value);
|
||||
Sh4cntx.sr.setFull(value);
|
||||
else if (reg != NoReg)
|
||||
*GetRegPtr(reg) = value;
|
||||
*GetRegPtr(Sh4cntx, reg) = value;
|
||||
}
|
||||
|
||||
const u8 *readMem(u32 addr, u32 len)
|
||||
|
||||
+384
-384
File diff suppressed because it is too large.
Load diff
+1
-1
Submodule core/deps/SDL updated: 79ec168f3c...2359383fc1.
Submodule
+1
Submodule core/deps/asio added at d3402006e8.
@@ -13,7 +13,7 @@
|
||||
template<class T, int N> class RingBuffer
|
||||
{
|
||||
public:
|
||||
RingBuffer<T, N>() :
|
||||
RingBuffer() :
|
||||
_head(0),
|
||||
_tail(0),
|
||||
_size(0) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
template<class T, int N> class StaticBuffer
|
||||
{
|
||||
public:
|
||||
StaticBuffer<T, N>() :
|
||||
StaticBuffer() :
|
||||
_size(0) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
|
||||
cmake_policy(VERSION 3.2)
|
||||
cmake_minimum_required(VERSION 3.6 FATAL_ERROR)
|
||||
cmake_policy(VERSION 3.6)
|
||||
|
||||
set(GLM_VERSION "0.9.9")
|
||||
project(glm VERSION ${GLM_VERSION} LANGUAGES CXX)
|
||||
|
||||
+1
-1
Submodule core/deps/libchdr updated: 9b6ff6c3c2...5f82799f2c.
@@ -31,7 +31,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) && !defined(USE_LIBCDIO) // libcdio has its equivalent version
|
||||
#undef fopen
|
||||
|
||||
void *fopen_utf8(const char * filename, const char * mode)
|
||||
|
||||
@@ -190,7 +190,9 @@ int main(int argc, char *argv[]) { }" HAVE_NULLABLE)
|
||||
|
||||
test_big_endian(WORDS_BIGENDIAN)
|
||||
|
||||
find_package(ZLIB 1.1.2 REQUIRED)
|
||||
if(NOT TARGET zlibstatic)
|
||||
find_package(ZLIB 1.1.2 REQUIRED)
|
||||
endif()
|
||||
# so developers on systems where zlib is named differently (Windows, sometimes)
|
||||
# can override the name used in the pkg-config file
|
||||
if (NOT ZLIB_LINK_LIBRARY_NAME)
|
||||
@@ -239,17 +241,22 @@ if(ENABLE_LZMA)
|
||||
endif(ENABLE_LZMA)
|
||||
|
||||
if(ENABLE_ZSTD)
|
||||
find_package(zstd 1.3.6)
|
||||
if(zstd_FOUND)
|
||||
if(TARGET libzstd_static)
|
||||
set(zstd_TARGET libzstd_static)
|
||||
set(HAVE_LIBZSTD 1)
|
||||
if(TARGET zstd::libzstd_shared)
|
||||
set(zstd_TARGET zstd::libzstd_shared)
|
||||
else()
|
||||
set(zstd_TARGET zstd::libzstd_static)
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "-- zstd library not found; zstandard support disabled")
|
||||
endif(zstd_FOUND)
|
||||
find_package(zstd 1.3.6)
|
||||
if(zstd_FOUND)
|
||||
set(HAVE_LIBZSTD 1)
|
||||
if(TARGET zstd::libzstd_shared)
|
||||
set(zstd_TARGET zstd::libzstd_shared)
|
||||
else()
|
||||
set(zstd_TARGET zstd::libzstd_static)
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "-- zstd library not found; zstandard support disabled")
|
||||
endif()
|
||||
endif()
|
||||
endif(ENABLE_ZSTD)
|
||||
|
||||
if (COMMONCRYPTO_FOUND)
|
||||
|
||||
@@ -175,7 +175,11 @@ if(SHARED_LIB_VERSIONNING)
|
||||
set_target_properties(zip PROPERTIES VERSION 5.5 SOVERSION 5)
|
||||
endif()
|
||||
|
||||
target_link_libraries(zip PRIVATE ZLIB::ZLIB)
|
||||
if (TARGET zlibstatic)
|
||||
target_link_libraries(zip PRIVATE zlibstatic)
|
||||
else()
|
||||
target_link_libraries(zip PRIVATE ZLIB::ZLIB)
|
||||
endif()
|
||||
target_include_directories(zip
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib>
|
||||
|
||||
+1
-1
Submodule core/deps/luabridge updated: fab7b33b89...5d21e35633.
@@ -338,7 +338,7 @@ receiveDevicesFromMiniSSDPD(int s, int * error)
|
||||
#ifdef DEBUG
|
||||
printf(" usnsize=%u\n", usnsize);
|
||||
#endif /* DEBUG */
|
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
|
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize+3);
|
||||
if(tmp == NULL) {
|
||||
if (error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
|
||||
+1
-1
Submodule core/deps/oboe updated: 03242e9ef9...b15f5e39c0.
@@ -7,6 +7,8 @@
|
||||
#include <windows.h>
|
||||
#pragma pack(pop)
|
||||
|
||||
#define PICO_SUPPORT_THREADING
|
||||
|
||||
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
|
||||
#else
|
||||
@@ -54,6 +56,15 @@ static inline void PICO_IDLE(void)
|
||||
|
||||
#define alloca _alloca
|
||||
|
||||
#ifdef PICO_SUPPORT_THREADING
|
||||
#define PICO_SUPPORT_MUTEX
|
||||
/* mutex implementations */
|
||||
extern void* pico_mutex_init(void);
|
||||
extern void pico_mutex_lock(void* mux);
|
||||
extern void pico_mutex_unlock(void* mux);
|
||||
extern void pico_mutex_deinit(void* mux);
|
||||
#endif
|
||||
|
||||
#endif /* PICO_SUPPORT_MSVC */
|
||||
|
||||
|
||||
@@ -170,6 +170,7 @@ struct pico_ip_mreq_source {
|
||||
#define PICO_SOCK_EV_CLOSE 8u
|
||||
#define PICO_SOCK_EV_FIN 0x10u
|
||||
#define PICO_SOCK_EV_ERR 0x80u
|
||||
#define PICO_SOCK_EV_DEL 0x100u
|
||||
|
||||
struct pico_msginfo {
|
||||
struct pico_device *dev;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "pico_frame.h"
|
||||
#include "pico_constants.h"
|
||||
|
||||
#define PICO_MAX_TIMERS 20
|
||||
#define PICO_MAX_TIMERS 50
|
||||
|
||||
#define PICO_ETH_MRU (1514u)
|
||||
#define PICO_IP_MRU (1500u)
|
||||
|
||||
@@ -295,7 +295,7 @@ static int pico_ethernet_ipv6_dst(struct pico_frame *f, struct pico_eth *const d
|
||||
|
||||
/* Ethernet send, first attempt: try our own address.
|
||||
* Returns 0 if the packet is not for us.
|
||||
* Returns 1 if the packet is cloned to our own receive queue, so the caller can discard the original frame.
|
||||
* Returns 1 if the packet is cloned to our own receive queue and the original frame is dicarded.
|
||||
* */
|
||||
static int32_t pico_ethsend_local(struct pico_frame *f, struct pico_eth_hdr *hdr)
|
||||
{
|
||||
@@ -308,7 +308,9 @@ static int32_t pico_ethsend_local(struct pico_frame *f, struct pico_eth_hdr *hdr
|
||||
dbg("sending out packet destined for our own mac\n");
|
||||
if (pico_ethernet_receive(clone) < 0) {
|
||||
dbg("pico_ethernet_receive() failed\n");
|
||||
return 0;
|
||||
}
|
||||
pico_frame_discard(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -317,13 +319,12 @@ static int32_t pico_ethsend_local(struct pico_frame *f, struct pico_eth_hdr *hdr
|
||||
|
||||
/* Ethernet send, second attempt: try bcast.
|
||||
* Returns 0 if the packet is not bcast, so it will be handled somewhere else.
|
||||
* Returns 1 if the packet is handled by the pico_device_broadcast() function, so it can be discarded.
|
||||
* Returns 1 if the packet is handled by the pico_device_broadcast() function and is discarded.
|
||||
* */
|
||||
static int32_t pico_ethsend_bcast(struct pico_frame *f)
|
||||
{
|
||||
if (IS_LIMITED_BCAST(f)) {
|
||||
(void)pico_device_broadcast(f); /* We can discard broadcast even if it's not sent. */
|
||||
return 1;
|
||||
return (pico_device_broadcast(f) > 0); // Return 1 on success, ret > 0
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -242,6 +242,10 @@ static int8_t pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie)
|
||||
if (!dev)
|
||||
return -1;
|
||||
|
||||
// prevent overflow
|
||||
if (cookie->size > PICO_ICMP_MAXCOOKIE)
|
||||
return -1;
|
||||
|
||||
echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, dev, (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size));
|
||||
if (!echo)
|
||||
return -1;
|
||||
|
||||
@@ -92,7 +92,7 @@ PACKED_STRUCT_DEF pico_icmp4_hdr {
|
||||
#define PICO_ICMP_MASKREPLY 18
|
||||
|
||||
#define PICO_ICMP_MAXTYPE 18
|
||||
|
||||
#define PICO_ICMP_MAXCOOKIE 65528
|
||||
|
||||
#define PICO_ICMP_UNREACH_NET 0
|
||||
#define PICO_ICMP_UNREACH_HOST 1
|
||||
|
||||
@@ -190,7 +190,6 @@ static int socket_tcp_do_deliver(struct pico_socket *s, struct pico_frame *f)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg("TCP SOCKET> Not s.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -826,6 +826,8 @@ static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len)
|
||||
static int tcpopt_len_check(uint32_t *idx, uint8_t len, uint8_t expected)
|
||||
{
|
||||
if (len != expected) {
|
||||
if (len < 2)
|
||||
return -1;
|
||||
*idx = *idx + len - 2;
|
||||
return -1;
|
||||
}
|
||||
@@ -880,7 +882,7 @@ static inline void tcp_parse_option_timestamp(struct pico_socket_tcp *t, struct
|
||||
t->ts_nxt = long_be(tsval);
|
||||
}
|
||||
|
||||
static void tcp_parse_options(struct pico_frame *f)
|
||||
static int tcp_parse_options(struct pico_frame *f)
|
||||
{
|
||||
struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
|
||||
uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR;
|
||||
@@ -897,6 +899,10 @@ static void tcp_parse_options(struct pico_frame *f)
|
||||
if (f->payload && ((opt + i) > f->payload))
|
||||
break;
|
||||
|
||||
if (len == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcp_dbg_options("Received option '%d', len = %d \n", type, len);
|
||||
switch (type) {
|
||||
case PICO_TCP_OPTION_NOOP:
|
||||
@@ -924,6 +930,7 @@ static void tcp_parse_options(struct pico_frame *f)
|
||||
i = i + len - 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void tcp_send_add_tcpflags(struct pico_socket_tcp *ts, struct pico_frame *f)
|
||||
@@ -1755,7 +1762,8 @@ static int tcp_data_in(struct pico_socket *s, struct pico_frame *f)
|
||||
(void)hdr;
|
||||
|
||||
if (((hdr->len & 0xf0u) >> 2u) <= f->transport_len) {
|
||||
tcp_parse_options(f);
|
||||
if (tcp_parse_options(f) < 0)
|
||||
return -1;
|
||||
f->payload = f->transport_hdr + ((hdr->len & 0xf0u) >> 2u);
|
||||
f->payload_len = payload_len;
|
||||
tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
|
||||
@@ -2130,7 +2138,8 @@ static int tcp_ack(struct pico_socket *s, struct pico_frame *f)
|
||||
tcp_ack_dbg(s, f);
|
||||
#endif
|
||||
|
||||
tcp_parse_options(f);
|
||||
if (tcp_parse_options(f) < 0)
|
||||
return -1;
|
||||
t->recv_wnd = short_be(hdr->rwnd);
|
||||
|
||||
acked = (uint16_t)tcp_ack_advance_una(t, f, &acked_timestamp);
|
||||
@@ -2446,7 +2455,8 @@ static int tcp_syn(struct pico_socket *s, struct pico_frame *f)
|
||||
f->sock = &new->sock;
|
||||
mtu = (uint16_t)pico_socket_get_mss(&new->sock);
|
||||
new->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR);
|
||||
tcp_parse_options(f);
|
||||
if (tcp_parse_options(f) < 0)
|
||||
return -1;
|
||||
new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
|
||||
new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
|
||||
new->tcpq_hold.max_size = 2u * mtu;
|
||||
@@ -2793,7 +2803,7 @@ static uint8_t invalid_flags(struct pico_socket *s, uint8_t flags)
|
||||
{ /* PICO_SOCKET_STATE_TCP_UNDEF */ 0, },
|
||||
{ /* PICO_SOCKET_STATE_TCP_CLOSED */ 0, },
|
||||
{ /* PICO_SOCKET_STATE_TCP_LISTEN */ PICO_TCP_SYN, PICO_TCP_SYN | PICO_TCP_PSH },
|
||||
{ /* PICO_SOCKET_STATE_TCP_SYN_SENT */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK},
|
||||
{ /* PICO_SOCKET_STATE_TCP_SYN_SENT */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK, PICO_TCP_SYNACK | PICO_TCP_PSH },
|
||||
{ /* PICO_SOCKET_STATE_TCP_SYN_RECV */ PICO_TCP_SYN, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
|
||||
{ /* PICO_SOCKET_STATE_TCP_ESTABLISHED*/ PICO_TCP_SYN, PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST, PICO_TCP_RSTACK},
|
||||
{ /* PICO_SOCKET_STATE_TCP_CLOSE_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
|
||||
@@ -2864,6 +2874,11 @@ int pico_tcp_input(struct pico_socket *s, struct pico_frame *f)
|
||||
// tcp_dbg("[sam] TCP> s->state >> 8 = %u\n", s->state >> 8);
|
||||
tcp_dbg("[tcp input] socket: %p state: %d <-- local port:%u remote port: %u seq: 0x%08x ack: 0x%08x flags: 0x%02x t_len: %u, hdr: %u payload: %d\n", s, s->state >> 8, short_be(hdr->trans.dport), short_be(hdr->trans.sport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len );
|
||||
|
||||
if ((f->payload + f->payload_len) > (f->buffer + f->buffer_len)) {
|
||||
tcp_dbg("TCP> Invalid payload len %04x\n", f->payload_len);
|
||||
pico_frame_discard(f);
|
||||
return -1;
|
||||
}
|
||||
/* This copy of the frame has the current socket as owner */
|
||||
f->sock = s;
|
||||
s->timestamp = TCP_TIME;
|
||||
@@ -2874,7 +2889,9 @@ int pico_tcp_input(struct pico_socket *s, struct pico_frame *f)
|
||||
}
|
||||
else if (flags == PICO_TCP_SYN || flags == (PICO_TCP_SYN | PICO_TCP_PSH)) {
|
||||
tcp_action_call(action->syn, s, f);
|
||||
} else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) {
|
||||
} else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)
|
||||
// Windows CE / DirectPlay sets the PSH flag on SYN|ACK packets, which is normally invalid
|
||||
|| flags == (PICO_TCP_SYN | PICO_TCP_ACK | PICO_TCP_PSH)) {
|
||||
tcp_action_call(action->synack, s, f);
|
||||
} else {
|
||||
ret = tcp_action_by_flags(action, s, f, flags);
|
||||
|
||||
@@ -451,6 +451,7 @@ int32_t pico_device_broadcast(struct pico_frame *f)
|
||||
{
|
||||
struct pico_tree_node *index;
|
||||
int32_t ret = -1;
|
||||
int sent = 0;
|
||||
|
||||
pico_tree_foreach(index, &Device_tree)
|
||||
{
|
||||
@@ -463,14 +464,28 @@ int32_t pico_device_broadcast(struct pico_frame *f)
|
||||
break;
|
||||
|
||||
copy->dev = dev;
|
||||
copy->dev->send(copy->dev, copy->start, (int)copy->len);
|
||||
ret = copy->dev->send(copy->dev, copy->start, (int)copy->len);
|
||||
/* FIXME: If a device driver returns zero (which means the device
|
||||
* driver is currently busy) there is no means to retry the
|
||||
* broadcast operation later. */
|
||||
pico_frame_discard(copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = f->dev->send(f->dev, f->start, (int)f->len);
|
||||
/* FIXME: If a device driver returns zero (which means the device
|
||||
* driver is currently busy) there is no means to retry the
|
||||
* broadcast operation later. */
|
||||
}
|
||||
|
||||
/* FIXME: If at least one device driver was able to sent the frame on
|
||||
* the wire, the broadcast operation will be considered successful. */
|
||||
if (ret > 0) {
|
||||
sent = 1;
|
||||
}
|
||||
}
|
||||
ret = sent ? f->len : -1;
|
||||
pico_frame_discard(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -473,6 +473,8 @@ static void socket_garbage_collect(pico_time now, void *arg)
|
||||
struct pico_socket *s = (struct pico_socket *) arg;
|
||||
IGNORE_PARAMETER(now);
|
||||
|
||||
if (s->wakeup)
|
||||
s->wakeup(PICO_SOCK_EV_DEL, s);
|
||||
socket_clean_queues(s);
|
||||
PICO_FREE(s);
|
||||
}
|
||||
|
||||
@@ -1,44 +1,40 @@
|
||||
cmake_minimum_required(VERSION 2.6...3.0.2)
|
||||
cmake_minimum_required(VERSION 3.5...4.0.0)
|
||||
|
||||
project(xbyak CXX)
|
||||
|
||||
file(GLOB headers xbyak/*.h)
|
||||
|
||||
if (DEFINED CMAKE_VERSION AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.0.2)
|
||||
include(GNUInstallDirs)
|
||||
add_library(${PROJECT_NAME} INTERFACE)
|
||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||
|
||||
target_include_directories(
|
||||
${PROJECT_NAME} INTERFACE
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
include(GNUInstallDirs)
|
||||
add_library(${PROJECT_NAME} INTERFACE)
|
||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}-targets
|
||||
)
|
||||
target_include_directories(
|
||||
${PROJECT_NAME} INTERFACE
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
|
||||
configure_file(
|
||||
cmake/config.cmake.in
|
||||
${PROJECT_NAME}Config.cmake
|
||||
@ONLY
|
||||
)
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}-targets
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
configure_file(
|
||||
cmake/config.cmake.in
|
||||
${PROJECT_NAME}Config.cmake
|
||||
@ONLY
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}-targets
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
elseif(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include")
|
||||
endif()
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}-targets
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${headers}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
+644
@@ -0,0 +1,644 @@
|
||||
# Known critical issues:
|
||||
# - AVX512 related tests are incomplete. Because default environment of
|
||||
# GitHub Actions doesn't guarantee to support AVX512.
|
||||
# As of May 2021, they're using Xeon E5-2673 (which doesn't support
|
||||
# AVX512) and Xeon Platinum 8171M (which supports AVX512).
|
||||
# See also https://github.com/actions/runner/issues/1069
|
||||
#
|
||||
# In this CI script, it always run `make default` which compiles xxHash
|
||||
# with AVX512 intrinsics. But if test runner doesn't support AVX512,
|
||||
# it doesn't run `make check` which tests runtime error/consistency.
|
||||
# It means that this test stochastically detects a failure in AVX512
|
||||
# code path.
|
||||
#
|
||||
# Known issues:
|
||||
# - This test script ignores exit code of cppcheck which can see under
|
||||
# Job:Linux x64 misc tests > cppcheck in the GitHub Actions report.
|
||||
# Because xxHash project doesn't 100% follow their recommendation.
|
||||
# Also sometimes it reports false positives.
|
||||
#
|
||||
# - GitHub Actions doesn't support Visual Studio 2015 and 2013.
|
||||
# https://github.com/actions/virtual-environments/issues/387
|
||||
#
|
||||
# - Setup procedure for msys2 environment is painfully slow. It takes
|
||||
# 3..5 minutes.
|
||||
#
|
||||
# Notes:
|
||||
# - You can investigate various information at the right pane of GitHub
|
||||
# Actions report page.
|
||||
#
|
||||
# | Item | Section in the right pane |
|
||||
# | ------------------------- | ------------------------------------- |
|
||||
# | OS, VM | Set up job |
|
||||
# | git repo, commit hash | Run actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 |
|
||||
# | gcc, tools | Environment info |
|
||||
#
|
||||
# - To fail earlier, order of tests in the same job are roughly sorted by
|
||||
# elapsed time.
|
||||
#
|
||||
# Todos:
|
||||
# - [ ] Linux: Add native ARM runner.
|
||||
# - [ ] Linux: Add native ARM64 runner.
|
||||
# - [ ] Linux: Add native PPC64LE runner.
|
||||
# - [ ] Linux: Add native S390X runner.
|
||||
# - [ ] Windows: Add VS2013.
|
||||
# - [ ] Windows: Add VS2015.
|
||||
# - [ ] Windows: Add clang for msys2.
|
||||
# - [ ] Windows: Add native or emulated ARM runner.
|
||||
# - [ ] Windows: Add native or emulated ARM64 runner.
|
||||
|
||||
|
||||
# Name of the workflow is also displayed as a SVG badge
|
||||
name: xxHash CI tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
concurrency:
|
||||
group: fast-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
xxhash-c-compilers:
|
||||
name: CC=${{ matrix.cc }}, ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false # 'false' means Don't stop matrix workflows even if some matrix entry fails.
|
||||
matrix:
|
||||
include: [
|
||||
# You can access the following values via ${{ matrix.??? }}
|
||||
#
|
||||
# pkgs : apt-get package names. It can include multiple package names which are delimited by space.
|
||||
# cc : C compiler executable.
|
||||
# cxx : C++ compiler executable for `make ctocpptest`.
|
||||
# os : GitHub Actions YAML workflow label. See https://github.com/actions/virtual-environments#available-environments
|
||||
|
||||
# cc
|
||||
{ pkgs: '', cc: cc, cxx: c++, os: ubuntu-latest, },
|
||||
|
||||
# gcc
|
||||
{ pkgs: '', cc: gcc, cxx: g++, os: ubuntu-latest, },
|
||||
# { pkgs: 'gcc-13 g++-13 lib32gcc-13-dev', cc: gcc-13, cxx: g++-13, os: ubuntu-22.04, }, # currently failing
|
||||
{ pkgs: 'gcc-12 g++-12 lib32gcc-12-dev', cc: gcc-12, cxx: g++-12, os: ubuntu-22.04, },
|
||||
{ pkgs: 'gcc-11 g++-11 lib32gcc-11-dev', cc: gcc-11, cxx: g++-11, os: ubuntu-22.04, },
|
||||
{ pkgs: 'gcc-10 g++-10 lib32gcc-10-dev', cc: gcc-10, cxx: g++-10, os: ubuntu-22.04, },
|
||||
{ pkgs: 'gcc-9 g++-9 lib32gcc-9-dev', cc: gcc-9, cxx: g++-9, os: ubuntu-22.04, },
|
||||
{ pkgs: 'gcc-8 g++-8 lib32gcc-8-dev', cc: gcc-8, cxx: g++-8, os: ubuntu-20.04, },
|
||||
{ pkgs: 'gcc-7 g++-7 lib32gcc-7-dev', cc: gcc-7, cxx: g++-7, os: ubuntu-20.04, },
|
||||
|
||||
# clang
|
||||
{ pkgs: '', cc: clang, cxx: clang++, os: ubuntu-latest, },
|
||||
{ pkgs: 'clang-15', cc: clang-15, cxx: clang++-15, os: ubuntu-22.04, },
|
||||
{ pkgs: 'clang-14', cc: clang-14, cxx: clang++-14, os: ubuntu-22.04, },
|
||||
{ pkgs: 'clang-13', cc: clang-13, cxx: clang++-13, os: ubuntu-22.04, },
|
||||
{ pkgs: 'clang-12', cc: clang-12, cxx: clang++-12, os: ubuntu-22.04, },
|
||||
{ pkgs: 'clang-11', cc: clang-11, cxx: clang++-11, os: ubuntu-22.04, },
|
||||
{ pkgs: 'clang-10', cc: clang-10, cxx: clang++-10, os: ubuntu-20.04, },
|
||||
{ pkgs: 'clang-9', cc: clang-9, cxx: clang++-9, os: ubuntu-20.04, },
|
||||
{ pkgs: 'clang-8', cc: clang-8, cxx: clang++-8, os: ubuntu-20.04, },
|
||||
{ pkgs: 'clang-7', cc: clang-7, cxx: clang++-7, os: ubuntu-20.04, },
|
||||
{ pkgs: 'clang-6.0', cc: clang-6.0, cxx: clang++-6.0, os: ubuntu-20.04, },
|
||||
]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
env: # Set environment variables
|
||||
# We globally set CC and CXX to improve compatibility with .travis.yml
|
||||
CC: ${{ matrix.cc }}
|
||||
CXX: ${{ matrix.cxx }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: apt-get install
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-multilib
|
||||
sudo apt-get install ${{ matrix.pkgs }}
|
||||
|
||||
- name: Environment info
|
||||
run: |
|
||||
echo && type $CC && which $CC && $CC --version
|
||||
echo && type $CXX && which $CXX && $CXX --version
|
||||
echo && type make && make -v
|
||||
echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present
|
||||
|
||||
- name: C90 + no-long-long compliance
|
||||
if: always()
|
||||
run: |
|
||||
CFLAGS="-std=c90 -pedantic -Wno-long-long -Werror" make clean xxhsum
|
||||
|
||||
- name: C90 + XXH_NO_LONG_LONG
|
||||
if: always()
|
||||
run: |
|
||||
# strict c90, with no long long support; resulting in no XXH64_* symbol
|
||||
make clean c90test
|
||||
|
||||
- name: dispatch
|
||||
if: always()
|
||||
run: |
|
||||
# removing sign conversion warnings due to a bug in gcc-5's definition of some AVX512 intrinsics
|
||||
CFLAGS="-Werror" MOREFLAGS="-Wno-sign-conversion" make clean dispatch
|
||||
|
||||
- name: DISPATCH=1
|
||||
if: always()
|
||||
run: |
|
||||
CFLAGS="-Wall -Wextra -Werror" make DISPATCH=1 clean default
|
||||
|
||||
- name: XXH_SIZE_OPT == 2
|
||||
if: always()
|
||||
run: |
|
||||
CFLAGS="-Os -DXXH_SIZE_OPT=2 -Wall -Wextra -Werror" make clean xxhsum
|
||||
|
||||
- name: noxxh3test
|
||||
if: always()
|
||||
run: |
|
||||
# check library can be compiled with XXH_NO_XXH3, resulting in no XXH3_* symbol
|
||||
make clean noxxh3test
|
||||
|
||||
- name: nostreamtest
|
||||
if: always()
|
||||
run: |
|
||||
# check library can be compiled with XXH_NO_STREAM, resulting in no streaming symbols
|
||||
make clean noxxh3test
|
||||
|
||||
- name: make avx512f
|
||||
run: |
|
||||
CFLAGS="-O1 -mavx512f -Werror" make clean default
|
||||
|
||||
- name: test-all
|
||||
if: always()
|
||||
run: |
|
||||
make clean test-all
|
||||
|
||||
|
||||
ubuntu-consistency:
|
||||
name: Linux x64 check results consistency
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Environment info
|
||||
run: |
|
||||
echo && gcc --version
|
||||
echo && make -v
|
||||
echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present
|
||||
|
||||
- name: Scalar code path
|
||||
run: |
|
||||
CPPFLAGS=-DXXH_VECTOR=XXH_SCALAR make clean check
|
||||
|
||||
- name: SSE2 code path
|
||||
run: |
|
||||
CPPFLAGS=-DXXH_VECTOR=XXH_SSE2 make clean check
|
||||
|
||||
- name: AVX2 code path
|
||||
run: |
|
||||
CPPFLAGS="-mavx2 -DXXH_VECTOR=XXH_AVX2" make clean check
|
||||
|
||||
# As for AVX512, see "Known critical issues" at the top of this file
|
||||
- name: AVX512 code path
|
||||
run: |
|
||||
# Run "make check" if /proc/cpuinfo has flags for avx512.
|
||||
grep -q "^flags.*\bavx512\b" /proc/cpuinfo && CPPFLAGS="-mavx512f -DXXH_VECTOR=XXH_AVX512" make clean check || (echo This test runner does not support AVX512. && $(exit 0))
|
||||
|
||||
- name: reroll code path (#240)
|
||||
run: |
|
||||
CPPFLAGS=-DXXH_REROLL=1 make clean check
|
||||
|
||||
- name: tests/bench
|
||||
run: |
|
||||
make -C tests/bench
|
||||
|
||||
|
||||
ubuntu-wasm:
|
||||
name: Ubuntu Node ${{ matrix.node-version }} WebAssembly/asm.js tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x, 17.x, 18.x]
|
||||
|
||||
env:
|
||||
EM_VERSION: 3.1.33 # TODO: more emsdk versions
|
||||
EM_CACHE_FOLDER: emsdk-cache-${{ matrix.node-version }}
|
||||
CC: emcc
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Setup cache
|
||||
id: cache-system-libraries
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{env.EM_CACHE_FOLDER}}
|
||||
key: em${{env.EM_VERSION}}-node${{ matrix.node-version }}-${{ runner.os }}
|
||||
|
||||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: ${{env.EM_VERSION}}
|
||||
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Environment info
|
||||
run: |
|
||||
echo && node -p '`node version: ${process.versions.node}, v8 version: ${process.versions.v8}`'
|
||||
echo && emcc --version
|
||||
echo && make -v
|
||||
echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present
|
||||
|
||||
- name: Scalar code path
|
||||
run: |
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" RUN_ENV="node" NODE_JS=1 make clean check
|
||||
|
||||
- name: SIMD128 (via NEON SIMDe) code path (XXH_VECTOR=XXH_NEON)
|
||||
run: |
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_NEON -msimd128" RUN_ENV="node" NODE_JS=1 make clean check
|
||||
|
||||
- name: Scalar asm.js (-sWASM=0)
|
||||
run: |
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" RUN_ENV="node" NODE_JS=1 LDFLAGS="-sWASM=0" make clean check
|
||||
|
||||
|
||||
ubuntu-misc:
|
||||
name: Linux x64 misc tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: apt-get install
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install valgrind cppcheck
|
||||
|
||||
- name: Environment info
|
||||
run: |
|
||||
echo && gcc --version
|
||||
echo && clang --version
|
||||
echo && valgrind --version
|
||||
echo && cppcheck --version
|
||||
echo && make -v
|
||||
echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present
|
||||
|
||||
- name: cppcheck
|
||||
run: |
|
||||
# This test script ignores exit code of cppcheck. See knowin issues
|
||||
# at the top of this file.
|
||||
make clean cppcheck || echo There are some cppcheck reports
|
||||
|
||||
- name: test-mem (valgrind)
|
||||
run: |
|
||||
make clean test-mem
|
||||
|
||||
- name: usan
|
||||
run: |
|
||||
make clean usan
|
||||
|
||||
- name: Lint Unicode in root-dir, cli/, tests/, tests/bench/, tests/collisions/.
|
||||
run: |
|
||||
make lint-unicode
|
||||
|
||||
- name: test-filename-escape
|
||||
# See also issue #695 - https://github.com/Cyan4973/xxHash/issues/695
|
||||
run: |
|
||||
make clean test-filename-escape
|
||||
|
||||
- name: test-cli-comment-line
|
||||
run: |
|
||||
make clean test-cli-comment-line
|
||||
|
||||
ubuntu-cmake-unofficial:
|
||||
name: Linux x64 cmake unofficial build test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Environment info
|
||||
run: |
|
||||
echo && gcc --version
|
||||
echo && cmake --version
|
||||
echo && make -v
|
||||
echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present
|
||||
|
||||
- name: cmake
|
||||
run: |
|
||||
cd cmake_unofficial
|
||||
cmake -Bbuild
|
||||
cd build
|
||||
CFLAGS=-Werror make
|
||||
mkdir -p test_install_dir
|
||||
DESTDIR=test_install_dir cmake --install .
|
||||
|
||||
- name: cmake pkgconfig generation
|
||||
run: |
|
||||
cd cmake_unofficial
|
||||
pwd
|
||||
ls
|
||||
rm -rf build
|
||||
cmake -Bbuild -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_INCLUDEDIR=/usr/include -DCMAKE_INSTALL_LIBDIR=/usr/lib
|
||||
echo "checking content of libxxhash.pc"
|
||||
cat build/libxxhash.pc | grep "libdir=/usr/lib"
|
||||
cat build/libxxhash.pc | grep "includedir=/usr/include"
|
||||
|
||||
- name: cmake minimum version v3.10 test
|
||||
run: |
|
||||
mkdir -p cmake_bins
|
||||
cd cmake_bins
|
||||
wget https://cmake.org/files/v3.10/cmake-3.10.0-Linux-x86_64.tar.gz
|
||||
tar xzf cmake-3.10.0-Linux-x86_64.tar.gz
|
||||
cd ../cmake_unofficial
|
||||
rm -rf build
|
||||
pwd
|
||||
ls
|
||||
mkdir -p build
|
||||
cd build
|
||||
../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake --version
|
||||
../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake ..
|
||||
../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake --build .
|
||||
mkdir -p test_install_dir
|
||||
DESTDIR=test_install_dir ../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake --install .
|
||||
rm -rf *
|
||||
../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake --build .
|
||||
|
||||
|
||||
|
||||
# Linux, { ARM, ARM64, PPC64LE, PPC64, S390X }
|
||||
# All tests are using QEMU and gcc cross compiler.
|
||||
|
||||
qemu-consistency:
|
||||
name: QEMU ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false # 'false' means Don't stop matrix workflows even if some matrix failed.
|
||||
matrix:
|
||||
include: [
|
||||
{ name: 'ARM', xcc_pkg: gcc-arm-linux-gnueabi, xcc: arm-linux-gnueabi-gcc, xemu_pkg: qemu-system-arm, xemu: qemu-arm-static, os: ubuntu-latest, },
|
||||
{ name: 'AARCH64', xcc_pkg: gcc-aarch64-linux-gnu, xcc: aarch64-linux-gnu-gcc, xemu_pkg: qemu-system-arm, xemu: qemu-aarch64-static, os: ubuntu-latest, },
|
||||
{ name: 'PPC64LE', xcc_pkg: gcc-powerpc64le-linux-gnu, xcc: powerpc64le-linux-gnu-gcc, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64le-static, os: ubuntu-latest, },
|
||||
{ name: 'PPC64', xcc_pkg: gcc-powerpc64-linux-gnu, xcc: powerpc64-linux-gnu-gcc, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64-static, os: ubuntu-latest, },
|
||||
{ name: 'S390X', xcc_pkg: gcc-s390x-linux-gnu, xcc: s390x-linux-gnu-gcc, xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static, os: ubuntu-latest, },
|
||||
{ name: 'MIPS', xcc_pkg: gcc-mips-linux-gnu, xcc: mips-linux-gnu-gcc, xemu_pkg: qemu-system-mips, xemu: qemu-mips-static, os: ubuntu-latest, },
|
||||
{ name: 'M68K', xcc_pkg: gcc-m68k-linux-gnu, xcc: m68k-linux-gnu-gcc, xemu_pkg: qemu-system-m68k, xemu: qemu-m68k-static, os: ubuntu-latest, },
|
||||
{ name: 'RISC-V', xcc_pkg: gcc-riscv64-linux-gnu, xcc: riscv64-linux-gnu-gcc, xemu_pkg: qemu-system-riscv64,xemu: qemu-riscv64-static, os: ubuntu-latest, },
|
||||
# SPARC64 qemu emulation seems broken on Ubuntu-22
|
||||
{ name: 'SPARC', xcc_pkg: gcc-sparc64-linux-gnu, xcc: sparc64-linux-gnu-gcc, xemu_pkg: qemu-system-sparc, xemu: qemu-sparc64-static, os: ubuntu-20.04, },
|
||||
{ name: 'LoongArch', xcc_pkg: gcc-14-loongarch64-linux-gnu, xcc: loongarch64-linux-gnu-gcc-14, xemu_pkg: qemu-system-loongarch64, xemu: qemu-loongarch64-static, os: ubuntu-24.04, },
|
||||
|
||||
{ name: 'ARM, gcc-10', xcc_pkg: gcc-10-arm-linux-gnueabi, xcc: arm-linux-gnueabi-gcc-10, xemu_pkg: qemu-system-arm, xemu: qemu-arm-static, os: ubuntu-20.04, },
|
||||
{ name: 'AARCH64, gcc-10', xcc_pkg: gcc-10-aarch64-linux-gnu, xcc: aarch64-linux-gnu-gcc-10, xemu_pkg: qemu-system-arm, xemu: qemu-aarch64-static, os: ubuntu-20.04, },
|
||||
{ name: 'PPC64LE, gcc-10', xcc_pkg: gcc-10-powerpc64le-linux-gnu, xcc: powerpc64le-linux-gnu-gcc-10, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64le-static, os: ubuntu-20.04, },
|
||||
{ name: 'PPC64, gcc-10', xcc_pkg: gcc-10-powerpc64-linux-gnu, xcc: powerpc64-linux-gnu-gcc-10, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64-static, os: ubuntu-20.04, },
|
||||
{ name: 'S390X, gcc-10', xcc_pkg: gcc-10-s390x-linux-gnu, xcc: s390x-linux-gnu-gcc-10, xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static, os: ubuntu-20.04, },
|
||||
{ name: 'MIPS, gcc-10', xcc_pkg: gcc-10-mips-linux-gnu, xcc: mips-linux-gnu-gcc-10, xemu_pkg: qemu-system-mips, xemu: qemu-mips-static, os: ubuntu-20.04, },
|
||||
|
||||
{ name: 'ARM, gcc-9', xcc_pkg: gcc-9-arm-linux-gnueabi, xcc: arm-linux-gnueabi-gcc-9, xemu_pkg: qemu-system-arm, xemu: qemu-arm-static, os: ubuntu-20.04, },
|
||||
# SVE tests require at least gcc-10.1
|
||||
# { name: 'AARCH64, gcc-9', xcc_pkg: gcc-9-aarch64-linux-gnu, xcc: aarch64-linux-gnu-gcc-9, xemu_pkg: qemu-system-arm, xemu: qemu-aarch64-static, os: ubuntu-20.04, },
|
||||
{ name: 'PPC64LE, gcc-9', xcc_pkg: gcc-9-powerpc64le-linux-gnu, xcc: powerpc64le-linux-gnu-gcc-9, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64le-static, os: ubuntu-20.04, },
|
||||
{ name: 'PPC64, gcc-9', xcc_pkg: gcc-9-powerpc64-linux-gnu, xcc: powerpc64-linux-gnu-gcc-9, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64-static, os: ubuntu-20.04, },
|
||||
{ name: 'S390X, gcc-9', xcc_pkg: gcc-9-s390x-linux-gnu, xcc: s390x-linux-gnu-gcc-9, xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static, os: ubuntu-20.04, },
|
||||
{ name: 'MIPS, gcc-9', xcc_pkg: gcc-9-mips-linux-gnu, xcc: mips-linux-gnu-gcc-9, xemu_pkg: qemu-system-mips, xemu: qemu-mips-static, os: ubuntu-20.04, },
|
||||
|
||||
{ name: 'ARM, gcc-8', xcc_pkg: gcc-8-arm-linux-gnueabi, xcc: arm-linux-gnueabi-gcc-8, xemu_pkg: qemu-system-arm, xemu: qemu-arm-static, os: ubuntu-20.04, },
|
||||
# aarch64-linux-gnu-gcc-8 linker has an issue for LDFLAGS="-static"
|
||||
# { name: 'AARCH64, gcc-8', xcc_pkg: gcc-8-aarch64-linux-gnu, xcc: aarch64-linux-gnu-gcc-8, xemu_pkg: qemu-system-arm, xemu: qemu-aarch64-static, os: ubuntu-20.04, },
|
||||
{ name: 'PPC64LE, gcc-8', xcc_pkg: gcc-8-powerpc64le-linux-gnu, xcc: powerpc64le-linux-gnu-gcc-8, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64le-static, os: ubuntu-20.04, },
|
||||
{ name: 'PPC64, gcc-8', xcc_pkg: gcc-8-powerpc64-linux-gnu, xcc: powerpc64-linux-gnu-gcc-8, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64-static, os: ubuntu-20.04, },
|
||||
{ name: 'S390X, gcc-8', xcc_pkg: gcc-8-s390x-linux-gnu, xcc: s390x-linux-gnu-gcc-8, xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static, os: ubuntu-20.04, },
|
||||
# ubuntu-20.04 fails to retrieve gcc-8-mips-linux-gnu for some reason.
|
||||
# { name: 'MIPS, gcc-8', xcc_pkg: gcc-8-mips-linux-gnu, xcc: mips-linux-gnu-gcc-8, xemu_pkg: qemu-system-mips, xemu: qemu-mips-static, os: ubuntu-20.04, },
|
||||
]
|
||||
env: # Set environment variables
|
||||
XCC: ${{ matrix.xcc }}
|
||||
XEMU: ${{ matrix.xemu }}
|
||||
MOREFLAGS: -Werror
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: apt update & install (1)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-multilib g++-multilib qemu-utils qemu-user-static
|
||||
|
||||
- name: Environment info (1)
|
||||
run: |
|
||||
echo && apt-cache search "^gcc-" | grep "linux" | sort
|
||||
|
||||
- name: apt update & install (2)
|
||||
run: |
|
||||
sudo apt-get install ${{ matrix.xcc_pkg }} ${{ matrix.xemu_pkg }}
|
||||
|
||||
- name: Environment info (2)
|
||||
run: |
|
||||
echo && which $XCC
|
||||
echo && $XCC --version
|
||||
echo && $XCC -v # Show built-in specs
|
||||
echo && which $XEMU
|
||||
echo && $XEMU --version
|
||||
|
||||
- name: ARM (XXH_VECTOR=[ scalar, NEON ])
|
||||
if: ${{ startsWith(matrix.name, 'ARM') }}
|
||||
run: |
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_NEON" CFLAGS="-O3 -march=armv7-a -fPIC -mfloat-abi=softfp -mfpu=neon-vfpv4" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
make -C tests clean
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make -C tests sanity_test_vectors.h test_sanity
|
||||
|
||||
- name: AARCH64 (XXH_VECTOR=[ scalar, NEON, SVE ])
|
||||
if: ${{ startsWith(matrix.name, 'AARCH64') }}
|
||||
run: |
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_NEON" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=off,sve512=off,sve1024=off,sve2048=off" make clean check
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=on,sve512=off,sve1024=off,sve2048=off" make clean check
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=on,sve512=on,sve1024=off,sve2048=off" make clean check
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=on,sve512=on,sve1024=on,sve2048=off" make clean check
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=on,sve512=on,sve1024=on,sve2048=on" make clean check
|
||||
|
||||
- name: PPC64(LE) (XXH_VECTOR=[ scalar, VSX ])
|
||||
if: ${{ startsWith(matrix.name, 'PPC64') }}
|
||||
run: |
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_VSX" CFLAGS="-O3 -maltivec -mvsx -mpower8-vector -mcpu=power8" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
|
||||
- name: S390X (XXH_VECTOR=[ scalar, VSX ])
|
||||
if: ${{ startsWith(matrix.name, 'S390X') }}
|
||||
run: |
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
CPPFLAGS=-DXXH_VECTOR=XXH_VSX CFLAGS="-O3 -march=arch11 -mzvector" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
|
||||
- name: MIPS-M68K-RISCV-SPARC (XXH_VECTOR=[ scalar ])
|
||||
if: ${{ startsWith(matrix.name, 'MIPS') || startsWith(matrix.name, 'M68K') || startsWith(matrix.name, 'RISC-V') || startsWith(matrix.name, 'SPARC') }}
|
||||
run: |
|
||||
make clean; LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make check
|
||||
|
||||
- name: LoongArch (XXH_VECTOR=[ scalar, LSX ])
|
||||
if: ${{ startsWith(matrix.name, 'LoongArch') }}
|
||||
run: |
|
||||
CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
CPPFLAGS=-DXXH_VECTOR=XXH_LSX CFLAGS="-O3 -march=la464 -mlsx" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
|
||||
|
||||
# macOS
|
||||
|
||||
macos-general:
|
||||
name: ${{ matrix.system.os }}
|
||||
runs-on: ${{ matrix.system.os }}
|
||||
strategy:
|
||||
fail-fast: false # 'false' means Don't stop matrix workflows even if some matrix failed.
|
||||
matrix:
|
||||
system: [
|
||||
{ os: macos-13 },
|
||||
{ os: macos-14 },
|
||||
{ os: macos-15 },
|
||||
{ os: macos-latest },
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Environment info
|
||||
run: |
|
||||
echo && clang --version
|
||||
echo && sysctl -a | grep machdep.cpu # cpuinfo
|
||||
|
||||
- name: make
|
||||
run: |
|
||||
CFLAGS="-Werror" make clean default
|
||||
|
||||
- name: make test
|
||||
run: |
|
||||
# test scenario where "stdout" is not the console
|
||||
make clean test MOREFLAGS='-Werror' | tee
|
||||
|
||||
|
||||
# Windows, { VC++2022, VC++2019 } x { x64, Win32, ARM, ARM64 }
|
||||
#
|
||||
# - Default shell for Windows environment is PowerShell Core.
|
||||
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#using-a-specific-shell
|
||||
#
|
||||
# - "windows-2022" uses Visual Studio 2022.
|
||||
# https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022
|
||||
#
|
||||
# - "windows-2019" uses Visual Studio 2019.
|
||||
# https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019
|
||||
|
||||
windows-visualc-general:
|
||||
name: ${{ matrix.system.vc }}, ${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.system.os }} # Runs-on foreach value of strategy.matrix.system.os
|
||||
strategy:
|
||||
fail-fast: false # 'false' means: Don't stop matrix workflows even if some matrix failed.
|
||||
matrix:
|
||||
system: [
|
||||
{ os: windows-2022, vc: "VC++ 2022", clangcl: 'true', },
|
||||
{ os: windows-2019, vc: "VC++ 2019", clangcl: 'true', },
|
||||
]
|
||||
arch: [ x64, Win32, ARM64 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Build ${{ matrix.system.os }}, ${{ matrix.arch }}
|
||||
run: |
|
||||
cd cmake_unofficial
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -A ${{ matrix.arch }} -DCMAKE_C_FLAGS="/W4 /WX"
|
||||
cmake --build . --config Release
|
||||
|
||||
- name: Test
|
||||
# Run benchmark for testing only if target arch is x64 or Win32.
|
||||
if: ${{ matrix.arch == 'x64' || matrix.arch == 'Win32' }}
|
||||
run: |
|
||||
.\cmake_unofficial\build\Release\xxhsum.exe -bi1
|
||||
|
||||
- name: Build ${{ matrix.system.os }}, ${{ matrix.arch }}, with DISPATCH
|
||||
# DISPATCH only if target arch is x64 or Win32.
|
||||
if: ${{ ( matrix.arch == 'x64' || matrix.arch == 'Win32' ) }}
|
||||
run: |
|
||||
cd cmake_unofficial
|
||||
mkdir build-visual-dispatch
|
||||
cd build-visual-dispatch
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DDISPATCH=ON -A x64 -DCMAKE_C_FLAGS="/W4 /WX"
|
||||
cmake --build . --config Release
|
||||
|
||||
- name: Runtime Test (DISPATCH)
|
||||
# Run benchmark for testing only if target arch is x64 or Win32.
|
||||
if: ${{ ( matrix.arch == 'x64' || matrix.arch == 'Win32' ) }}
|
||||
run: |
|
||||
.\cmake_unofficial\build-visual-dispatch\Release\xxhsum.exe -V | grep autoVec
|
||||
.\cmake_unofficial\build-visual-dispatch\Release\xxhsum.exe -bi1
|
||||
|
||||
|
||||
- name: Build ${{ matrix.system.os }}, clang-cl, ${{ matrix.arch }}
|
||||
if: ${{ matrix.system.clangcl == 'true' }}
|
||||
run: |
|
||||
cd cmake_unofficial
|
||||
mkdir build-clang-cl
|
||||
cd build-clang-cl
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -A x64 -DCMAKE_GENERATOR_TOOLSET=ClangCL
|
||||
cmake --build . --config Release
|
||||
|
||||
- name: Test (clang-cl)
|
||||
# Run benchmark for testing only if target arch is x64 or Win32.
|
||||
if: ${{ matrix.system.clangcl == 'true' && ( matrix.arch == 'x64' || matrix.arch == 'Win32' ) }}
|
||||
run: |
|
||||
.\cmake_unofficial\build-clang-cl\Release\xxhsum.exe -bi1
|
||||
|
||||
|
||||
|
||||
# Windows, { mingw64, mingw32 }
|
||||
#
|
||||
# - Shell for msys2 is sh (msys2). defaults.run.shell is for this setting.
|
||||
#
|
||||
# https://github.com/msys2/MINGW-packages/blob/master/.github/workflows/main.yml
|
||||
# https://github.com/actions/starter-workflows/issues/95
|
||||
|
||||
windows-msys2-general:
|
||||
name: Windows ${{ matrix.msystem }}
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false # 'false' means Don't stop matrix workflows even if some matrix failed.
|
||||
matrix:
|
||||
include: [
|
||||
{ msystem: mingw64, toolchain: mingw-w64-x86_64-toolchain },
|
||||
{ msystem: mingw32, toolchain: mingw-w64-i686-toolchain },
|
||||
]
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: msys2/setup-msys2@7efe20baefed56359985e327d329042cde2434ff # v2
|
||||
with:
|
||||
msystem: MSYS
|
||||
install: mingw-w64-i686-make ${{ matrix.toolchain }}
|
||||
update: true
|
||||
|
||||
- name: Update
|
||||
run: |
|
||||
pacman --noconfirm -Suuy
|
||||
pacman --noconfirm -Suu
|
||||
|
||||
- name: mingw64
|
||||
if: ${{ matrix.msystem == 'mingw64' }}
|
||||
run: |
|
||||
PATH=/mingw64/bin:$PATH /mingw32/bin/mingw32-make clean test gcc-og-test MOREFLAGS=-Werror
|
||||
PATH=/mingw64/bin:$PATH /mingw32/bin/mingw32-make -C tests/bench
|
||||
# Abort if result of "file ./xxhsum.exe" doesn't contain 'x86-64'.
|
||||
# Expected output is "./xxhsum.exe: PE32+ executable (console) x86-64, for MS Windows"
|
||||
file ./xxhsum.exe
|
||||
file ./xxhsum.exe | grep -q 'x86-64' || $(exit 1)
|
||||
./xxhsum.exe --version
|
||||
|
||||
- name: mingw32
|
||||
if: ${{ matrix.msystem == 'mingw32' }}
|
||||
run: |
|
||||
PATH=/mingw32/bin:$PATH /mingw32/bin/mingw32-make.exe clean test MOREFLAGS=-Werror
|
||||
PATH=/mingw32/bin:$PATH /mingw32/bin/mingw32-make.exe -C tests/bench
|
||||
# Abort if result of "file ./xxhsum.exe" doesn't contain '80386'.
|
||||
# Expected output is "./xxhsum.exe: PE32 executable (console) Intel i386, for MS Windows"
|
||||
file ./xxhsum.exe
|
||||
file ./xxhsum.exe | grep -q '386' || $(exit 1)
|
||||
./xxhsum.exe --version
|
||||
@@ -0,0 +1,72 @@
|
||||
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||
# by a third-party and are governed by separate terms of service, privacy
|
||||
# policy, and support documentation.
|
||||
|
||||
name: Scorecard supply-chain security
|
||||
on:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
branch_protection_rule:
|
||||
# To guarantee Maintained check is occasionally updated. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||
schedule:
|
||||
- cron: '35 19 * * 2'
|
||||
push:
|
||||
branches: [ "dev" ]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
# Needed to publish results and get a badge (see publish_results below).
|
||||
id-token: write
|
||||
# Uncomment the permissions below if installing in a private repository.
|
||||
# contents: read
|
||||
# actions: read
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# - you are installing Scorecard on a *private* repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Public repositories:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
# - Allows the repository to include the Scorecard badge.
|
||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||
# For private repositories:
|
||||
# - `publish_results` will always be set to `false`, regardless
|
||||
# of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@c6c77c8c2d62cfd5b2e8d548817fd3d1582ac744 # v2.14.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -12,14 +12,16 @@ libxxhash.*
|
||||
xxh32sum
|
||||
xxh64sum
|
||||
xxh128sum
|
||||
xxh3sum
|
||||
xxhsum
|
||||
xxhsum32
|
||||
xxhsum_privateXXH
|
||||
xxhsum_inlinedXXH
|
||||
dispatch
|
||||
tests/generate_unicode_test
|
||||
|
||||
# compilation chain
|
||||
.clang_complete
|
||||
tests/sanity_test
|
||||
tests/sanity_test_vectors_generator
|
||||
fuzzer
|
||||
|
||||
# Mac OS-X artefacts
|
||||
*.dSYM
|
||||
@@ -44,3 +46,16 @@ infer-out
|
||||
tmp*
|
||||
tests/*.unicode
|
||||
tests/unicode_test*
|
||||
*.txt
|
||||
!CMakeLists.txt
|
||||
*.xxhsum
|
||||
|
||||
# editor artifacts
|
||||
.clang_complete
|
||||
.clangd
|
||||
*.swp
|
||||
.vscode/
|
||||
.vs/
|
||||
|
||||
# Doxygen
|
||||
doxygen/
|
||||
@@ -1,113 +0,0 @@
|
||||
language: c
|
||||
|
||||
# Dump CPU info before start
|
||||
before_install:
|
||||
- cat /proc/cpuinfo
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
|
||||
- name: General linux tests (Xenial)
|
||||
dist: xenial
|
||||
arch: amd64
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang
|
||||
- g++-multilib
|
||||
- gcc-multilib
|
||||
- cppcheck
|
||||
script:
|
||||
- make -B test-all
|
||||
|
||||
- name: Check results consistency on x64
|
||||
arch: amd64
|
||||
script:
|
||||
- CPPFLAGS=-DXXH_VECTOR=0 make check # Scalar code path
|
||||
- make clean
|
||||
- CPPFLAGS=-DXXH_VECTOR=1 make check # SSE2 code path
|
||||
- make clean
|
||||
- CPPFLAGS="-mavx2 -DXXH_VECTOR=2" make check # AVX2 code path
|
||||
- make clean
|
||||
- CPPFLAGS=-DXXH_REROLL=1 make check # reroll code path (#240)
|
||||
- make -C tests/bench
|
||||
|
||||
- name: ARM compilation and consistency checks (Qemu)
|
||||
dist: xenial
|
||||
arch: amd64
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- qemu-system-arm
|
||||
- qemu-user-static
|
||||
- gcc-arm-linux-gnueabi
|
||||
- libc6-dev-armel-cross
|
||||
script:
|
||||
# arm (32-bit)
|
||||
- CC=arm-linux-gnueabi-gcc CPPFLAGS=-DXXH_VECTOR=0 LDFLAGS=-static RUN_ENV=qemu-arm-static make check # Scalar code path
|
||||
- make clean
|
||||
# NEON (32-bit)
|
||||
- CC=arm-linux-gnueabi-gcc CPPFLAGS=-DXXH_VECTOR=3 CFLAGS="-O3 -march=armv7-a -fPIC -mfloat-abi=softfp -mfpu=neon-vfpv4" LDFLAGS=-static RUN_ENV=qemu-arm-static make check # NEON code path
|
||||
|
||||
- name: aarch64 compilation and consistency checks
|
||||
dist: xenial
|
||||
arch: arm64
|
||||
script:
|
||||
# aarch64
|
||||
- CPPFLAGS=-DXXH_VECTOR=0 LDFLAGS=-static make check # Scalar code path
|
||||
# NEON (64-bit)
|
||||
- make clean
|
||||
- CPPFLAGS=-DXXH_VECTOR=3 LDFLAGS=-static make check # NEON code path
|
||||
|
||||
# We need Bionic here because the QEMU versions shipped in the older repos
|
||||
# do not support POWER8 emulation, and compiling QEMU from source is a pain.
|
||||
- name: PowerPC + PPC64 compilation and consistency checks (Qemu on Bionic)
|
||||
dist: bionic
|
||||
arch: amd64
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- qemu-system-ppc
|
||||
- qemu-user-static
|
||||
- gcc-powerpc-linux-gnu
|
||||
- gcc-powerpc64-linux-gnu
|
||||
- libc6-dev-powerpc-cross
|
||||
- libc6-dev-ppc64-cross
|
||||
script:
|
||||
- CC=powerpc-linux-gnu-gcc RUN_ENV=qemu-ppc-static LDFLAGS=-static make check # Scalar code path
|
||||
- make clean
|
||||
- CC=powerpc64-linux-gnu-gcc RUN_ENV=qemu-ppc64-static CPPFLAGS=-DXXH_VECTOR=0 CFLAGS="-O3" LDFLAGS="-static -m64" make check # Scalar code path
|
||||
- make clean
|
||||
# VSX code
|
||||
- CC=powerpc64-linux-gnu-gcc RUN_ENV="qemu-ppc64-static -cpu power8" CFLAGS="-O3 -maltivec -mvsx -mcpu=power8 -mpower8-vector" LDFLAGS="-static -m64" make check # Auto code path
|
||||
- make clean
|
||||
|
||||
- name: PPC64LE compilation and consistency checks
|
||||
dist: xenial
|
||||
arch: ppc64le
|
||||
script:
|
||||
# Scalar (universal) code path
|
||||
- CPPFLAGS=-DXXH_VECTOR=0 LDFLAGS=-static make check
|
||||
# VSX code path (64-bit)
|
||||
- make clean
|
||||
- CPPFLAGS=-DXXH_VECTOR=4 CFLAGS="-O3 -maltivec -mvsx -mpower8-vector -mcpu=power8" LDFLAGS="-static" make check
|
||||
|
||||
- name: IBM s390x compilation and consistency checks
|
||||
dist: bionic
|
||||
arch: s390x
|
||||
script:
|
||||
# Scalar (universal) code path
|
||||
- CPPFLAGS=-DXXH_VECTOR=0 LDFLAGS=-static make check
|
||||
# s390x code path (64-bit)
|
||||
- make clean
|
||||
- CPPFLAGS=-DXXH_VECTOR=4 CFLAGS="-O3 -march=arch11 -mzvector" LDFLAGS="-static" make check
|
||||
|
||||
- name: cmake build test
|
||||
script:
|
||||
- cd cmake_unofficial
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake ..
|
||||
- make
|
||||
|
||||
@@ -1,3 +1,76 @@
|
||||
v0.8.3
|
||||
- fix : variant `XXH3_128bits_withSecretandSeed()` could produce an invalid result in some specific set of conditions, #894 by @hltj
|
||||
- cli : vector extension detected at runtime on x86/x64, enabled by default
|
||||
- cli : new commands `--filelist` and `--files-from`, by @Ian-Clowes
|
||||
- cli : XXH3 64-bits GNU format can now be generated and checked (command `-H3`)
|
||||
- portability: LoongArch SX SIMD extension, by @lrzlin
|
||||
- portability: can build on AIX, suggested by @likema
|
||||
- portability: validated for SPARC cpus
|
||||
|
||||
v0.8.2
|
||||
- fix : XXH3 S390x vector implementation (@hzhuang1)
|
||||
- fix : PowerPC vector compilation with IBM XL compiler (@MaxiBoether)
|
||||
- perf : improved WASM speed by x2/x3 using SIMD128 (@easyaspi314)
|
||||
- perf : improved speed (+20%) for XXH3 on ARM NEON (@easyaspi314)
|
||||
- cli : Fix filename contain /LF character (@t-mat)
|
||||
- cli : Support # comment lines in --check files (@t-mat)
|
||||
- cli : Support commands --binary and --ignore-missing (@t-mat)
|
||||
- build: fix -Og compilation (@easyaspi314, @t-mat)
|
||||
- build: fix pkgconfig generation with cmake (@ilya-fedin)
|
||||
- build: fix icc compilation
|
||||
- build: fix cmake install directories
|
||||
- build: new build options XXH_NO_XXH3, XXH_SIZE_OPT and XXH_NO_STREAM to reduce binary size (@easyaspi314)
|
||||
- build: dedicated install targets (@ffontaine)
|
||||
- build: support DISPATCH mode in cmake (@hzhuang1)
|
||||
- portability: fix x86dispatch when building with Visual + clang-cl (@t-mat)
|
||||
- portability: SVE vector implementation of XXH3 (@hzhuang1)
|
||||
- portability: compatibility with freestanding environments, using XXH_NO_STDLIB
|
||||
- portability: can build on Haiku (@Begasus)
|
||||
- portability: validated on m68k and risc-v
|
||||
- doc : XXH3 specification (@Adrien1018)
|
||||
- doc : improved doxygen documentation (@easyaspi314, @t-mat)
|
||||
- misc : dedicated sanity test binary (@t-mat)
|
||||
|
||||
v0.8.1
|
||||
- perf : much improved performance for XXH3 streaming variants, notably on gcc and msvc
|
||||
- perf : improved XXH64 speed and latency on small inputs
|
||||
- perf : small XXH32 speed and latency improvement on small inputs of random size
|
||||
- perf : minor stack usage improvement for XXH32 and XXH64
|
||||
- api : new experimental variants XXH3_*_withSecretandSeed()
|
||||
- api : update XXH3_generateSecret(), can no generate secret of any size (>= XXH3_SECRET_SIZE_MIN)
|
||||
- cli : xxhsum can now generate and check XXH3 checksums, using command `-H3`
|
||||
- build: can build xxhash without XXH3, with new build macro XXH_NO_XXH3
|
||||
- build: fix xxh_x86dispatch build with MSVC, by @apankrat
|
||||
- build: XXH_INLINE_ALL can always be used safely, even after XXH_NAMESPACE or a previous XXH_INLINE_ALL
|
||||
- build: improved PPC64LE vector support, by @mpe
|
||||
- install: fix pkgconfig, by @ellert
|
||||
- install: compatibility with Haiku, by @Begasus
|
||||
- doc : code comments made compatible with doxygen, by @easyaspi314
|
||||
- misc : XXH_ACCEPT_NULL_INPUT_POINTER is no longer necessary, all functions can accept NULL input pointers, as long as size == 0
|
||||
- misc : complete refactor of CI tests on Github Actions, offering much larger coverage, by @t-mat
|
||||
- misc : xxhsum code base split into multiple specialized units, within directory cli/, by @easyaspi314
|
||||
|
||||
v0.8.0
|
||||
- api : stabilize XXH3
|
||||
- cli : xxhsum can parse BSD-style --check lines, by @WayneD
|
||||
- cli : `xxhsum -` accepts console input, requested by @jaki
|
||||
- cli : xxhsum accepts -- separator, by @jaki
|
||||
- cli : fix : print correct default algo for symlinked helpers, by @martinetd
|
||||
- install: improved pkgconfig script, allowing custom install locations, requested by @ellert
|
||||
|
||||
v0.7.4
|
||||
- perf: automatic vector detection and selection at runtime (`xxh_x86dispatch.h`), initiated by @easyaspi314
|
||||
- perf: added AVX512 support, by @gzm55
|
||||
- api : new: secret generator `XXH_generateSecret()`, suggested by @koraa
|
||||
- api : fix: XXH3_state_t is movable, identified by @koraa
|
||||
- api : fix: state is correctly aligned in AVX mode (unlike `malloc()`), by @easyaspi314
|
||||
- api : fix: streaming generated wrong values in some combination of random ingestion lengths, reported by @WayneD
|
||||
- cli : fix unicode print on Windows, by @easyaspi314
|
||||
- cli : can `-c` check file generated by sfv
|
||||
- build: `make DISPATCH=1` generates `xxhsum` and `libxxhash` with runtime vector detection (x86/x64 only)
|
||||
- install: cygwin installation support
|
||||
- doc : Cryptol specification of XXH32 and XXH64, by @weaversa
|
||||
|
||||
v0.7.3
|
||||
- perf: improved speed for large inputs (~+20%)
|
||||
- perf: improved latency for small inputs (~10%)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# Doxygen config for xxHash
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
|
||||
PROJECT_NAME = "xxHash"
|
||||
PROJECT_NUMBER = "0.8.2"
|
||||
PROJECT_BRIEF = "Extremely fast non-cryptographic hash function"
|
||||
OUTPUT_DIRECTORY = doxygen
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# We already separate the internal docs.
|
||||
INTERNAL_DOCS = NO
|
||||
# Consistency
|
||||
SORT_MEMBER_DOCS = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
|
||||
# Warnings
|
||||
QUIET = YES
|
||||
# Until we document everything
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
|
||||
# TODO: Add the other files. It is just xxhash.h for now.
|
||||
FILE_PATTERNS = xxhash.h xxh_x86dispatch.c
|
||||
# Note: xxHash's source files are technically ASCII only.
|
||||
INPUT_ENCODING = UTF-8
|
||||
TAB_SIZE = 4
|
||||
MARKDOWN_SUPPORT = YES
|
||||
|
||||
# xxHash is a C library
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
# We hide private part from public document
|
||||
EXTRACT_STATIC = NO
|
||||
# We hide private part from public document
|
||||
EXTRACT_PRIVATE = NO
|
||||
# Document the macros
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
# Predefine some macros to clean up the output.
|
||||
PREDEFINED = "XXH_DOXYGEN=" \
|
||||
"XXH_PUBLIC_API=" \
|
||||
"XXH_NOESCAPE=" \
|
||||
"XXH_FORCE_INLINE=static inline" \
|
||||
"XXH_NO_INLINE=static" \
|
||||
"XXH_RESTRICT=restrict" \
|
||||
"XSUM_API=" \
|
||||
"XXH_STATIC_LINKING_ONLY" \
|
||||
"XXH_IMPLEMENTATION" \
|
||||
"XXH_PUREF=[[gnu::pure]]" \
|
||||
"XXH_CONSTF=[[gnu::const]]" \
|
||||
"XXH_MALLOCF=[[gnu::malloc]]" \
|
||||
"XXH_ALIGN(N)=alignas(N)" \
|
||||
"XXH_ALIGN_MEMBER(align,type)=alignas(align) type"
|
||||
|
||||
# We want HTML docs
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
# Tweak the colors a bit
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_GAMMA = 100
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
|
||||
# We don't want LaTeX.
|
||||
GENERATE_LATEX = NO
|
||||
@@ -0,0 +1,64 @@
|
||||
# Doxygen config for xxHash
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
|
||||
PROJECT_NAME = "xxHash"
|
||||
PROJECT_NUMBER = "0.8.2"
|
||||
PROJECT_BRIEF = "Extremely fast non-cryptographic hash function"
|
||||
OUTPUT_DIRECTORY = doxygen
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# We already separate the internal docs.
|
||||
INTERNAL_DOCS = YES
|
||||
# Consistency
|
||||
SORT_MEMBER_DOCS = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
|
||||
# Warnings
|
||||
QUIET = YES
|
||||
# Until we document everything
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
|
||||
# TODO: Add the other files. It is just xxhash.h for now.
|
||||
FILE_PATTERNS = xxhash.h xxh_x86dispatch.c
|
||||
# Note: xxHash's source files are technically ASCII only.
|
||||
INPUT_ENCODING = UTF-8
|
||||
TAB_SIZE = 4
|
||||
MARKDOWN_SUPPORT = YES
|
||||
|
||||
# xxHash is a C library
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
# So we can document the internals
|
||||
EXTRACT_STATIC = YES
|
||||
# We show private part in the internal document
|
||||
EXTRACT_PRIVATE = YES
|
||||
# Document the macros
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
# Predefine some macros to clean up the output.
|
||||
PREDEFINED = "XXH_DOXYGEN=" \
|
||||
"XXH_PUBLIC_API=" \
|
||||
"XXH_NOESCAPE=" \
|
||||
"XXH_FORCE_INLINE=static inline" \
|
||||
"XXH_NO_INLINE=static" \
|
||||
"XXH_RESTRICT=restrict" \
|
||||
"XSUM_API=" \
|
||||
"XXH_STATIC_LINKING_ONLY" \
|
||||
"XXH_IMPLEMENTATION" \
|
||||
"XXH_PUREF=[[gnu::pure]]" \
|
||||
"XXH_CONSTF=[[gnu::const]]" \
|
||||
"XXH_MALLOCF=[[gnu::malloc]]" \
|
||||
"XXH_ALIGN(N)=alignas(N)" \
|
||||
"XXH_ALIGN_MEMBER(align,type)=alignas(align) type"
|
||||
|
||||
# We want HTML docs
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
# Tweak the colors a bit
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_GAMMA = 100
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
|
||||
# We don't want LaTeX.
|
||||
GENERATE_LATEX = NO
|
||||
@@ -1,5 +1,5 @@
|
||||
xxHash Library
|
||||
Copyright (c) 2012-present, Yann Collet
|
||||
Copyright (c) 2012-2021 Yann Collet
|
||||
All rights reserved.
|
||||
|
||||
BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
|
||||
@@ -24,25 +24,3 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------
|
||||
|
||||
xxhsum command line interface
|
||||
Copyright (c) 2013-present, Yann Collet
|
||||
All rights reserved.
|
||||
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
+387
-105
@@ -1,6 +1,6 @@
|
||||
# ################################################################
|
||||
# xxHash Makefile
|
||||
# Copyright (C) Yann Collet 2012-present
|
||||
# Copyright (C) 2012-2024 Yann Collet
|
||||
#
|
||||
# GPL v2 License
|
||||
#
|
||||
@@ -24,11 +24,14 @@
|
||||
# ################################################################
|
||||
# xxhsum: provides 32/64 bits hash of one or multiple files, or stdin
|
||||
# ################################################################
|
||||
Q = $(if $(filter 1,$(V) $(VERBOSE)),,@)
|
||||
|
||||
# Version numbers
|
||||
LIBVER_MAJOR_SCRIPT:=`sed -n '/define XXH_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < xxhash.h`
|
||||
LIBVER_MINOR_SCRIPT:=`sed -n '/define XXH_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < xxhash.h`
|
||||
LIBVER_PATCH_SCRIPT:=`sed -n '/define XXH_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < xxhash.h`
|
||||
SED ?= sed
|
||||
SED_ERE_OPT ?= -E
|
||||
LIBVER_MAJOR_SCRIPT:=`$(SED) -n '/define XXH_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < xxhash.h`
|
||||
LIBVER_MINOR_SCRIPT:=`$(SED) -n '/define XXH_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < xxhash.h`
|
||||
LIBVER_PATCH_SCRIPT:=`$(SED) -n '/define XXH_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < xxhash.h`
|
||||
LIBVER_MAJOR := $(shell echo $(LIBVER_MAJOR_SCRIPT))
|
||||
LIBVER_MINOR := $(shell echo $(LIBVER_MINOR_SCRIPT))
|
||||
LIBVER_PATCH := $(shell echo $(LIBVER_PATCH_SCRIPT))
|
||||
@@ -40,9 +43,10 @@ DEBUGFLAGS+=-Wall -Wextra -Wconversion -Wcast-qual -Wcast-align -Wshadow \
|
||||
-Wstrict-prototypes -Wundef -Wpointer-arith -Wformat-security \
|
||||
-Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
|
||||
-Wredundant-decls -Wstrict-overflow=2
|
||||
CFLAGS += $(DEBUGFLAGS)
|
||||
FLAGS = $(CFLAGS) $(CPPFLAGS) $(MOREFLAGS)
|
||||
CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
|
||||
FLAGS = $(CFLAGS) $(CPPFLAGS)
|
||||
XXHSUM_VERSION = $(LIBVER)
|
||||
UNAME := $(shell uname)
|
||||
|
||||
# Define *.exe as extension for Windows systems
|
||||
ifneq (,$(filter Windows%,$(OS)))
|
||||
@@ -51,9 +55,23 @@ else
|
||||
EXT =
|
||||
endif
|
||||
|
||||
# automatically enable runtime vector dispatch on x86/64 targets
|
||||
detect_x86_arch = $(shell $(CC) -dumpmachine | grep -E 'i[3-6]86|x86_64')
|
||||
ifneq ($(strip $(call detect_x86_arch)),)
|
||||
#note: can be overridden at compile time, by setting DISPATCH=0
|
||||
DISPATCH ?= 1
|
||||
endif
|
||||
|
||||
ifeq ($(NODE_JS),1)
|
||||
# Link in unrestricted filesystem support
|
||||
LDFLAGS += -sNODERAWFS
|
||||
# Set flag to fix isatty() support
|
||||
CPPFLAGS += -DXSUM_NODE_JS=1
|
||||
endif
|
||||
|
||||
# OS X linker doesn't support -soname, and use different extension
|
||||
# see: https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html
|
||||
ifeq ($(shell uname), Darwin)
|
||||
ifeq ($(UNAME), Darwin)
|
||||
SHARED_EXT = dylib
|
||||
SHARED_EXT_MAJOR = $(LIBVER_MAJOR).$(SHARED_EXT)
|
||||
SHARED_EXT_VER = $(LIBVER).$(SHARED_EXT)
|
||||
@@ -67,36 +85,60 @@ endif
|
||||
|
||||
LIBXXH = libxxhash.$(SHARED_EXT_VER)
|
||||
|
||||
XXHSUM_SRC_DIR = cli
|
||||
XXHSUM_SPLIT_SRCS = $(XXHSUM_SRC_DIR)/xxhsum.c \
|
||||
$(XXHSUM_SRC_DIR)/xsum_os_specific.c \
|
||||
$(XXHSUM_SRC_DIR)/xsum_arch.c \
|
||||
$(XXHSUM_SRC_DIR)/xsum_output.c \
|
||||
$(XXHSUM_SRC_DIR)/xsum_sanity_check.c \
|
||||
$(XXHSUM_SRC_DIR)/xsum_bench.c
|
||||
XXHSUM_SPLIT_OBJS = $(XXHSUM_SPLIT_SRCS:.c=.o)
|
||||
XXHSUM_HEADERS = $(XXHSUM_SRC_DIR)/xsum_config.h \
|
||||
$(XXHSUM_SRC_DIR)/xsum_arch.h \
|
||||
$(XXHSUM_SRC_DIR)/xsum_os_specific.h \
|
||||
$(XXHSUM_SRC_DIR)/xsum_output.h \
|
||||
$(XXHSUM_SRC_DIR)/xsum_sanity_check.h \
|
||||
$(XXHSUM_SRC_DIR)/xsum_bench.h
|
||||
|
||||
## generate CLI and libraries in release mode (default for `make`)
|
||||
.PHONY: default
|
||||
default: ## generate CLI and libraries in release mode (default for `make`)
|
||||
default: DEBUGFLAGS=
|
||||
default: lib xxhsum_and_links
|
||||
|
||||
.PHONY: all
|
||||
all: lib xxhsum xxhsum_inlinedXXH
|
||||
|
||||
xxhsum: xxhash.o xxhsum.o ## generate command line interface (CLI)
|
||||
## xxhsum is the command line interface (CLI)
|
||||
ifeq ($(DISPATCH),1)
|
||||
xxhsum: CPPFLAGS += -DXXHSUM_DISPATCH=1
|
||||
xxhsum: xxh_x86dispatch.o
|
||||
endif
|
||||
xxhsum: xxhash.o $(XXHSUM_SPLIT_OBJS)
|
||||
$(CC) $(FLAGS) $^ $(LDFLAGS) -o $@$(EXT)
|
||||
|
||||
xxhsum32: CFLAGS += -m32 ## generate CLI in 32-bits mode
|
||||
xxhsum32: xxhash.c xxhsum.c ## do not generate object (avoid mixing different ABI)
|
||||
xxhsum32: xxhash.c $(XXHSUM_SPLIT_SRCS) ## do not generate object (avoid mixing different ABI)
|
||||
$(CC) $(FLAGS) $^ $(LDFLAGS) -o $@$(EXT)
|
||||
|
||||
xxhash.o: xxhash.c xxhash.h xxh3.h
|
||||
$(CC) $(FLAGS) -c $< -o $@
|
||||
xxhsum.o: xxhsum.c xxhash.h
|
||||
$(CC) $(FLAGS) -c $< -o $@
|
||||
## dispatch only works for x86/x64 systems
|
||||
dispatch: CPPFLAGS += -DXXHSUM_DISPATCH=1
|
||||
dispatch: xxhash.o xxh_x86dispatch.o $(XXHSUM_SPLIT_SRCS)
|
||||
$(CC) $(FLAGS) $^ $(LDFLAGS) -o $@$(EXT)
|
||||
|
||||
xxhash.o: xxhash.c xxhash.h
|
||||
xxhsum.o: $(XXHSUM_SRC_DIR)/xxhsum.c $(XXHSUM_HEADERS) \
|
||||
xxhash.h xxh_x86dispatch.h
|
||||
xxh_x86dispatch.o: xxh_x86dispatch.c xxh_x86dispatch.h xxhash.h
|
||||
|
||||
.PHONY: xxhsum_and_links
|
||||
xxhsum_and_links: xxhsum xxh32sum xxh64sum xxh128sum
|
||||
xxhsum_and_links: xxhsum xxh32sum xxh64sum xxh128sum xxh3sum
|
||||
|
||||
xxh32sum xxh64sum xxh128sum: xxhsum
|
||||
xxh32sum xxh64sum xxh128sum xxh3sum: xxhsum
|
||||
ln -sf $<$(EXT) $@$(EXT)
|
||||
|
||||
xxhsum_inlinedXXH: CPPFLAGS += -DXXH_INLINE_ALL
|
||||
xxhsum_inlinedXXH: xxhsum.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
xxhsum_inlinedXXH: $(XXHSUM_SPLIT_SRCS)
|
||||
$(CC) $(FLAGS) $< -o $@$(EXT)
|
||||
|
||||
|
||||
# library
|
||||
@@ -109,6 +151,9 @@ $(LIBXXH): LDFLAGS += -shared
|
||||
ifeq (,$(filter Windows%,$(OS)))
|
||||
$(LIBXXH): CFLAGS += -fPIC
|
||||
endif
|
||||
ifeq ($(LIBXXH_DISPATCH),1)
|
||||
$(LIBXXH): xxh_x86dispatch.c
|
||||
endif
|
||||
$(LIBXXH): xxhash.c
|
||||
$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@
|
||||
ln -sf $@ libxxhash.$(SHARED_EXT_MAJOR)
|
||||
@@ -122,33 +167,35 @@ libxxhash: $(LIBXXH)
|
||||
lib: ## generate static and dynamic xxhash libraries
|
||||
lib: libxxhash.a libxxhash
|
||||
|
||||
pkgconfig:
|
||||
@sed -e 's|@PREFIX@|$(PREFIX)|' \
|
||||
-e 's|@VERSION@|$(LIBVER)|' \
|
||||
libxxhash.pc.in >libxxhash.pc
|
||||
|
||||
# helper targets
|
||||
|
||||
AWK = awk
|
||||
AWK = awk
|
||||
GREP = grep
|
||||
SORT = sort
|
||||
NM = nm
|
||||
|
||||
.PHONY: list
|
||||
list: ## list all Makefile targets
|
||||
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | $(AWK) -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | $(SORT) | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
|
||||
$(Q)$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | $(AWK) -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | $(SORT) | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
|
||||
|
||||
.PHONY: help
|
||||
help: ## list documented targets
|
||||
@$(GREP) -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||
$(Q)$(GREP) -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||
$(SORT) | \
|
||||
$(AWK) 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## remove all build artifacts
|
||||
@$(RM) -r *.dSYM # Mac OS-X specific
|
||||
@$(RM) core *.o *.$(SHARED_EXT) *.$(SHARED_EXT).* *.a libxxhash.pc
|
||||
@$(RM) xxhsum$(EXT) xxhsum32$(EXT) xxhsum_inlinedXXH$(EXT)
|
||||
@$(RM) xxh32sum$(EXT) xxh64sum$(EXT) xxh128sum$(EXT)
|
||||
$(Q)$(RM) -r *.dSYM # Mac OS-X specific
|
||||
$(Q)$(RM) core *.o *.obj *.$(SHARED_EXT) *.$(SHARED_EXT).* *.a libxxhash.pc
|
||||
$(Q)$(RM) xxhsum$(EXT) xxhsum32$(EXT) xxhsum_inlinedXXH$(EXT) dispatch$(EXT)
|
||||
$(Q)$(RM) xxhsum.wasm xxhsum.js xxhsum.html
|
||||
$(Q)$(RM) xxh32sum$(EXT) xxh64sum$(EXT) xxh128sum$(EXT) xxh3sum$(EXT)
|
||||
$(Q)$(RM) fuzzer
|
||||
$(Q)$(RM) $(XXHSUM_SRC_DIR)/*.o $(XXHSUM_SRC_DIR)/*.obj
|
||||
$(MAKE) -C tests clean
|
||||
$(MAKE) -C tests/bench clean
|
||||
$(MAKE) -C tests/collisions clean
|
||||
@echo cleaning completed
|
||||
|
||||
|
||||
@@ -159,63 +206,147 @@ clean: ## remove all build artifacts
|
||||
# make check can be run with cross-compiled binaries on emulated environments (qemu user mode)
|
||||
# by setting $(RUN_ENV) to the target emulation environment
|
||||
.PHONY: check
|
||||
check: xxhsum ## basic tests for xxhsum CLI, set RUN_ENV for emulated environments
|
||||
check: xxhsum test_sanity ## basic tests for xxhsum CLI, set RUN_ENV for emulated environments
|
||||
# stdin
|
||||
# If you get "Wrong parameters" on Emscripten+Node.js, recompile with `NODE_JS=1`
|
||||
$(RUN_ENV) ./xxhsum$(EXT) < xxhash.c
|
||||
# multiple files
|
||||
$(RUN_ENV) ./xxhsum$(EXT) xxhash.* xxhsum.*
|
||||
$(RUN_ENV) ./xxhsum$(EXT) xxhash.*
|
||||
# internal bench
|
||||
$(RUN_ENV) ./xxhsum$(EXT) -bi1
|
||||
$(RUN_ENV) ./xxhsum$(EXT) -bi0
|
||||
# long bench command
|
||||
$(RUN_ENV) ./xxhsum$(EXT) --benchmark-all -i0
|
||||
# bench multiple variants
|
||||
$(RUN_ENV) ./xxhsum$(EXT) -b1,2,3 -i0
|
||||
# file bench
|
||||
$(RUN_ENV) ./xxhsum$(EXT) -bi1 xxhash.c
|
||||
$(RUN_ENV) ./xxhsum$(EXT) -bi0 xxhash.c
|
||||
# 32-bit
|
||||
$(RUN_ENV) ./xxhsum$(EXT) -H0 xxhash.c
|
||||
# 128-bit
|
||||
$(RUN_ENV) ./xxhsum$(EXT) -H2 xxhash.c
|
||||
# XXH3 (enforce BSD style)
|
||||
$(RUN_ENV) ./xxhsum$(EXT) -H3 xxhash.c | grep "XXH3"
|
||||
# request incorrect variant
|
||||
$(RUN_ENV) ./xxhsum$(EXT) -H9 xxhash.c ; test $$? -eq 1
|
||||
@printf "\n ....... checks completed successfully ....... \n"
|
||||
|
||||
.PHONY: test-unicode
|
||||
test-unicode:
|
||||
$(MAKE) -C tests test_unicode
|
||||
|
||||
.PHONY: test_sanity
|
||||
test_sanity:
|
||||
$(MAKE) -C tests test_sanity
|
||||
|
||||
.PHONY: test-mem
|
||||
VALGRIND = valgrind --leak-check=yes --error-exitcode=1
|
||||
test-mem: RUN_ENV = $(VALGRIND)
|
||||
test-mem: xxhsum check
|
||||
|
||||
.PHONY: test32
|
||||
test32: clean xxhsum32
|
||||
test32: xxhsum32
|
||||
@echo ---- test 32-bit ----
|
||||
./xxhsum32 -bi1 xxhash.c
|
||||
./xxhsum32 -bi0 xxhash.c
|
||||
|
||||
TEST_FILES = xxhsum$(EXT) xxhash.c xxhash.h
|
||||
.PHONY: test-xxhsum-c
|
||||
test-xxhsum-c: xxhsum
|
||||
# xxhsum to/from pipe
|
||||
./xxhsum xxh* | ./xxhsum -c -
|
||||
./xxhsum -H0 xxh* | ./xxhsum -c -
|
||||
./xxhsum $(TEST_FILES) | ./xxhsum -c -
|
||||
./xxhsum -H0 $(TEST_FILES) | ./xxhsum -c -
|
||||
# xxhsum -c is unable to verify checksum of file from STDIN (#470)
|
||||
./xxhsum < README.md > .test.README.md.xxh
|
||||
./xxhsum -c .test.README.md.xxh < README.md
|
||||
# xxhsum -q does not display "Loading" message into stderr (#251)
|
||||
! ./xxhsum -q xxh* 2>&1 | grep Loading
|
||||
! ./xxhsum -q $(TEST_FILES) 2>&1 | grep Loading
|
||||
# xxhsum does not display "Loading" message into stderr either
|
||||
! ./xxhsum $(TEST_FILES) 2>&1 | grep Loading
|
||||
# Check that xxhsum do display filename that it failed to open.
|
||||
LC_ALL=C ./xxhsum nonexistent 2>&1 | grep "Error: Could not open 'nonexistent'"
|
||||
# xxhsum to/from file, shell redirection
|
||||
./xxhsum xxh* > .test.xxh64
|
||||
./xxhsum -H0 xxh* > .test.xxh32
|
||||
./xxhsum -H2 xxh* > .test.xxh128
|
||||
./xxhsum -c .test.xxh64
|
||||
./xxhsum -c .test.xxh32
|
||||
./xxhsum -c .test.xxh128
|
||||
./xxhsum $(TEST_FILES) > .test.xxh64
|
||||
./xxhsum --tag $(TEST_FILES) > .test.xxh64_tag
|
||||
./xxhsum --little-endian $(TEST_FILES) > .test.le_xxh64
|
||||
./xxhsum --tag --little-endian $(TEST_FILES) > .test.le_xxh64_tag
|
||||
./xxhsum -H0 $(TEST_FILES) > .test.xxh32
|
||||
./xxhsum -H0 --tag $(TEST_FILES) > .test.xxh32_tag
|
||||
./xxhsum -H0 --little-endian $(TEST_FILES) > .test.le_xxh32
|
||||
./xxhsum -H0 --tag --little-endian $(TEST_FILES) > .test.le_xxh32_tag
|
||||
./xxhsum -H2 $(TEST_FILES) > .test.xxh128
|
||||
./xxhsum -H2 --tag $(TEST_FILES) > .test.xxh128_tag
|
||||
./xxhsum -H2 --little-endian $(TEST_FILES) > .test.le_xxh128
|
||||
./xxhsum -H2 --tag --little-endian $(TEST_FILES) > .test.le_xxh128_tag
|
||||
./xxhsum -H3 $(TEST_FILES) > .test.xxh3
|
||||
./xxhsum -H3 --tag $(TEST_FILES) > .test.xxh3_tag
|
||||
./xxhsum -H3 --little-endian $(TEST_FILES) > .test.le_xxh3
|
||||
./xxhsum -H3 --tag --little-endian $(TEST_FILES) > .test.le_xxh3_tag
|
||||
./xxhsum -c .test.xxh*
|
||||
./xxhsum -c --little-endian .test.le_xxh*
|
||||
./xxhsum -c .test.*_tag
|
||||
# read list of files from stdin
|
||||
./xxhsum -c < .test.xxh64
|
||||
./xxhsum -c < .test.xxh32
|
||||
./xxhsum -c < .test.xxh64
|
||||
./xxhsum -c < .test.xxh128
|
||||
./xxhsum -c < .test.xxh3
|
||||
cat .test.xxh* | ./xxhsum -c -
|
||||
# check variant with '*' marker as second separator
|
||||
$(SED) 's/ / \*/' .test.xxh32 | ./xxhsum -c
|
||||
# bsd-style output
|
||||
./xxhsum --tag xxhsum* | $(GREP) XXH64
|
||||
./xxhsum --tag -H0 xxhsum* | $(GREP) XXH32
|
||||
./xxhsum --tag -H1 xxhsum* | $(GREP) XXH64
|
||||
./xxhsum --tag -H2 xxhsum* | $(GREP) XXH128
|
||||
./xxhsum --tag -H3 xxhsum* | $(GREP) XXH3
|
||||
./xxhsum -H3 xxhsum* | $(GREP) XXH3_ # prefix for GNU format
|
||||
./xxhsum --tag -H32 xxhsum* | $(GREP) XXH32
|
||||
./xxhsum --tag -H64 xxhsum* | $(GREP) XXH64
|
||||
./xxhsum --tag -H128 xxhsum* | $(GREP) XXH128
|
||||
./xxhsum --tag -H0 --little-endian xxhsum* | $(GREP) XXH32_LE
|
||||
./xxhsum --tag -H1 --little-endian xxhsum* | $(GREP) XXH64_LE
|
||||
./xxhsum --tag -H2 --little-endian xxhsum* | $(GREP) XXH128_LE
|
||||
./xxhsum --tag -H3 --little-endian xxhsum* | $(GREP) XXH3_LE
|
||||
./xxhsum --tag -H32 --little-endian xxhsum* | $(GREP) XXH32_LE
|
||||
./xxhsum --tag -H64 --little-endian xxhsum* | $(GREP) XXH64_LE
|
||||
./xxhsum --tag -H128 --little-endian xxhsum* | $(GREP) XXH128_LE
|
||||
# check bsd-style
|
||||
./xxhsum --tag xxhsum* | ./xxhsum -c
|
||||
./xxhsum --tag -H32 --little-endian xxhsum* | ./xxhsum -c
|
||||
# xxhsum -c warns improperly format lines.
|
||||
cat .test.xxh64 .test.xxh32 | ./xxhsum -c - | $(GREP) improperly
|
||||
cat .test.xxh32 .test.xxh64 | ./xxhsum -c - | $(GREP) improperly
|
||||
echo '12345678 ' >>.test.xxh32
|
||||
./xxhsum -c .test.xxh32 | $(GREP) improperly
|
||||
echo '123456789 file' >>.test.xxh64
|
||||
./xxhsum -c .test.xxh64 | $(GREP) improperly
|
||||
# Expects "FAILED"
|
||||
echo "0000000000000000 LICENSE" | ./xxhsum -c -; test $$? -eq 1
|
||||
echo "00000000 LICENSE" | ./xxhsum -c -; test $$? -eq 1
|
||||
# Expects "FAILED open or read"
|
||||
echo "0000000000000000 test-expects-file-not-found" | ./xxhsum -c -; test $$? -eq 1
|
||||
echo "00000000 test-expects-file-not-found" | ./xxhsum -c -; test $$? -eq 1
|
||||
@$(RM) .test.xxh32 .test.xxh64 .test.xxh128
|
||||
# --filelist
|
||||
echo xxhash.c > .test.filenames
|
||||
$(RUN_ENV) ./xxhsum$(EXT) --filelist .test.filenames
|
||||
# --filelist from stdin
|
||||
cat .test.filenames | $(RUN_ENV) ./xxhsum$(EXT) --filelist
|
||||
@$(RM) .test.*
|
||||
|
||||
LIB_FUZZING_ENGINE?="-fsanitize=fuzzer"
|
||||
CC_VERSION := $(shell $(CC) --version)
|
||||
ifneq (,$(findstring clang,$(CC_VERSION)))
|
||||
fuzzer: libxxhash.a fuzz/fuzzer.c
|
||||
$(CC) $(CFLAGS) $(LIB_FUZZING_ENGINE) -I. -o fuzzer fuzz/fuzzer.c -L. -Wl,-Bstatic -lxxhash -Wl,-Bdynamic
|
||||
endif
|
||||
|
||||
.PHONY: test-filename-escape
|
||||
test-filename-escape:
|
||||
$(MAKE) -C tests test_filename_escape
|
||||
|
||||
.PHONY: test-cli-comment-line
|
||||
test-cli-comment-line:
|
||||
$(MAKE) -C tests test_cli_comment_line
|
||||
|
||||
.PHONY: test-cli-ignore-missing
|
||||
test-cli-ignore-missing:
|
||||
$(MAKE) -C tests test_cli_ignore_missing
|
||||
|
||||
.PHONY: armtest
|
||||
armtest: clean
|
||||
@@ -227,11 +358,18 @@ clangtest: clean
|
||||
@echo ---- test clang compilation ----
|
||||
CC=clang MOREFLAGS="-Werror -Wconversion -Wno-sign-conversion" $(MAKE) all
|
||||
|
||||
.PHONY: gcc-og-test
|
||||
gcc-og-test: clean
|
||||
@echo ---- test gcc -Og compilation ----
|
||||
CFLAGS="-Og -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror -fPIC" CPPFLAGS="-DXXH_NO_INLINE_HINTS" MOREFLAGS="-Werror" $(MAKE) all
|
||||
|
||||
.PHONY: cxxtest
|
||||
cxxtest: clean
|
||||
@echo ---- test C++ compilation ----
|
||||
CC="$(CXX) -Wno-deprecated" $(MAKE) all CFLAGS="-O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror -fPIC"
|
||||
|
||||
# In strict C90 mode, there is no `long long` type support,
|
||||
# consequently, only XXH32 can be compiled.
|
||||
.PHONY: c90test
|
||||
ifeq ($(NO_C90_TEST),true)
|
||||
c90test:
|
||||
@@ -242,10 +380,41 @@ c90test: CFLAGS += -std=c90 -Werror -pedantic
|
||||
c90test: xxhash.c
|
||||
@echo ---- test strict C90 compilation [xxh32 only] ----
|
||||
$(RM) xxhash.o
|
||||
$(CC) $(FLAGS) $^ $(LDFLAGS) -c
|
||||
$(CC) $(FLAGS) $^ -c
|
||||
$(NM) xxhash.o | $(GREP) XXH64 ; test $$? -eq 1
|
||||
$(RM) xxhash.o
|
||||
endif
|
||||
|
||||
.PHONY: noxxh3test
|
||||
noxxh3test: CPPFLAGS += -DXXH_NO_XXH3
|
||||
noxxh3test: CFLAGS += -Werror -pedantic -Wno-long-long # XXH64 requires long long support
|
||||
noxxh3test: OFILE = xxh_noxxh3.o
|
||||
noxxh3test: xxhash.c
|
||||
@echo ---- test compilation without XXH3 ----
|
||||
$(CC) $(FLAGS) -c $^ -o $(OFILE)
|
||||
$(NM) $(OFILE) | $(GREP) XXH3_ ; test $$? -eq 1
|
||||
$(RM) $(OFILE)
|
||||
|
||||
.PHONY: nostreamtest
|
||||
nostreamtest: CPPFLAGS += -DXXH_NO_STREAM
|
||||
nostreamtest: CFLAGS += -Werror -pedantic -Wno-long-long # XXH64 requires long long support
|
||||
nostreamtest: OFILE = xxh_nostream.o
|
||||
nostreamtest: xxhash.c
|
||||
@echo ---- test compilation without streaming ----
|
||||
$(CC) $(FLAGS) -c $^ -o $(OFILE)
|
||||
$(NM) $(OFILE) | $(GREP) update ; test $$? -eq 1
|
||||
$(RM) $(OFILE)
|
||||
|
||||
.PHONY: nostdlibtest
|
||||
nostdlibtest: CPPFLAGS += -DXXH_NO_STDLIB
|
||||
nostdlibtest: CFLAGS += -Werror -pedantic -Wno-long-long # XXH64 requires long long support
|
||||
nostdlibtest: OFILE = xxh_nostdlib.o
|
||||
nostdlibtest: xxhash.c
|
||||
@echo ---- test compilation without \<stdlib.h\> ----
|
||||
$(CC) $(FLAGS) -c $^ -o $(OFILE)
|
||||
$(NM) $(OFILE) | $(GREP) "U _free\|U free" ; test $$? -eq 1
|
||||
$(RM) $(OFILE)
|
||||
|
||||
.PHONY: usan
|
||||
usan: CC=clang
|
||||
usan: CXX=clang++
|
||||
@@ -270,16 +439,17 @@ cppcheck: ## check C source files using $(CPPCHECK) static analyzer
|
||||
namespaceTest: ## ensure XXH_NAMESPACE redefines all public symbols
|
||||
$(CC) -c xxhash.c
|
||||
$(CC) -DXXH_NAMESPACE=TEST_ -c xxhash.c -o xxhash2.o
|
||||
$(CC) xxhash.o xxhash2.o xxhsum.c -o xxhsum2 # will fail if one namespace missing (symbol collision)
|
||||
$(CC) xxhash.o xxhash2.o $(XXHSUM_SPLIT_SRCS) -o xxhsum2 # will fail if one namespace missing (symbol collision)
|
||||
$(RM) *.o xxhsum2 # clean
|
||||
|
||||
MAN = $(XXHSUM_SRC_DIR)/xxhsum.1
|
||||
MD2ROFF ?= ronn
|
||||
MD2ROFF_FLAGS ?= --roff --warnings --manual="User Commands" --organization="xxhsum $(XXHSUM_VERSION)"
|
||||
xxhsum.1: xxhsum.1.md xxhash.h
|
||||
cat $< | $(MD2ROFF) $(MD2ROFF_FLAGS) | sed -n '/^\.\\\".*/!p' > $@
|
||||
$(MAN): $(XXHSUM_SRC_DIR)/xxhsum.1.md xxhash.h
|
||||
cat $< | $(MD2ROFF) $(MD2ROFF_FLAGS) | $(SED) -n '/^\.\\\".*/!p' > $@
|
||||
|
||||
.PHONY: man
|
||||
man: xxhsum.1 ## generate man page from markdown source
|
||||
man: $(MAN) ## generate man page from markdown source
|
||||
|
||||
.PHONY: clean-man
|
||||
clean-man:
|
||||
@@ -290,21 +460,69 @@ preview-man: man
|
||||
man ./xxhsum.1
|
||||
|
||||
.PHONY: test
|
||||
test: DEBUGFLAGS += -DDEBUGLEVEL=1
|
||||
test: all namespaceTest check test-xxhsum-c c90test test-tools
|
||||
test: DEBUGFLAGS += -DXXH_DEBUGLEVEL=1
|
||||
test: all namespaceTest check test-xxhsum-c c90test test-tools noxxh3test nostdlibtest
|
||||
|
||||
# this test checks that including "xxhash.h" multiple times and with different directives still compiles properly
|
||||
.PHONY: test-multiInclude
|
||||
test-multiInclude:
|
||||
$(MAKE) -C tests test_multiInclude
|
||||
|
||||
.PHONY: test-inline-notexposed
|
||||
test-inline-notexposed: xxhsum_inlinedXXH
|
||||
$(NM) xxhsum_inlinedXXH | $(GREP) "t _XXH32_" ; test $$? -eq 1 # no XXH32 symbol should be left
|
||||
$(NM) xxhsum_inlinedXXH | $(GREP) "t _XXH64_" ; test $$? -eq 1 # no XXH64 symbol should be left
|
||||
|
||||
.PHONY: test-inline
|
||||
test-inline:
|
||||
$(MAKE) -C tests test_multiInclude
|
||||
test-inline: test-inline-notexposed test-multiInclude
|
||||
|
||||
|
||||
.PHONY: test-all
|
||||
test-all: CFLAGS += -Werror
|
||||
test-all: test test32 clangtest cxxtest usan test-inline listL120 trailingWhitespace staticAnalyze test-unicode
|
||||
test-all: test test32 test-unicode clangtest gcc-og-test cxxtest usan test-inline listL120 trailingWhitespace test-xxh-nnn-sums
|
||||
|
||||
.PHONY: test-tools
|
||||
test-tools:
|
||||
CFLAGS=-Werror $(MAKE) -C tests/bench
|
||||
CFLAGS=-Werror $(MAKE) -C tests/collisions
|
||||
CFLAGS=-Werror $(MAKE) -C tests/collisions check
|
||||
|
||||
.PHONY: test-xxh-nnn-sums
|
||||
test-xxh-nnn-sums: xxhsum_and_links
|
||||
./xxhsum README.md > tmp.xxhsum.out # xxhsum outputs xxh64
|
||||
./xxh32sum README.md > tmp.xxh32sum.out
|
||||
./xxh64sum README.md > tmp.xxh64sum.out
|
||||
./xxh128sum README.md > tmp.xxh128sum.out
|
||||
./xxh3sum README.md > tmp.xxh3sum.out
|
||||
cat tmp.xxhsum.out
|
||||
cat tmp.xxh32sum.out
|
||||
cat tmp.xxh64sum.out
|
||||
cat tmp.xxh128sum.out
|
||||
cat tmp.xxh3sum.out
|
||||
./xxhsum -c tmp.xxhsum.out
|
||||
./xxhsum -c tmp.xxh32sum.out
|
||||
./xxhsum -c tmp.xxh64sum.out
|
||||
./xxhsum -c tmp.xxh128sum.out
|
||||
./xxhsum -c tmp.xxh3sum.out
|
||||
./xxh32sum -c tmp.xxhsum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh32sum -c tmp.xxh32sum.out
|
||||
./xxh32sum -c tmp.xxh64sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh32sum -c tmp.xxh128sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh32sum -c tmp.xxh3sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh64sum -c tmp.xxhsum.out
|
||||
./xxh64sum -c tmp.xxh32sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh64sum -c tmp.xxh64sum.out
|
||||
./xxh64sum -c tmp.xxh128sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh64sum -c tmp.xxh3sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh128sum -c tmp.xxhsum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh128sum -c tmp.xxh32sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh128sum -c tmp.xxh64sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh128sum -c tmp.xxh128sum.out
|
||||
./xxh128sum -c tmp.xxh3sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh3sum -c tmp.xxhsum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh3sum -c tmp.xxh32sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh3sum -c tmp.xxh64sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh3sum -c tmp.xxh128sum.out ; test $$? -eq 1 # expects "no properly formatted"
|
||||
./xxh3sum -c tmp.xxh3sum.out
|
||||
|
||||
.PHONY: listL120
|
||||
listL120: # extract lines >= 120 characters in *.{c,h}, by Takayuki Matsuoka (note: $$, for Makefile compatibility)
|
||||
@@ -312,13 +530,16 @@ listL120: # extract lines >= 120 characters in *.{c,h}, by Takayuki Matsuoka (n
|
||||
|
||||
.PHONY: trailingWhitespace
|
||||
trailingWhitespace:
|
||||
! $(GREP) -E "`printf '[ \\t]$$'`" xxhsum.1 *.c *.h LICENSE Makefile cmake_unofficial/CMakeLists.txt
|
||||
! $(GREP) -E "`printf '[ \\t]$$'`" cli/*.c cli/*.h cli/*.1 *.c *.h LICENSE Makefile cmake_unofficial/CMakeLists.txt
|
||||
|
||||
.PHONY: lint-unicode
|
||||
lint-unicode:
|
||||
./tests/unicode_lint.sh
|
||||
|
||||
# =========================================================
|
||||
# make install is validated only for the following targets
|
||||
# =========================================================
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU Haiku OpenBSD FreeBSD NetBSD DragonFly SunOS CYGWIN% , $(UNAME)))
|
||||
|
||||
DESTDIR ?=
|
||||
# directory variables: GNU conventions prefer lowercase
|
||||
@@ -327,29 +548,30 @@ DESTDIR ?=
|
||||
prefix ?= /usr/local
|
||||
PREFIX ?= $(prefix)
|
||||
exec_prefix ?= $(PREFIX)
|
||||
libdir ?= $(exec_prefix)/lib
|
||||
EXEC_PREFIX ?= $(exec_prefix)
|
||||
libdir ?= $(EXEC_PREFIX)/lib
|
||||
LIBDIR ?= $(libdir)
|
||||
includedir ?= $(PREFIX)/include
|
||||
INCLUDEDIR ?= $(includedir)
|
||||
bindir ?= $(exec_prefix)/bin
|
||||
bindir ?= $(EXEC_PREFIX)/bin
|
||||
BINDIR ?= $(bindir)
|
||||
datarootdir ?= $(PREFIX)/share
|
||||
mandir ?= $(datarootdir)/man
|
||||
man1dir ?= $(mandir)/man1
|
||||
|
||||
ifneq (,$(filter $(shell uname),FreeBSD NetBSD DragonFly))
|
||||
ifneq (,$(filter $(UNAME),FreeBSD NetBSD DragonFly))
|
||||
PKGCONFIGDIR ?= $(PREFIX)/libdata/pkgconfig
|
||||
else
|
||||
PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig
|
||||
endif
|
||||
|
||||
ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
ifneq (,$(filter $(UNAME),OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
MANDIR ?= $(PREFIX)/man/man1
|
||||
else
|
||||
MANDIR ?= $(man1dir)
|
||||
endif
|
||||
|
||||
ifneq (,$(filter $(shell uname),SunOS))
|
||||
ifneq (,$(filter $(UNAME),SunOS))
|
||||
INSTALL ?= ginstall
|
||||
else
|
||||
INSTALL ?= install
|
||||
@@ -357,51 +579,111 @@ endif
|
||||
|
||||
INSTALL_PROGRAM ?= $(INSTALL)
|
||||
INSTALL_DATA ?= $(INSTALL) -m 644
|
||||
MAKE_DIR ?= $(INSTALL) -d -m 755
|
||||
|
||||
|
||||
# Escape special symbols by putting each character into its separate class
|
||||
EXEC_PREFIX_REGEX ?= $(shell echo "$(EXEC_PREFIX)" | $(SED) $(SED_ERE_OPT) -e "s/([^^])/[\1]/g" -e "s/\\^/\\\\^/g")
|
||||
PREFIX_REGEX ?= $(shell echo "$(PREFIX)" | $(SED) $(SED_ERE_OPT) -e "s/([^^])/[\1]/g" -e "s/\\^/\\\\^/g")
|
||||
|
||||
PCLIBDIR ?= $(shell echo "$(LIBDIR)" | $(SED) -n $(SED_ERE_OPT) -e "s@^$(EXEC_PREFIX_REGEX)(/|$$)@@p")
|
||||
PCINCDIR ?= $(shell echo "$(INCLUDEDIR)" | $(SED) -n $(SED_ERE_OPT) -e "s@^$(PREFIX_REGEX)(/|$$)@@p")
|
||||
PCEXECDIR?= $(if $(filter $(PREFIX),$(EXEC_PREFIX)),$$\{prefix\},$(EXEC_PREFIX))
|
||||
|
||||
ifeq (,$(PCLIBDIR))
|
||||
# Additional prefix check is required, since the empty string is technically a
|
||||
# valid PCLIBDIR
|
||||
ifeq (,$(shell echo "$(LIBDIR)" | $(SED) -n $(SED_ERE_OPT) -e "\\@^$(EXEC_PREFIX_REGEX)(/|$$)@ p"))
|
||||
$(error configured libdir ($(LIBDIR)) is outside of exec_prefix ($(EXEC_PREFIX)), can't generate pkg-config file)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (,$(PCINCDIR))
|
||||
# Additional prefix check is required, since the empty string is technically a
|
||||
# valid PCINCDIR
|
||||
ifeq (,$(shell echo "$(INCLUDEDIR)" | $(SED) -n $(SED_ERE_OPT) -e "\\@^$(PREFIX_REGEX)(/|$$)@ p"))
|
||||
$(error configured includedir ($(INCLUDEDIR)) is outside of prefix ($(PREFIX)), can't generate pkg-config file)
|
||||
endif
|
||||
endif
|
||||
|
||||
libxxhash.pc: libxxhash.pc.in
|
||||
@echo creating pkgconfig
|
||||
$(Q)$(SED) $(SED_ERE_OPT) -e 's|@PREFIX@|$(PREFIX)|' \
|
||||
-e 's|@EXECPREFIX@|$(PCEXECDIR)|' \
|
||||
-e 's|@LIBDIR@|$$\{exec_prefix\}/$(PCLIBDIR)|' \
|
||||
-e 's|@INCLUDEDIR@|$$\{prefix\}/$(PCINCDIR)|' \
|
||||
-e 's|@VERSION@|$(LIBVER)|' \
|
||||
$< > $@
|
||||
|
||||
|
||||
install_libxxhash.a: libxxhash.a
|
||||
@echo Installing libxxhash.a
|
||||
$(Q)$(MAKE_DIR) $(DESTDIR)$(LIBDIR)
|
||||
$(Q)$(INSTALL_DATA) libxxhash.a $(DESTDIR)$(LIBDIR)
|
||||
|
||||
install_libxxhash: libxxhash
|
||||
@echo Installing libxxhash
|
||||
$(Q)$(MAKE_DIR) $(DESTDIR)$(LIBDIR)
|
||||
$(Q)$(INSTALL_PROGRAM) $(LIBXXH) $(DESTDIR)$(LIBDIR)
|
||||
$(Q)ln -sf $(LIBXXH) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT_MAJOR)
|
||||
$(Q)ln -sf $(LIBXXH) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT)
|
||||
|
||||
install_libxxhash.includes:
|
||||
$(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR) # includes
|
||||
$(Q)$(INSTALL_DATA) xxhash.h $(DESTDIR)$(INCLUDEDIR)
|
||||
$(Q)$(INSTALL_DATA) xxh3.h $(DESTDIR)$(INCLUDEDIR) # for compatibility, will be removed in v0.9.0
|
||||
ifeq ($(LIBXXH_DISPATCH),1)
|
||||
$(Q)$(INSTALL_DATA) xxh_x86dispatch.h $(DESTDIR)$(INCLUDEDIR)
|
||||
endif
|
||||
|
||||
install_libxxhash.pc: libxxhash.pc
|
||||
@echo Installing pkgconfig
|
||||
$(Q)$(MAKE_DIR) $(DESTDIR)$(PKGCONFIGDIR)/
|
||||
$(Q)$(INSTALL_DATA) libxxhash.pc $(DESTDIR)$(PKGCONFIGDIR)/
|
||||
|
||||
install_xxhsum: xxhsum
|
||||
@echo Installing xxhsum
|
||||
$(Q)$(MAKE_DIR) $(DESTDIR)$(BINDIR)/
|
||||
$(Q)$(INSTALL_PROGRAM) xxhsum $(DESTDIR)$(BINDIR)/xxhsum
|
||||
$(Q)ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh32sum
|
||||
$(Q)ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh64sum
|
||||
$(Q)ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh128sum
|
||||
$(Q)ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh3sum
|
||||
|
||||
install_man:
|
||||
@echo Installing man pages
|
||||
$(Q)$(MAKE_DIR) $(DESTDIR)$(MANDIR)/
|
||||
$(Q)$(INSTALL_DATA) $(MAN) $(DESTDIR)$(MANDIR)/xxhsum.1
|
||||
$(Q)ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh32sum.1
|
||||
$(Q)ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh64sum.1
|
||||
$(Q)ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh128sum.1
|
||||
$(Q)ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh3sum.1
|
||||
|
||||
.PHONY: install
|
||||
install: lib pkgconfig xxhsum ## install libraries, CLI, links and man page
|
||||
@echo Installing libxxhash
|
||||
@$(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)
|
||||
@$(INSTALL_DATA) libxxhash.a $(DESTDIR)$(LIBDIR)
|
||||
@$(INSTALL_PROGRAM) $(LIBXXH) $(DESTDIR)$(LIBDIR)
|
||||
@ln -sf $(LIBXXH) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT_MAJOR)
|
||||
@ln -sf $(LIBXXH) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT)
|
||||
@$(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR) # includes
|
||||
@$(INSTALL_DATA) xxhash.h $(DESTDIR)$(INCLUDEDIR)
|
||||
@$(INSTALL_DATA) xxh3.h $(DESTDIR)$(INCLUDEDIR)
|
||||
@echo Installing pkgconfig
|
||||
@$(INSTALL) -d -m 755 $(DESTDIR)$(PKGCONFIGDIR)/
|
||||
@$(INSTALL_DATA) libxxhash.pc $(DESTDIR)$(PKGCONFIGDIR)/
|
||||
@echo Installing xxhsum
|
||||
@$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)/ $(DESTDIR)$(MANDIR)/
|
||||
@$(INSTALL_PROGRAM) xxhsum $(DESTDIR)$(BINDIR)/xxhsum
|
||||
@ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh32sum
|
||||
@ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh64sum
|
||||
@ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh128sum
|
||||
@echo Installing man pages
|
||||
@$(INSTALL_DATA) xxhsum.1 $(DESTDIR)$(MANDIR)/xxhsum.1
|
||||
@ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh32sum.1
|
||||
@ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh64sum.1
|
||||
@ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh128sum.1
|
||||
## install libraries, CLI, links and man pages
|
||||
install: install_libxxhash.a install_libxxhash install_libxxhash.includes install_libxxhash.pc install_xxhsum install_man
|
||||
@echo xxhash installation completed
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall: ## uninstall libraries, CLI, links and man page
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/libxxhash.a
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT)
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT_MAJOR)
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/$(LIBXXH)
|
||||
@$(RM) $(DESTDIR)$(INCLUDEDIR)/xxhash.h
|
||||
@$(RM) $(DESTDIR)$(PKGCONFIGDIR)/libxxhash.pc
|
||||
@$(RM) $(DESTDIR)$(BINDIR)/xxh32sum
|
||||
@$(RM) $(DESTDIR)$(BINDIR)/xxh64sum
|
||||
@$(RM) $(DESTDIR)$(BINDIR)/xxh128sum
|
||||
@$(RM) $(DESTDIR)$(BINDIR)/xxhsum
|
||||
@$(RM) $(DESTDIR)$(MANDIR)/xxh32sum.1
|
||||
@$(RM) $(DESTDIR)$(MANDIR)/xxh64sum.1
|
||||
@$(RM) $(DESTDIR)$(MANDIR)/xxh128sum.1
|
||||
@$(RM) $(DESTDIR)$(MANDIR)/xxhsum.1
|
||||
$(Q)$(RM) $(DESTDIR)$(LIBDIR)/libxxhash.a
|
||||
$(Q)$(RM) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT)
|
||||
$(Q)$(RM) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT_MAJOR)
|
||||
$(Q)$(RM) $(DESTDIR)$(LIBDIR)/$(LIBXXH)
|
||||
$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/xxhash.h
|
||||
$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/xxh3.h
|
||||
$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/xxh_x86dispatch.h
|
||||
$(Q)$(RM) $(DESTDIR)$(PKGCONFIGDIR)/libxxhash.pc
|
||||
$(Q)$(RM) $(DESTDIR)$(BINDIR)/xxh32sum
|
||||
$(Q)$(RM) $(DESTDIR)$(BINDIR)/xxh64sum
|
||||
$(Q)$(RM) $(DESTDIR)$(BINDIR)/xxh128sum
|
||||
$(Q)$(RM) $(DESTDIR)$(BINDIR)/xxh3sum
|
||||
$(Q)$(RM) $(DESTDIR)$(BINDIR)/xxhsum
|
||||
$(Q)$(RM) $(DESTDIR)$(MANDIR)/xxh32sum.1
|
||||
$(Q)$(RM) $(DESTDIR)$(MANDIR)/xxh64sum.1
|
||||
$(Q)$(RM) $(DESTDIR)$(MANDIR)/xxh128sum.1
|
||||
$(Q)$(RM) $(DESTDIR)$(MANDIR)/xxh3sum.1
|
||||
$(Q)$(RM) $(DESTDIR)$(MANDIR)/xxhsum.1
|
||||
@echo xxhsum successfully uninstalled
|
||||
|
||||
endif
|
||||
+173
-107
@@ -1,125 +1,178 @@
|
||||
|
||||
xxHash - Extremely fast hash algorithm
|
||||
======================================
|
||||
|
||||
<!-- TODO: Update. -->
|
||||
xxHash is an Extremely fast Hash algorithm, running at RAM speed limits.
|
||||
It successfully completes the [SMHasher](https://code.google.com/p/smhasher/wiki/SMHasher) test suite
|
||||
which evaluates collision, dispersion and randomness qualities of hash functions.
|
||||
Code is highly portable, and hashes are identical on all platforms (little / big endian).
|
||||
xxHash is an Extremely fast Hash algorithm, processing at RAM speed limits.
|
||||
Code is highly portable, and produces hashes identical across all platforms (little / big endian).
|
||||
The library includes the following algorithms :
|
||||
- XXH32 : generates 32-bit hashes, using 32-bit arithmetic
|
||||
- XXH64 : generates 64-bit hashes, using 64-bit arithmetic
|
||||
- XXH3 (since `v0.8.0`): generates 64 or 128-bit hashes, using vectorized arithmetic.
|
||||
The 128-bit variant is called XXH128.
|
||||
|
||||
All variants successfully complete the [SMHasher](https://code.google.com/p/smhasher/wiki/SMHasher) test suite
|
||||
which evaluates the quality of hash functions (collision, dispersion and randomness).
|
||||
Additional tests, which evaluate more thoroughly speed and collision properties of 64-bit hashes, [are also provided](https://github.com/Cyan4973/xxHash/tree/dev/tests).
|
||||
|
||||
|Branch |Status |
|
||||
|------------|---------|
|
||||
|master | [](https://travis-ci.org/Cyan4973/xxHash?branch=master) |
|
||||
|dev | [](https://travis-ci.org/Cyan4973/xxHash?branch=dev) |
|
||||
|
||||
|release | [](https://github.com/Cyan4973/xxHash/actions?query=branch%3Arelease+) |
|
||||
|dev | [](https://github.com/Cyan4973/xxHash/actions?query=branch%3Adev+) |
|
||||
|
||||
|
||||
Benchmarks
|
||||
-------------------------
|
||||
|
||||
The benchmark uses SMHasher speed test, compiled with Visual 2010 on a Windows Seven 32-bit box.
|
||||
The reference system uses a Core 2 Duo @3GHz
|
||||
The benchmarked reference system uses an Intel i7-9700K cpu, and runs Ubuntu x64 20.04.
|
||||
The [open source benchmark program] is compiled with `clang` v10.0 using `-O3` flag.
|
||||
|
||||
| Hash Name | Width | Bandwidth (GB/s) | Small Data Velocity | Quality | Comment |
|
||||
| --------- | ----- | ---------------- | ----- | --- | --- |
|
||||
| __XXH3__ (SSE2) | 64 | 31.5 GB/s | 133.1 | 10
|
||||
| __XXH128__ (SSE2) | 128 | 29.6 GB/s | 118.1 | 10
|
||||
| _RAM sequential read_ | N/A | 28.0 GB/s | N/A | N/A | _for reference_
|
||||
| City64 | 64 | 22.0 GB/s | 76.6 | 10
|
||||
| T1ha2 | 64 | 22.0 GB/s | 99.0 | 9 | Slightly worse [collisions]
|
||||
| City128 | 128 | 21.7 GB/s | 57.7 | 10
|
||||
| __XXH64__ | 64 | 19.4 GB/s | 71.0 | 10
|
||||
| SpookyHash | 64 | 19.3 GB/s | 53.2 | 10
|
||||
| Mum | 64 | 18.0 GB/s | 67.0 | 9 | Slightly worse [collisions]
|
||||
| __XXH32__ | 32 | 9.7 GB/s | 71.9 | 10
|
||||
| City32 | 32 | 9.1 GB/s | 66.0 | 10
|
||||
| Murmur3 | 32 | 3.9 GB/s | 56.1 | 10
|
||||
| SipHash | 64 | 3.0 GB/s | 43.2 | 10
|
||||
| FNV64 | 64 | 1.2 GB/s | 62.7 | 5 | Poor avalanche properties
|
||||
| Blake2 | 256 | 1.1 GB/s | 5.1 | 10 | Cryptographic
|
||||
| SHA1 | 160 | 0.8 GB/s | 5.6 | 10 | Cryptographic but broken
|
||||
| MD5 | 128 | 0.6 GB/s | 7.8 | 10 | Cryptographic but broken
|
||||
|
||||
| Name | Speed | Quality | Author |
|
||||
|---------------|--------------------|:-------:|-------------------|
|
||||
| [xxHash] | 5.4 GB/s | 10 | Y.C. |
|
||||
| MurmurHash 3a | 2.7 GB/s | 10 | Austin Appleby |
|
||||
| SBox | 1.4 GB/s | 9 | Bret Mulvey |
|
||||
| Lookup3 | 1.2 GB/s | 9 | Bob Jenkins |
|
||||
| CityHash64 | 1.05 GB/s | 10 | Pike & Alakuijala |
|
||||
| FNV | 0.55 GB/s | 5 | Fowler, Noll, Vo |
|
||||
| CRC32 | 0.43 GB/s † | 9 | |
|
||||
| MD5-32 | 0.33 GB/s | 10 | Ronald L.Rivest |
|
||||
| SHA1-32 | 0.28 GB/s | 10 | |
|
||||
[open source benchmark program]: https://github.com/Cyan4973/xxHash/tree/release/tests/bench
|
||||
[collisions]: https://github.com/Cyan4973/xxHash/wiki/Collision-ratio-comparison#collision-study
|
||||
|
||||
[xxHash]: https://www.xxhash.com
|
||||
note 1: Small data velocity is a _rough_ evaluation of algorithm's efficiency on small data. For more detailed analysis, please refer to next paragraph.
|
||||
|
||||
Note †: SMHasher's CRC32 implementation is known to be slow. Faster implementations exist.
|
||||
note 2: some algorithms feature _faster than RAM_ speed. In which case, they can only reach their full speed potential when input is already in CPU cache (L3 or better). Otherwise, they max out on RAM speed limit.
|
||||
|
||||
Q.Score is a measure of quality of the hash function.
|
||||
It depends on successfully passing SMHasher test set.
|
||||
10 is a perfect score.
|
||||
Algorithms with a score < 5 are not listed on this table.
|
||||
### Small data
|
||||
|
||||
A more recent version, XXH64, has been created thanks to [Mathias Westerdahl](https://github.com/JCash),
|
||||
which offers superior speed and dispersion for 64-bit systems.
|
||||
Note however that 32-bit applications will still run faster using the 32-bit version.
|
||||
Performance on large data is only one part of the picture.
|
||||
Hashing is also very useful in constructions like hash tables and bloom filters.
|
||||
In these use cases, it's frequent to hash a lot of small data (starting at a few bytes).
|
||||
Algorithm's performance can be very different for such scenarios, since parts of the algorithm,
|
||||
such as initialization or finalization, become fixed cost.
|
||||
The impact of branch mis-prediction also becomes much more present.
|
||||
|
||||
SMHasher speed test, compiled using GCC 4.8.2, on Linux Mint 64-bit.
|
||||
The reference system uses a Core i5-3340M @2.7GHz
|
||||
|
||||
| Version | Speed on 64-bit | Speed on 32-bit |
|
||||
|------------|------------------|------------------|
|
||||
| XXH64 | 13.8 GB/s | 1.9 GB/s |
|
||||
| XXH32 | 6.8 GB/s | 6.0 GB/s |
|
||||
|
||||
This project also includes a command line utility, named `xxhsum`, offering similar features to `md5sum`,
|
||||
thanks to [Takayuki Matsuoka](https://github.com/t-mat)'s contributions.
|
||||
|
||||
|
||||
### License
|
||||
|
||||
The library files `xxhash.c` and `xxhash.h` are BSD licensed.
|
||||
The utility `xxhsum` is GPL licensed.
|
||||
|
||||
|
||||
### New hash algorithms
|
||||
|
||||
Starting with `v0.7.0`, the library includes a new algorithm named `XXH3`,
|
||||
which is able to generate 64 and 128-bit hashes.
|
||||
|
||||
The new algorithm is much faster than its predecessors for both long and small inputs,
|
||||
which can be observed in the following graphs:
|
||||
|
||||

|
||||
XXH3 has been designed for excellent performance on both long and small inputs,
|
||||
which can be observed in the following graph:
|
||||
|
||||

|
||||
|
||||
To access these new prototypes, one needs to unlock their declaration, using the build macro `XXH_STATIC_LINKING_ONLY`.
|
||||
For a more detailed analysis, please visit the wiki :
|
||||
https://github.com/Cyan4973/xxHash/wiki/Performance-comparison#benchmarks-concentrating-on-small-data-
|
||||
|
||||
The algorithm is currently in development, meaning its return values might still change in future versions.
|
||||
However, the API is stable, and can be used in production, typically for ephemeral
|
||||
data (produced and consumed in same session).
|
||||
Quality
|
||||
-------------------------
|
||||
|
||||
`XXH3`'s return values will be finalized upon reaching `v0.8.0`.
|
||||
Speed is not the only property that matters.
|
||||
Produced hash values must respect excellent dispersion and randomness properties,
|
||||
so that any sub-section of it can be used to maximally spread out a table or index,
|
||||
as well as reduce the amount of collisions to the minimal theoretical level, following the [birthday paradox].
|
||||
|
||||
`xxHash` has been tested with Austin Appleby's excellent SMHasher test suite,
|
||||
and passes all tests, ensuring reasonable quality levels.
|
||||
It also passes extended tests from [newer forks of SMHasher], featuring additional scenarios and conditions.
|
||||
|
||||
Finally, xxHash provides its own [massive collision tester](https://github.com/Cyan4973/xxHash/tree/dev/tests/collisions),
|
||||
able to generate and compare billions of hashes to test the limits of 64-bit hash algorithms.
|
||||
On this front too, xxHash features good results, in line with the [birthday paradox].
|
||||
A more detailed analysis is documented [in the wiki](https://github.com/Cyan4973/xxHash/wiki/Collision-ratio-comparison).
|
||||
|
||||
[birthday paradox]: https://en.wikipedia.org/wiki/Birthday_problem
|
||||
[newer forks of SMHasher]: https://github.com/rurban/smhasher
|
||||
|
||||
|
||||
### Build modifiers
|
||||
|
||||
The following macros can be set at compilation time to modify libxxhash's behavior. They are all disabled by default.
|
||||
The following macros can be set at compilation time to modify `libxxhash`'s behavior. They are generally disabled by default.
|
||||
|
||||
- `XXH_INLINE_ALL`: Make all functions `inline`, with implementations being directly included within `xxhash.h`.
|
||||
Inlining functions is beneficial for speed on small keys.
|
||||
It's _extremely effective_ when key length is expressed as _a compile time constant_,
|
||||
with performance improvements being observed in the +200% range .
|
||||
- `XXH_INLINE_ALL`: Make all functions `inline`, implementation is directly included within `xxhash.h`.
|
||||
Inlining functions is beneficial for speed, notably for small keys.
|
||||
It's _extremely effective_ when key's length is expressed as _a compile time constant_,
|
||||
with performance improvements observed in the +200% range .
|
||||
See [this article](https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html) for details.
|
||||
Note: there is no need to compile an `xxhash.o` object file in this case.
|
||||
- `XXH_NO_INLINE_HINTS`: By default, xxHash uses tricks like `__attribute__((always_inline))` and `__forceinline` to try and improve performance at the cost of code size. Defining this to 1 will mark all internal functions as `static`, allowing the compiler to decide whether to inline a function or not. This is very useful when optimizing for the smallest binary size, and it is automatically defined when compiling with `-O0`, `-Os`, `-Oz`, or `-fno-inline` on GCC and Clang. This may also increase performance depending on the compiler and the architecture.
|
||||
- `XXH_REROLL`: Reduces the size of the generated code by not unrolling some loops. Impact on performance may vary, depending on the platform and the algorithm.
|
||||
- `XXH_ACCEPT_NULL_INPUT_POINTER`: if set to `1`, when input is a `NULL` pointer,
|
||||
xxHash'd result is the same as a zero-length input
|
||||
(instead of a dereference segfault).
|
||||
Adds one branch at the beginning of the hash.
|
||||
- `XXH_PRIVATE_API`: same outcome as `XXH_INLINE_ALL`. Still available for legacy support.
|
||||
The name underlines that `XXH_*` symbol names will not be exported.
|
||||
- `XXH_STATIC_LINKING_ONLY`: gives access to internal state declaration, required for static allocation.
|
||||
Incompatible with dynamic linking, due to risks of ABI changes.
|
||||
- `XXH_NAMESPACE`: Prefixes all symbols with the value of `XXH_NAMESPACE`.
|
||||
This macro can only use compilable character set.
|
||||
Useful to evade symbol naming collisions,
|
||||
in case of multiple inclusions of xxHash's source code.
|
||||
Client applications still use the regular function names,
|
||||
as symbols are automatically translated through `xxhash.h`.
|
||||
- `XXH_FORCE_ALIGN_CHECK`: Use a faster direct read path when input is aligned.
|
||||
This option can result in dramatic performance improvement on architectures unable to load memory from unaligned addresses
|
||||
when input to hash happens to be aligned on 32 or 64-bit boundaries.
|
||||
It is (slightly) detrimental on platform with good unaligned memory access performance (same instruction for both aligned and unaligned accesses).
|
||||
This option is automatically disabled on `x86`, `x64` and `aarch64`, and enabled on all other platforms.
|
||||
- `XXH_FORCE_MEMORY_ACCESS`: The default method `0` uses a portable `memcpy()` notation.
|
||||
Method `1` uses a gcc-specific `packed` attribute, which can provide better performance for some targets.
|
||||
Method `2` forces unaligned reads, which is not standards compliant, but might sometimes be the only way to extract better read performance.
|
||||
Method `3` uses a byteshift operation, which is best for old compilers which don't inline `memcpy()` or big-endian systems without a byteswap instruction
|
||||
- `XXH_CPU_LITTLE_ENDIAN`: By default, endianess is determined at compile time.
|
||||
It's possible to skip auto-detection and force format to little-endian, by setting this macro to 1.
|
||||
Setting it to 0 forces big-endian.
|
||||
- `XXH_PRIVATE_API`: same impact as `XXH_INLINE_ALL`.
|
||||
Name underlines that XXH_* symbols will not be exported.
|
||||
- `XXH_NAMESPACE`: Prefixes all symbols with the value of `XXH_NAMESPACE`.
|
||||
Useful to evade symbol naming collisions,
|
||||
in case of multiple inclusions of xxHash's source code.
|
||||
Client applications can still use the regular function name,
|
||||
as symbols are automatically translated through `xxhash.h`.
|
||||
- `XXH_STATIC_LINKING_ONLY`: gives access to the state declaration for static allocation.
|
||||
Incompatible with dynamic linking, due to risks of ABI changes.
|
||||
- `XXH_NO_LONG_LONG`: removes support for XXH3 and XXH64 for targets without 64-bit support.
|
||||
Method `2` forces unaligned reads, which is not standard compliant, but might sometimes be the only way to extract better read performance.
|
||||
Method `3` uses a byteshift operation, which is best for old compilers which don't inline `memcpy()` or big-endian systems without a byteswap instruction.
|
||||
- `XXH_CPU_LITTLE_ENDIAN`: By default, endianness is determined by a runtime test resolved at compile time.
|
||||
If, for some reason, the compiler cannot simplify the runtime test, it can cost performance.
|
||||
It's possible to skip auto-detection and simply state that the architecture is little-endian by setting this macro to 1.
|
||||
Setting it to 0 states big-endian.
|
||||
- `XXH_ENABLE_AUTOVECTORIZE`: Auto-vectorization may be triggered for XXH32 and XXH64, depending on cpu vector capabilities and compiler version.
|
||||
Note: auto-vectorization tends to be triggered more easily with recent versions of `clang`.
|
||||
For XXH32, SSE4.1 or equivalent (NEON) is enough, while XXH64 requires AVX512.
|
||||
Unfortunately, auto-vectorization is generally detrimental to XXH performance.
|
||||
For this reason, the xxhash source code tries to prevent auto-vectorization by default.
|
||||
That being said, systems evolve, and this conclusion is not forthcoming.
|
||||
For example, it has been reported that recent Zen4 cpus are more likely to improve performance with vectorization.
|
||||
Therefore, should you prefer or want to test vectorized code, you can enable this flag:
|
||||
it will remove the no-vectorization protection code, thus making it more likely for XXH32 and XXH64 to be auto-vectorized.
|
||||
- `XXH32_ENDJMP`: Switch multi-branch finalization stage of XXH32 by a single jump.
|
||||
This is generally undesirable for performance, especially when hashing inputs of random sizes.
|
||||
But depending on exact architecture and compiler, a jump might provide slightly better performance on small inputs. Disabled by default.
|
||||
- `XXH_IMPORT`: MSVC specific: should only be defined for dynamic linking, as it prevents linkage errors.
|
||||
- `XXH_NO_STDLIB`: Disable invocation of `<stdlib.h>` functions, notably `malloc()` and `free()`.
|
||||
`libxxhash`'s `XXH*_createState()` will always fail and return `NULL`.
|
||||
But one-shot hashing (like `XXH32()`) or streaming using statically allocated states
|
||||
still work as expected.
|
||||
This build flag is useful for embedded environments without dynamic allocation.
|
||||
- `XXH_DEBUGLEVEL` : When set to any value >= 1, enables `assert()` statements.
|
||||
This (slightly) slows down execution, but may help finding bugs during debugging sessions.
|
||||
|
||||
#### Binary size control
|
||||
- `XXH_NO_XXH3` : removes symbols related to `XXH3` (both 64 & 128 bits) from generated binary.
|
||||
`XXH3` is by far the largest contributor to `libxxhash` size,
|
||||
so it's useful to reduce binary size for applications which do not employ `XXH3`.
|
||||
- `XXH_NO_LONG_LONG`: removes compilation of algorithms relying on 64-bit `long long` types
|
||||
which include `XXH3` and `XXH64`.
|
||||
Only `XXH32` will be compiled.
|
||||
Useful for targets (architectures and compilers) without 64-bit support.
|
||||
- `XXH_NO_STREAM`: Disables the streaming API, limiting the library to single shot variants only.
|
||||
- `XXH_NO_INLINE_HINTS`: By default, xxHash uses `__attribute__((always_inline))` and `__forceinline` to improve performance at the cost of code size.
|
||||
Defining this macro to 1 will mark all internal functions as `static`, allowing the compiler to decide whether to inline a function or not.
|
||||
This is very useful when optimizing for smallest binary size,
|
||||
and is automatically defined when compiling with `-O0`, `-Os`, `-Oz`, or `-fno-inline` on GCC and Clang.
|
||||
It may also be required to successfully compile using `-Og`, depending on compiler version.
|
||||
- `XXH_SIZE_OPT`: `0`: default, optimize for speed
|
||||
`1`: default for `-Os` and `-Oz`: disables some speed hacks for size optimization
|
||||
`2`: makes code as small as possible, performance may cry
|
||||
|
||||
#### Build modifiers specific for XXH3
|
||||
- `XXH_VECTOR` : manually select a vector instruction set (default: auto-selected at compilation time). Available instruction sets are `XXH_SCALAR`, `XXH_SSE2`, `XXH_AVX2`, `XXH_AVX512`, `XXH_NEON` and `XXH_VSX`. Compiler may require additional flags to ensure proper support (for example, `gcc` on x86_64 requires `-mavx2` for `AVX2`, or `-mavx512f` for `AVX512`).
|
||||
- `XXH_PREFETCH_DIST` : select prefetching distance. For close-to-metal adaptation to specific hardware platforms. XXH3 only.
|
||||
- `XXH_NO_PREFETCH` : disable prefetching. Some platforms or situations may perform better without prefetching. XXH3 only.
|
||||
|
||||
#### Makefile variables
|
||||
When compiling the Command Line Interface `xxhsum` using `make`, the following environment variables can also be set :
|
||||
- `DISPATCH=1` : use `xxh_x86dispatch.c`, select at runtime between `scalar`, `sse2`, `avx2` or `avx512` instruction set. This option is only valid for `x86`/`x64` systems. It is enabled by default when target `x86`/`x64` is detected. It can be forcefully turned off using `DISPATCH=0`.
|
||||
- `LIBXXH_DISPATCH=1` : same idea, implemented a runtime vector extension detector, but within `libxxhash`. This parameter is disabled by default. When enabled (only valid for `x86`/`x64` systems), new symbols published in `xxh_x86dispatch.h` become accessible. At the time of this writing, it's required to include `xxh_x86dispatch.h` in order to access the symbols with runtime vector extension detection.
|
||||
- `XXH_1ST_SPEED_TARGET` : select an initial speed target, expressed in MB/s, for the first speed test in benchmark mode. Benchmark will adjust the target at subsequent iterations, but the first test is made "blindly" by targeting this speed. Currently conservatively set to 10 MB/s, to support very slow (emulated) platforms.
|
||||
- `NODE_JS=1` : When compiling `xxhsum` for Node.js with Emscripten, this links the `NODERAWFS` library for unrestricted filesystem access and patches `isatty` to make the command line utility correctly detect the terminal. This does make the binary specific to Node.js.
|
||||
|
||||
### Building xxHash - Using vcpkg
|
||||
|
||||
@@ -133,10 +186,10 @@ You can download and install xxHash using the [vcpkg](https://github.com/Microso
|
||||
|
||||
The xxHash port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
Calling xxhash 64-bit variant from a C program:
|
||||
The simplest example calls xxhash 64-bit variant as a one-shot function
|
||||
generating a hash value from a single buffer, and invoked from a C/C++ program:
|
||||
|
||||
```C
|
||||
#include "xxhash.h"
|
||||
@@ -146,7 +199,8 @@ Calling xxhash 64-bit variant from a C program:
|
||||
}
|
||||
```
|
||||
|
||||
Using streaming variant is more involved, but makes it possible to provide data incrementally:
|
||||
Streaming variant is more involved, but makes it possible to provide data incrementally:
|
||||
|
||||
```C
|
||||
#include "stdlib.h" /* abort() */
|
||||
#include "xxhash.h"
|
||||
@@ -168,17 +222,17 @@ XXH64_hash_t calcul_hash_streaming(FileHandler fh)
|
||||
|
||||
/* Feed the state with input data, any size, any number of times */
|
||||
(...)
|
||||
while ( /* any condition */ ) {
|
||||
size_t const length = get_more_data(buffer, bufferSize, fh);
|
||||
while ( /* some data left */ ) {
|
||||
size_t const length = get_more_data(buffer, bufferSize, fh);
|
||||
if (XXH64_update(state, buffer, length) == XXH_ERROR) abort();
|
||||
(...)
|
||||
}
|
||||
(...)
|
||||
|
||||
/* Get the hash */
|
||||
/* Produce the final hash value */
|
||||
XXH64_hash_t const hash = XXH64_digest(state);
|
||||
|
||||
/* State can be re-used; in this example, it is simply freed */
|
||||
/* State could be re-used; but in this example, it is simply freed */
|
||||
free(buffer);
|
||||
XXH64_freeState(state);
|
||||
|
||||
@@ -187,19 +241,31 @@ XXH64_hash_t calcul_hash_streaming(FileHandler fh)
|
||||
```
|
||||
|
||||
|
||||
### License
|
||||
|
||||
The library files `xxhash.c` and `xxhash.h` are BSD licensed.
|
||||
The utility `xxhsum` is GPL licensed.
|
||||
|
||||
|
||||
### Other programming languages
|
||||
|
||||
Aside from the C reference version,
|
||||
xxHash is also available in many different programming languages,
|
||||
thanks to many great contributors.
|
||||
They are [listed here](https://www.xxhash.com/#other-languages).
|
||||
Beyond the C reference version,
|
||||
xxHash is also available from many different programming languages,
|
||||
thanks to great contributors.
|
||||
They are [listed here](http://www.xxhash.com/#other-languages).
|
||||
|
||||
|
||||
### Branch Policy
|
||||
### Packaging status
|
||||
|
||||
> - The "master" branch is considered stable, at all times.
|
||||
> - The "dev" branch is the one where all contributions must be merged
|
||||
before being promoted to master.
|
||||
> + If you plan to propose a patch, please commit into the "dev" branch,
|
||||
or its own feature branch.
|
||||
Direct commit to "master" are not permitted.
|
||||
Many distributions bundle a package manager
|
||||
which allows easy xxhash installation as both a `libxxhash` library
|
||||
and `xxhsum` command line interface.
|
||||
|
||||
[](https://repology.org/project/xxhash/versions)
|
||||
|
||||
|
||||
### Special Thanks
|
||||
|
||||
- Takayuki Matsuoka, aka @t-mat, for creating `xxhsum -c` and great support during early xxh releases
|
||||
- Mathias Westerdahl, aka @JCash, for introducing the first version of `XXH64`
|
||||
- Devin Hussey, aka @easyaspi314, for incredible low-level optimizations on `XXH3` and `XXH128`
|
||||
@@ -0,0 +1,13 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Security updates are applied only to the latest release.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
|
||||
|
||||
Please disclose it at [security advisory](https://github.com/Cyan4973/xxHash/security/advisories/new).
|
||||
|
||||
This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.
|
||||
@@ -13,10 +13,6 @@ environment:
|
||||
- COMPILER: "visual"
|
||||
ARCH: "x64"
|
||||
TEST_XXHSUM: "true"
|
||||
- COMPILER: "visual"
|
||||
ARCH: "x64"
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TEST_XXHSUM: "true"
|
||||
- COMPILER: "visual"
|
||||
ARCH: "Win32"
|
||||
TEST_XXHSUM: "true"
|
||||
@@ -26,16 +22,24 @@ environment:
|
||||
TEST_XXHSUM: "true"
|
||||
- COMPILER: "visual"
|
||||
ARCH: "ARM"
|
||||
- COMPILER: "visual"
|
||||
ARCH: "ARM64"
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
# note: ARM64 is not available with Visual Studio 14 2015, which is default for Appveyor
|
||||
- COMPILER: "gcc"
|
||||
PLATFORM: "mingw64"
|
||||
- COMPILER: "gcc"
|
||||
PLATFORM: "mingw32"
|
||||
- COMPILER: "gcc"
|
||||
PLATFORM: "clang"
|
||||
# Below tests are now disabled due to redundancy.
|
||||
# Their equivalent already runs correctly on Github Actions.
|
||||
# - COMPILER: "visual"
|
||||
# ARCH: "x64"
|
||||
# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
# TEST_XXHSUM: "true"
|
||||
# - COMPILER: "visual"
|
||||
# ARCH: "ARM64"
|
||||
# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
# # note: ARM64 is not available with Visual Studio 14 2015, which is default for Appveyor
|
||||
|
||||
# The following tests were also flacky on Appveyor, for various reasons.
|
||||
# - COMPILER: "gcc"
|
||||
# PLATFORM: "mingw64"
|
||||
# - COMPILER: "gcc"
|
||||
# PLATFORM: "mingw32"
|
||||
# - COMPILER: "gcc"
|
||||
# PLATFORM: "clang"
|
||||
|
||||
install:
|
||||
- ECHO Installing %COMPILER% %PLATFORM% %ARCH%
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"Cyan4973/xxHash": { }
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,4 @@
|
||||
This directory contains source code dedicated to the `xxhsum` command line utility,
|
||||
which is a user program of `libxxhash`.
|
||||
|
||||
Note that, in contrast with the library `libxxhash`, the command line utility `xxhsum` ships with GPLv2 license.
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* xxhsum - Command line interface for xxhash algorithms
|
||||
* Copyright (C) 2013-2024 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
int g_xsumarch_avoid_empty_unit = 0;
|
||||
|
||||
#if ((defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)) && !defined(_M_ARM64EC)) || defined(__i386__) || defined(_M_IX86) || defined(_M_IX86_FP)
|
||||
#if defined(XXHSUM_DISPATCH)
|
||||
|
||||
#include "../xxh_x86dispatch.h"
|
||||
|
||||
const char* XSUM_autox86(void)
|
||||
{
|
||||
int vecVersion = XXH_featureTest();
|
||||
switch(vecVersion) {
|
||||
case XXH_SCALAR:
|
||||
return "x86 autoVec (scalar: no vector extension detected)";
|
||||
case XXH_SSE2:
|
||||
return "x86 autoVec (SSE2 detected)";
|
||||
case XXH_AVX2:
|
||||
return "x86 autoVec (AVX2 detected)";
|
||||
case XXH_AVX512:
|
||||
return "x86 autoVec (AVX512 detected)";
|
||||
default:;
|
||||
}
|
||||
return " autoVec (error detecting vector extension)";
|
||||
}
|
||||
|
||||
#endif /* XXHSUM_DISPATCH */
|
||||
#endif /* x86 */
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* xxhsum - Command line interface for xxhash algorithms
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
/*
|
||||
* Checks for predefined macros by the compiler to try and get both the arch
|
||||
* and the compiler version.
|
||||
*/
|
||||
#ifndef XSUM_ARCH_H
|
||||
#define XSUM_ARCH_H
|
||||
|
||||
#include "xsum_config.h"
|
||||
|
||||
#define XSUM_LIB_VERSION XXH_VERSION_MAJOR.XXH_VERSION_MINOR.XXH_VERSION_RELEASE
|
||||
#define XSUM_QUOTE(str) #str
|
||||
#define XSUM_EXPAND_AND_QUOTE(str) XSUM_QUOTE(str)
|
||||
#define XSUM_PROGRAM_VERSION XSUM_EXPAND_AND_QUOTE(XSUM_LIB_VERSION)
|
||||
|
||||
|
||||
/* Show compiler versions in WELCOME_MESSAGE. XSUM_CC_VERSION_FMT will return the printf specifiers,
|
||||
* and VERSION will contain the comma separated list of arguments to the XSUM_CC_VERSION_FMT string. */
|
||||
#if defined(__clang_version__)
|
||||
/* Clang does its own thing. */
|
||||
# ifdef __apple_build_version__
|
||||
# define XSUM_CC_VERSION_FMT "Apple Clang %s"
|
||||
# else
|
||||
# define XSUM_CC_VERSION_FMT "Clang %s"
|
||||
# endif
|
||||
# define XSUM_CC_VERSION __clang_version__
|
||||
#elif defined(__VERSION__)
|
||||
/* GCC and ICC */
|
||||
# define XSUM_CC_VERSION_FMT "%s"
|
||||
# ifdef __INTEL_COMPILER /* icc adds its prefix */
|
||||
# define XSUM_CC_VERSION __VERSION__
|
||||
# else /* assume GCC */
|
||||
# define XSUM_CC_VERSION "GCC " __VERSION__
|
||||
# endif
|
||||
#elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
|
||||
/*
|
||||
* MSVC
|
||||
* "For example, if the version number of the Visual C++ compiler is
|
||||
* 15.00.20706.01, the _MSC_FULL_VER macro evaluates to 150020706."
|
||||
*
|
||||
* https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2017
|
||||
*/
|
||||
# define XSUM_CC_VERSION_FMT "MSVC %02i.%02i.%05i.%02i"
|
||||
# define XSUM_CC_VERSION _MSC_FULL_VER / 10000000 % 100, _MSC_FULL_VER / 100000 % 100, _MSC_FULL_VER % 100000, _MSC_BUILD
|
||||
#elif defined(_MSC_VER) /* old MSVC */
|
||||
# define XSUM_CC_VERSION_FMT "MSVC %02i.%02i"
|
||||
# define XSUM_CC_VERSION _MSC_VER / 100, _MSC_VER % 100
|
||||
#elif defined(__TINYC__)
|
||||
/* tcc stores its version in the __TINYC__ macro. */
|
||||
# define XSUM_CC_VERSION_FMT "tcc %i.%i.%i"
|
||||
# define XSUM_CC_VERSION __TINYC__ / 10000 % 100, __TINYC__ / 100 % 100, __TINYC__ % 100
|
||||
#else
|
||||
# define XSUM_CC_VERSION_FMT "%s"
|
||||
# define XSUM_CC_VERSION "unknown compiler"
|
||||
#endif
|
||||
|
||||
/* makes the next part easier */
|
||||
#if (defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)) && !defined(_M_ARM64EC)
|
||||
# define XSUM_ARCH_X64 1
|
||||
# define XSUM_ARCH_X86 "x86_64"
|
||||
#elif defined(__i386__) || defined(_M_IX86) || defined(_M_IX86_FP)
|
||||
# define XSUM_ARCH_X86 "i386"
|
||||
#endif
|
||||
|
||||
/* Try to detect the architecture. */
|
||||
#if defined(XSUM_ARCH_X86)
|
||||
# if defined(XXHSUM_DISPATCH)
|
||||
const char* XSUM_autox86(void);
|
||||
# define XSUM_ARCH XSUM_autox86()
|
||||
# elif defined(__AVX512F__)
|
||||
# define XSUM_ARCH XSUM_ARCH_X86 " + AVX512"
|
||||
# elif defined(__AVX2__)
|
||||
# define XSUM_ARCH XSUM_ARCH_X86 " + AVX2"
|
||||
# elif defined(__AVX__)
|
||||
# define XSUM_ARCH XSUM_ARCH_X86 " + AVX"
|
||||
# elif defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) \
|
||||
|| defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP == 2)
|
||||
# define XSUM_ARCH XSUM_ARCH_X86 " + SSE2"
|
||||
# else
|
||||
# define XSUM_ARCH XSUM_ARCH_X86
|
||||
# endif
|
||||
#elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
|
||||
# if defined(__ARM_FEATURE_SVE)
|
||||
# define XSUM_ARCH "aarch64 + SVE"
|
||||
# else
|
||||
# define XSUM_ARCH "aarch64 + NEON"
|
||||
# endif
|
||||
#elif defined(__arm__) || defined(__thumb__) || defined(__thumb2__) || defined(_M_ARM)
|
||||
/* ARM has a lot of different features that can change xxHash significantly. */
|
||||
# ifdef __ARM_ARCH
|
||||
# define XSUM_ARCH_ARM_VER XSUM_EXPAND_AND_QUOTE(__ARM_ARCH)
|
||||
# else
|
||||
# define XSUM_ARCH_ARM_VER XSUM_EXPAND_AND_QUOTE(_M_ARM)
|
||||
# endif
|
||||
# if defined(_M_ARM) /* windows arm is always thumb-2 */ \
|
||||
|| defined(__thumb2__) || (defined(__thumb__) && (__thumb__ == 2 || __ARM_ARCH >= 7))
|
||||
# define XSUM_ARCH_THUMB " Thumb-2"
|
||||
# elif defined(__thumb__)
|
||||
# define XSUM_ARCH_THUMB " Thumb-1"
|
||||
# else
|
||||
# define XSUM_ARCH_THUMB ""
|
||||
# endif
|
||||
/* ARMv7 has unaligned by default */
|
||||
# if defined(__ARM_FEATURE_UNALIGNED) || __ARM_ARCH >= 7 || defined(_M_ARM)
|
||||
# define XSUM_ARCH_UNALIGNED " + unaligned"
|
||||
# else
|
||||
# define XSUM_ARCH_UNALIGNED ""
|
||||
# endif
|
||||
# if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(_M_ARM)
|
||||
# define XSUM_ARCH_NEON " + NEON"
|
||||
# else
|
||||
# define XSUM_ARCH_NEON ""
|
||||
# endif
|
||||
# define XSUM_ARCH "ARMv" XSUM_ARCH_ARM_VER XSUM_ARCH_THUMB XSUM_ARCH_NEON XSUM_ARCH_UNALIGNED
|
||||
#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)
|
||||
# if defined(__GNUC__) && defined(__POWER9_VECTOR__)
|
||||
# define XSUM_ARCH "ppc64 + POWER9 vector"
|
||||
# elif defined(__GNUC__) && defined(__POWER8_VECTOR__)
|
||||
# define XSUM_ARCH "ppc64 + POWER8 vector"
|
||||
# else
|
||||
# define XSUM_ARCH "ppc64"
|
||||
# endif
|
||||
#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)
|
||||
# define XSUM_ARCH "ppc"
|
||||
#elif defined(__AVR)
|
||||
# define XSUM_ARCH "AVR"
|
||||
#elif defined(__mips64)
|
||||
# define XSUM_ARCH "mips64"
|
||||
#elif defined(__mips)
|
||||
# define XSUM_ARCH "mips"
|
||||
#elif defined(__s390x__)
|
||||
# define XSUM_ARCH "s390x"
|
||||
#elif defined(__s390__)
|
||||
# define XSUM_ARCH "s390"
|
||||
#elif defined(__wasm__) || defined(__asmjs__) || defined(__EMSCRIPTEN__)
|
||||
# if defined(__wasm_simd128__)
|
||||
# define XSUM_ARCH "wasm/asmjs + simd128"
|
||||
# else
|
||||
# define XSUM_ARCH "wasm/asmjs"
|
||||
# endif
|
||||
#elif defined(__loongarch_lp64)
|
||||
# define XSUM_ARCH "loongarch"
|
||||
#else
|
||||
# define XSUM_ARCH "unknown"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* XSUM_ARCH_H */
|
||||
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* xsum_bench - Benchmark functions for xxhsum
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#include "xsum_output.h" /* XSUM_logLevel */
|
||||
#include "xsum_bench.h"
|
||||
#include "xsum_sanity_check.h" /* XSUM_fillTestBuffer */
|
||||
#include "xsum_os_specific.h" /* XSUM_getFileSize */
|
||||
#ifndef XXH_STATIC_LINKING_ONLY
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
#endif
|
||||
#include "../xxhash.h"
|
||||
#ifdef XXHSUM_DISPATCH
|
||||
# include "../xxh_x86dispatch.h" /* activate _dispatch() redirectors */
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <assert.h>
|
||||
#include <string.h> /* strlen, memcpy */
|
||||
#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
|
||||
#include <errno.h> /* errno */
|
||||
|
||||
#define TIMELOOP_S 1
|
||||
#define TIMELOOP (TIMELOOP_S * CLOCKS_PER_SEC) /* target timing per iteration */
|
||||
#define TIMELOOP_MIN (TIMELOOP / 2) /* minimum timing to validate a result */
|
||||
|
||||
/* Each benchmark iteration attempts to match TIMELOOP (1 second).
|
||||
* The nb of loops is adjusted at each iteration to reach that target.
|
||||
* However, initially, there is no information, so 1st iteration blindly targets an arbitrary speed.
|
||||
* If it's too small, it will be adjusted, and a new attempt will be made.
|
||||
* But if it's too large, the first iteration can be very long,
|
||||
* before being fixed at second attempt.
|
||||
* So prefer starting with small speed targets.
|
||||
* XXH_1ST_SPEED_TARGET is defined in MB/s */
|
||||
#ifndef XXH_1ST_SPEED_TARGET
|
||||
# define XXH_1ST_SPEED_TARGET 10
|
||||
#endif
|
||||
|
||||
#define MAX_MEM (2 GB - 64 MB)
|
||||
|
||||
static clock_t XSUM_clockSpan( clock_t start )
|
||||
{
|
||||
return clock() - start; /* works even if overflow; Typical max span ~ 30 mn */
|
||||
}
|
||||
|
||||
static size_t XSUM_findMaxMem(XSUM_U64 requiredMem)
|
||||
{
|
||||
size_t const step = 64 MB;
|
||||
void* testmem = NULL;
|
||||
|
||||
requiredMem = (((requiredMem >> 26) + 1) << 26);
|
||||
requiredMem += 2*step;
|
||||
if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
|
||||
|
||||
while (!testmem) {
|
||||
if (requiredMem > step) requiredMem -= step;
|
||||
else requiredMem >>= 1;
|
||||
testmem = malloc ((size_t)requiredMem);
|
||||
}
|
||||
free (testmem);
|
||||
|
||||
/* keep some space available */
|
||||
if (requiredMem > step) requiredMem -= step;
|
||||
else requiredMem >>= 1;
|
||||
|
||||
return (size_t)requiredMem;
|
||||
}
|
||||
|
||||
/*
|
||||
* A secret buffer used for benchmarking XXH3's withSecret variants.
|
||||
*
|
||||
* In order for the bench to be realistic, the secret buffer would need to be
|
||||
* pre-generated.
|
||||
*
|
||||
* Adding a pointer to the parameter list would be messy.
|
||||
*/
|
||||
static XSUM_U8 g_benchSecretBuf[XXH3_SECRET_SIZE_MIN];
|
||||
|
||||
/*
|
||||
* Wrappers for the benchmark.
|
||||
*
|
||||
* If you would like to add other hashes to the bench, create a wrapper and add
|
||||
* it to the g_hashesToBench table. It will automatically be added.
|
||||
*/
|
||||
typedef XSUM_U32 (*hashFunction)(const void* buffer, size_t bufferSize, XSUM_U32 seed);
|
||||
|
||||
static XSUM_U32 localXXH32(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
return XXH32(buffer, bufferSize, seed);
|
||||
}
|
||||
static XSUM_U32 localXXH32_stream(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
XXH32_state_t state;
|
||||
(void)seed;
|
||||
XXH32_reset(&state, seed);
|
||||
XXH32_update(&state, buffer, bufferSize);
|
||||
return (XSUM_U32)XXH32_digest(&state);
|
||||
}
|
||||
static XSUM_U32 localXXH64(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
return (XSUM_U32)XXH64(buffer, bufferSize, seed);
|
||||
}
|
||||
static XSUM_U32 localXXH64_stream(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
XXH64_state_t state;
|
||||
(void)seed;
|
||||
XXH64_reset(&state, seed);
|
||||
XXH64_update(&state, buffer, bufferSize);
|
||||
return (XSUM_U32)XXH64_digest(&state);
|
||||
}
|
||||
static XSUM_U32 localXXH3_64b(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
(void)seed;
|
||||
return (XSUM_U32)XXH3_64bits(buffer, bufferSize);
|
||||
}
|
||||
static XSUM_U32 localXXH3_64b_seeded(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
return (XSUM_U32)XXH3_64bits_withSeed(buffer, bufferSize, seed);
|
||||
}
|
||||
static XSUM_U32 localXXH3_64b_secret(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
(void)seed;
|
||||
return (XSUM_U32)XXH3_64bits_withSecret(buffer, bufferSize, g_benchSecretBuf, sizeof(g_benchSecretBuf));
|
||||
}
|
||||
static XSUM_U32 localXXH3_128b(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
(void)seed;
|
||||
return (XSUM_U32)(XXH3_128bits(buffer, bufferSize).low64);
|
||||
}
|
||||
static XSUM_U32 localXXH3_128b_seeded(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
return (XSUM_U32)(XXH3_128bits_withSeed(buffer, bufferSize, seed).low64);
|
||||
}
|
||||
static XSUM_U32 localXXH3_128b_secret(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
(void)seed;
|
||||
return (XSUM_U32)(XXH3_128bits_withSecret(buffer, bufferSize, g_benchSecretBuf, sizeof(g_benchSecretBuf)).low64);
|
||||
}
|
||||
static XSUM_U32 localXXH3_stream(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
XXH3_state_t state;
|
||||
(void)seed;
|
||||
XXH3_64bits_reset(&state);
|
||||
XXH3_64bits_update(&state, buffer, bufferSize);
|
||||
return (XSUM_U32)XXH3_64bits_digest(&state);
|
||||
}
|
||||
static XSUM_U32 localXXH3_stream_seeded(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
XXH3_state_t state;
|
||||
XXH3_INITSTATE(&state);
|
||||
XXH3_64bits_reset_withSeed(&state, (XXH64_hash_t)seed);
|
||||
XXH3_64bits_update(&state, buffer, bufferSize);
|
||||
return (XSUM_U32)XXH3_64bits_digest(&state);
|
||||
}
|
||||
static XSUM_U32 localXXH128_stream(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
XXH3_state_t state;
|
||||
(void)seed;
|
||||
XXH3_128bits_reset(&state);
|
||||
XXH3_128bits_update(&state, buffer, bufferSize);
|
||||
return (XSUM_U32)(XXH3_128bits_digest(&state).low64);
|
||||
}
|
||||
static XSUM_U32 localXXH128_stream_seeded(const void* buffer, size_t bufferSize, XSUM_U32 seed)
|
||||
{
|
||||
XXH3_state_t state;
|
||||
XXH3_INITSTATE(&state);
|
||||
XXH3_128bits_reset_withSeed(&state, (XXH64_hash_t)seed);
|
||||
XXH3_128bits_update(&state, buffer, bufferSize);
|
||||
return (XSUM_U32)(XXH3_128bits_digest(&state).low64);
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
hashFunction func;
|
||||
} hashInfo;
|
||||
|
||||
static const hashInfo g_hashesToBench[] = {
|
||||
{ "XXH32", &localXXH32 },
|
||||
{ "XXH64", &localXXH64 },
|
||||
{ "XXH3_64b", &localXXH3_64b },
|
||||
{ "XXH3_64b w/seed", &localXXH3_64b_seeded },
|
||||
{ "XXH3_64b w/secret", &localXXH3_64b_secret },
|
||||
{ "XXH128", &localXXH3_128b },
|
||||
{ "XXH128 w/seed", &localXXH3_128b_seeded },
|
||||
{ "XXH128 w/secret", &localXXH3_128b_secret },
|
||||
{ "XXH32_stream", &localXXH32_stream },
|
||||
{ "XXH64_stream", &localXXH64_stream },
|
||||
{ "XXH3_stream", &localXXH3_stream },
|
||||
{ "XXH3_stream w/seed",&localXXH3_stream_seeded },
|
||||
{ "XXH128_stream", &localXXH128_stream },
|
||||
{ "XXH128_stream w/seed",&localXXH128_stream_seeded },
|
||||
};
|
||||
#define NB_HASHFUNC (sizeof(g_hashesToBench) / sizeof(*g_hashesToBench))
|
||||
|
||||
#define NB_TESTFUNC (1 + 2 * NB_HASHFUNC)
|
||||
int const g_nbTestFunctions = NB_TESTFUNC;
|
||||
char g_testIDs[NB_TESTFUNC] = { 0 };
|
||||
const char k_testIDs_default[NB_TESTFUNC] = { 0,
|
||||
1 /*XXH32*/, 0,
|
||||
1 /*XXH64*/, 0,
|
||||
1 /*XXH3*/, 0, 0, 0, 0, 0,
|
||||
1 /*XXH128*/ };
|
||||
|
||||
int g_nbIterations = NBLOOPS_DEFAULT;
|
||||
#define HASHNAME_MAX 29
|
||||
static void XSUM_benchHash(hashFunction h, const char* hName, int testID,
|
||||
const void* buffer, size_t bufferSize)
|
||||
{
|
||||
XSUM_U32 nbh_perIteration = (XSUM_U32)((XXH_1ST_SPEED_TARGET MB) / (bufferSize+1)) + 1;
|
||||
int iterationNb, nbIterations = g_nbIterations + !g_nbIterations /* min 1 */;
|
||||
double fastestH = 100000000.;
|
||||
assert(HASHNAME_MAX > 2);
|
||||
XSUM_logVerbose(2, "\r%80s\r", ""); /* Clean display line */
|
||||
|
||||
for (iterationNb = 1; iterationNb <= nbIterations; iterationNb++) {
|
||||
XSUM_U32 r=0;
|
||||
clock_t cStart;
|
||||
|
||||
XSUM_logVerbose(2, "%2i-%-*.*s : %10u ->\r",
|
||||
iterationNb,
|
||||
HASHNAME_MAX, HASHNAME_MAX, hName,
|
||||
(unsigned)bufferSize);
|
||||
cStart = clock();
|
||||
while (clock() == cStart); /* starts clock() at its exact beginning */
|
||||
cStart = clock();
|
||||
|
||||
{ XSUM_U32 u;
|
||||
for (u=0; u<nbh_perIteration; u++)
|
||||
r += h(buffer, bufferSize, u);
|
||||
}
|
||||
if (r==0) XSUM_logVerbose(3,".\r"); /* do something with r to defeat compiler "optimizing" hash away */
|
||||
|
||||
{ clock_t const nbTicks = XSUM_clockSpan(cStart);
|
||||
double const ticksPerHash = ((double)nbTicks / TIMELOOP) / nbh_perIteration;
|
||||
/*
|
||||
* clock() is the only decent portable timer, but it isn't very
|
||||
* precise.
|
||||
*
|
||||
* Sometimes, this lack of precision is enough that the benchmark
|
||||
* finishes before there are enough ticks to get a meaningful result.
|
||||
*
|
||||
* For example, on a Core 2 Duo (without any sort of Turbo Boost),
|
||||
* the imprecise timer caused peculiar results like so:
|
||||
*
|
||||
* XXH3_64b 4800.0 MB/s // conveniently even
|
||||
* XXH3_64b unaligned 4800.0 MB/s
|
||||
* XXH3_64b seeded 9600.0 MB/s // magical 2x speedup?!
|
||||
* XXH3_64b seeded unaligned 4800.0 MB/s
|
||||
*
|
||||
* If we sense a suspiciously low number of ticks, we increase the
|
||||
* iterations until we can get something meaningful.
|
||||
*/
|
||||
if (nbTicks < TIMELOOP_MIN) {
|
||||
/* Not enough time spent in benchmarking, risk of rounding bias */
|
||||
if (nbTicks == 0) { /* faster than resolution timer */
|
||||
nbh_perIteration *= 100;
|
||||
} else {
|
||||
/*
|
||||
* update nbh_perIteration so that the next round lasts
|
||||
* approximately 1 second.
|
||||
*/
|
||||
double nbh_perSecond = (1 / ticksPerHash) + 1;
|
||||
if (nbh_perSecond > (double)(4000U<<20)) nbh_perSecond = (double)(4000U<<20); /* avoid overflow */
|
||||
nbh_perIteration = (XSUM_U32)nbh_perSecond;
|
||||
}
|
||||
/* g_nbIterations==0 => quick evaluation, no claim of accuracy */
|
||||
if (g_nbIterations>0) {
|
||||
iterationNb--; /* new round for a more accurate speed evaluation */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ticksPerHash < fastestH) fastestH = ticksPerHash;
|
||||
if (fastestH>0.) { /* avoid div by zero */
|
||||
XSUM_logVerbose(2, "%2i-%-*.*s : %10u -> %8.0f it/s (%7.1f MB/s) \r",
|
||||
iterationNb,
|
||||
HASHNAME_MAX, HASHNAME_MAX, hName,
|
||||
(unsigned)bufferSize,
|
||||
(double)1 / fastestH,
|
||||
((double)bufferSize / (1 MB)) / fastestH);
|
||||
} }
|
||||
{ double nbh_perSecond = (1 / fastestH) + 1;
|
||||
if (nbh_perSecond > (double)(4000U<<20)) nbh_perSecond = (double)(4000U<<20); /* avoid overflow */
|
||||
nbh_perIteration = (XSUM_U32)nbh_perSecond;
|
||||
}
|
||||
}
|
||||
XSUM_logVerbose(1, "%2i#%-*.*s : %10u -> %8.0f it/s (%7.1f MB/s) \n",
|
||||
testID,
|
||||
HASHNAME_MAX, HASHNAME_MAX, hName,
|
||||
(unsigned)bufferSize,
|
||||
(double)1 / fastestH,
|
||||
((double)bufferSize / (1 MB)) / fastestH);
|
||||
if (XSUM_logLevel<1)
|
||||
XSUM_logVerbose(0, "%u, ", (unsigned)((double)1 / fastestH));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocates a string containing s1 and s2 concatenated. Acts like strdup.
|
||||
* The result must be freed.
|
||||
*/
|
||||
static char* XSUM_strcatDup(const char* s1, const char* s2)
|
||||
{
|
||||
assert(s1 != NULL);
|
||||
assert(s2 != NULL);
|
||||
{ size_t len1 = strlen(s1);
|
||||
size_t len2 = strlen(s2);
|
||||
char* buf = (char*)malloc(len1 + len2 + 1);
|
||||
if (buf != NULL) {
|
||||
/* strcpy(buf, s1) */
|
||||
memcpy(buf, s1, len1);
|
||||
/* strcat(buf, s2) */
|
||||
memcpy(buf + len1, s2, len2 + 1);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* XSUM_benchMem():
|
||||
* Benchmark provided content up to twice per function:
|
||||
* - once at provided aligned memory address (%16)
|
||||
* - second time at unaligned memory address (+3)
|
||||
* Enabled functions and modes are provided via @g_hashesToBench global variable.
|
||||
* @buffer: Must be 16-byte aligned.
|
||||
* The allocated size of underlying @buffer must be >= (@bufferSize+3).
|
||||
* This function also fills @g_benchSecretBuf, to bench XXH3's _withSecret() variants.
|
||||
*/
|
||||
static void XSUM_benchMem(const void* buffer, size_t bufferSize)
|
||||
{
|
||||
assert((((size_t)buffer) & 15) == 0); /* ensure alignment */
|
||||
XSUM_fillTestBuffer(g_benchSecretBuf, sizeof(g_benchSecretBuf));
|
||||
{ int i;
|
||||
for (i = 1; i < (int)NB_TESTFUNC; i++) {
|
||||
int const hashFuncID = (i-1) / 2;
|
||||
assert(g_hashesToBench[hashFuncID].name != NULL);
|
||||
if (g_testIDs[i] == 0) continue;
|
||||
/* aligned */
|
||||
if ((i % 2) == 1) {
|
||||
XSUM_benchHash(g_hashesToBench[hashFuncID].func, g_hashesToBench[hashFuncID].name, i, buffer, bufferSize);
|
||||
}
|
||||
/* unaligned */
|
||||
if ((i % 2) == 0) {
|
||||
/* Append "unaligned". */
|
||||
char* const hashNameBuf = XSUM_strcatDup(g_hashesToBench[hashFuncID].name, " unaligned");
|
||||
assert(hashNameBuf != NULL);
|
||||
XSUM_benchHash(g_hashesToBench[hashFuncID].func, hashNameBuf, i, ((const char*)buffer)+3, bufferSize);
|
||||
free(hashNameBuf);
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
static size_t XSUM_selectBenchedSize(const char* fileName)
|
||||
{
|
||||
XSUM_U64 const inFileSize = XSUM_getFileSize(fileName);
|
||||
size_t benchedSize = (size_t) XSUM_findMaxMem(inFileSize);
|
||||
if ((XSUM_U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
|
||||
if (benchedSize < inFileSize) {
|
||||
XSUM_log("Not enough memory for '%s' full size; testing %i MB only...\n", fileName, (int)(benchedSize>>20));
|
||||
}
|
||||
return benchedSize;
|
||||
}
|
||||
|
||||
|
||||
int XSUM_benchFiles(const char* fileNamesTable[], int nbFiles)
|
||||
{
|
||||
int fileIdx;
|
||||
for (fileIdx=0; fileIdx<nbFiles; fileIdx++) {
|
||||
const char* const inFileName = fileNamesTable[fileIdx];
|
||||
assert(inFileName != NULL);
|
||||
|
||||
{ FILE* const inFile = XSUM_fopen( inFileName, "rb" );
|
||||
size_t const benchedSize = XSUM_selectBenchedSize(inFileName);
|
||||
char* const buffer = (char*)calloc(benchedSize+16+3, 1);
|
||||
void* const alignedBuffer = (buffer+15) - (((size_t)(buffer+15)) & 0xF); /* align on next 16 bytes */
|
||||
|
||||
/* Checks */
|
||||
if (inFile==NULL){
|
||||
XSUM_log("Error: Could not open '%s': %s.\n", inFileName, strerror(errno));
|
||||
free(buffer);
|
||||
exit(11);
|
||||
}
|
||||
if(!buffer) {
|
||||
XSUM_log("\nError: Out of memory.\n");
|
||||
fclose(inFile);
|
||||
exit(12);
|
||||
}
|
||||
|
||||
/* Fill input buffer */
|
||||
{ size_t const readSize = fread(alignedBuffer, 1, benchedSize, inFile);
|
||||
fclose(inFile);
|
||||
if(readSize != benchedSize) {
|
||||
XSUM_log("\nError: Could not read '%s': %s.\n", inFileName, strerror(errno));
|
||||
free(buffer);
|
||||
exit(13);
|
||||
} }
|
||||
|
||||
/* bench */
|
||||
XSUM_benchMem(alignedBuffer, benchedSize);
|
||||
|
||||
free(buffer);
|
||||
} }
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int XSUM_benchInternal(size_t keySize)
|
||||
{
|
||||
void* const buffer = calloc(keySize+16+3, 1);
|
||||
if (buffer == NULL) {
|
||||
XSUM_log("\nError: Out of memory.\n");
|
||||
exit(12);
|
||||
}
|
||||
|
||||
{ const void* const alignedBuffer = ((char*)buffer+15) - (((size_t)((char*)buffer+15)) & 0xF); /* align on next 16 bytes */
|
||||
|
||||
/* bench */
|
||||
XSUM_logVerbose(1, "Sample of ");
|
||||
if (keySize > 10 KB) {
|
||||
XSUM_logVerbose(1, "%u KB", (unsigned)(keySize >> 10));
|
||||
} else {
|
||||
XSUM_logVerbose(1, "%u bytes", (unsigned)keySize);
|
||||
}
|
||||
XSUM_logVerbose(1, "... \n");
|
||||
|
||||
XSUM_benchMem(alignedBuffer, keySize);
|
||||
free(buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* xsum_bench - Benchmark functions for xxhsum
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#ifndef XSUM_BENCH_H
|
||||
#define XSUM_BENCH_H
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
#define NBLOOPS_DEFAULT 3 /* Default number of benchmark iterations */
|
||||
|
||||
extern int const g_nbTestFunctions;
|
||||
extern char g_testIDs[]; /* size : g_nbTestFunctions */
|
||||
extern const char k_testIDs_default[];
|
||||
extern int g_nbIterations;
|
||||
|
||||
int XSUM_benchInternal(size_t keySize);
|
||||
int XSUM_benchFiles(const char* fileNamesTable[], int nbFiles);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XSUM_BENCH_H */
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* xxhsum - Command line interface for xxhash algorithms
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
/*
|
||||
* This contains various configuration parameters and feature detection for
|
||||
* xxhsum.
|
||||
*
|
||||
* Similar to config.h in Autotools, this should be the first header included.
|
||||
*/
|
||||
|
||||
#ifndef XSUM_CONFIG_H
|
||||
#define XSUM_CONFIG_H
|
||||
|
||||
|
||||
/* ************************************
|
||||
* Compiler Options
|
||||
**************************************/
|
||||
/*
|
||||
* Disable Visual C's warnings when using the "insecure" CRT functions instead
|
||||
* of the "secure" _s functions.
|
||||
*
|
||||
* These functions are not portable, and aren't necessary if you are using the
|
||||
* original functions properly.
|
||||
*/
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
# ifndef _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Under Linux at least, pull in the *64 commands */
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
# define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
/*
|
||||
* So we can use __attribute__((__format__))
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
# define XSUM_ATTRIBUTE(x) __attribute__(x)
|
||||
#else
|
||||
# define XSUM_ATTRIBUTE(x)
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) /* UNIX-like OS */ \
|
||||
|| defined(__midipix__) || defined(__VMS))
|
||||
# if (defined(__APPLE__) && defined(__MACH__)) || defined(__SVR4) || defined(_AIX) || defined(__hpux) /* POSIX.1-2001 (SUSv3) conformant */ \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) /* BSD distros */
|
||||
# define XSUM_PLATFORM_POSIX_VERSION 200112L
|
||||
# else
|
||||
# if defined(__linux__) || defined(__linux)
|
||||
# ifndef _POSIX_C_SOURCE
|
||||
# define _POSIX_C_SOURCE 200112L /* use feature test macro */
|
||||
# endif
|
||||
# endif
|
||||
# include <unistd.h> /* declares _POSIX_VERSION */
|
||||
# if defined(_POSIX_VERSION) /* POSIX compliant */
|
||||
# define XSUM_PLATFORM_POSIX_VERSION _POSIX_VERSION
|
||||
# else
|
||||
# define XSUM_PLATFORM_POSIX_VERSION 0
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(XSUM_PLATFORM_POSIX_VERSION)
|
||||
# define XSUM_PLATFORM_POSIX_VERSION -1
|
||||
#endif
|
||||
|
||||
#if !defined(S_ISREG)
|
||||
# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
|
||||
/* ************************************
|
||||
* Windows helpers
|
||||
**************************************/
|
||||
|
||||
/*
|
||||
* Whether to use the Windows UTF-16 APIs instead of the portable libc 8-bit
|
||||
* ("ANSI") APIs.
|
||||
*
|
||||
* Windows is not UTF-8 clean by default, and the only way to access every file
|
||||
* on the OS is to use UTF-16.
|
||||
*
|
||||
* Do note that xxhsum uses UTF-8 internally and only uses UTF-16 for command
|
||||
* line arguments, console I/O, and opening files.
|
||||
*
|
||||
* Additionally, this guarantees all piped output is UTF-8.
|
||||
*/
|
||||
#if defined(XSUM_WIN32_USE_WCHAR) && !defined(_WIN32)
|
||||
/* We use Windows APIs, only use this on Windows. */
|
||||
# undef XSUM_WIN32_USE_WCHAR
|
||||
#endif
|
||||
|
||||
#ifndef XSUM_WIN32_USE_WCHAR
|
||||
# if defined(_WIN32)
|
||||
# include <wchar.h>
|
||||
# if WCHAR_MAX == 0xFFFFU /* UTF-16 wchar_t */
|
||||
# define XSUM_WIN32_USE_WCHAR 1
|
||||
# else
|
||||
# define XSUM_WIN32_USE_WCHAR 0
|
||||
# endif
|
||||
# else
|
||||
# define XSUM_WIN32_USE_WCHAR 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !XSUM_WIN32_USE_WCHAR
|
||||
/*
|
||||
* It doesn't make sense to have one without the other.
|
||||
* Due to XSUM_WIN32_USE_WCHAR being undef'd, this also handles
|
||||
* non-WIN32 platforms.
|
||||
*/
|
||||
# undef XSUM_WIN32_USE_WMAIN
|
||||
# define XSUM_WIN32_USE_WMAIN 0
|
||||
#else
|
||||
/*
|
||||
* Whether to use wmain() or main().
|
||||
*
|
||||
* wmain() is preferred because we don't have to mess with internal hidden
|
||||
* APIs.
|
||||
*
|
||||
* It always works on MSVC, but in MinGW, it only works on MinGW-w64 with the
|
||||
* -municode flag.
|
||||
*
|
||||
* Therefore we have to use main() -- there is no better option.
|
||||
*/
|
||||
# ifndef XSUM_WIN32_USE_WMAIN
|
||||
# if defined(_UNICODE) || defined(UNICODE) /* MinGW -municode */ \
|
||||
|| defined(_MSC_VER) /* MSVC */
|
||||
# define XSUM_WIN32_USE_WMAIN 1
|
||||
# else
|
||||
# define XSUM_WIN32_USE_WMAIN 0
|
||||
# endif
|
||||
# endif
|
||||
/*
|
||||
* It is always good practice to define these to prevent accidental use of the
|
||||
* ANSI APIs, even if the program primarily uses UTF-8.
|
||||
*/
|
||||
# ifndef _UNICODE
|
||||
# define _UNICODE
|
||||
# endif
|
||||
# ifndef UNICODE
|
||||
# define UNICODE
|
||||
# endif
|
||||
#endif /* XSUM_WIN32_USE_WCHAR */
|
||||
|
||||
#ifndef XSUM_API
|
||||
# ifdef XXH_INLINE_ALL
|
||||
# define XSUM_API static
|
||||
# else
|
||||
# define XSUM_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef XSUM_NO_TESTS
|
||||
# define XSUM_NO_TESTS 0
|
||||
#endif
|
||||
|
||||
/* ***************************
|
||||
* Basic types
|
||||
* ***************************/
|
||||
|
||||
#if defined(__cplusplus) /* C++ */ \
|
||||
|| (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) /* C99 */
|
||||
# include <stdint.h>
|
||||
typedef uint8_t XSUM_U8;
|
||||
typedef uint32_t XSUM_U32;
|
||||
typedef uint64_t XSUM_U64;
|
||||
# else
|
||||
# include <limits.h>
|
||||
typedef unsigned char XSUM_U8;
|
||||
# if UINT_MAX == 0xFFFFFFFFUL
|
||||
typedef unsigned int XSUM_U32;
|
||||
# else
|
||||
typedef unsigned long XSUM_U32;
|
||||
# endif
|
||||
typedef unsigned long long XSUM_U64;
|
||||
#endif /* not C++/C99 */
|
||||
|
||||
/* ***************************
|
||||
* Common constants
|
||||
* ***************************/
|
||||
|
||||
#define KB *( 1<<10)
|
||||
#define MB *( 1<<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
|
||||
#endif /* XSUM_CONFIG_H */
|
||||
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
* xxhsum - Command line interface for xxhash algorithms
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#include "xsum_os_specific.h" /* XSUM_API */
|
||||
#include <sys/stat.h> /* stat() / _stat64() */
|
||||
|
||||
/*
|
||||
* This file contains all of the ugly boilerplate to make xxhsum work across
|
||||
* platforms.
|
||||
*/
|
||||
#if defined(_MSC_VER) || XSUM_WIN32_USE_WCHAR
|
||||
typedef struct __stat64 XSUM_stat_t;
|
||||
# if defined(_MSC_VER)
|
||||
typedef int mode_t;
|
||||
# endif
|
||||
#else
|
||||
typedef struct stat XSUM_stat_t;
|
||||
#endif
|
||||
|
||||
#if defined(__EMSCRIPTEN__) && defined(XSUM_NODE_JS)
|
||||
# include <unistd.h> /* isatty */
|
||||
# include <emscripten.h> /* EM_ASM_INT */
|
||||
|
||||
/* The Emscripten SDK does not properly detect when the standard streams
|
||||
* are piped to node.js, and there does not seem to be any way to tell in
|
||||
* plain C. To work around it, inline JavaScript is used to call Node's
|
||||
* isatty() function. */
|
||||
static int XSUM_IS_CONSOLE(FILE* stdStream)
|
||||
{
|
||||
/* https://github.com/iliakan/detect-node */
|
||||
int is_node = EM_ASM_INT((
|
||||
return (Object.prototype.toString.call(
|
||||
typeof process !== 'undefined' ? process : 0
|
||||
) == '[object process]') | 0
|
||||
));
|
||||
if (is_node) {
|
||||
return EM_ASM_INT(
|
||||
return require('node:tty').isatty($0),
|
||||
fileno(stdStream)
|
||||
);
|
||||
} else {
|
||||
return isatty(fileno(stdStream));
|
||||
}
|
||||
}
|
||||
#elif defined(__EMSCRIPTEN__) || (defined(__linux__) && (XSUM_PLATFORM_POSIX_VERSION >= 1)) \
|
||||
|| (XSUM_PLATFORM_POSIX_VERSION >= 200112L) \
|
||||
|| defined(__DJGPP__) \
|
||||
|| defined(__MSYS__) \
|
||||
|| defined(__HAIKU__)
|
||||
# ifdef __OpenBSD__
|
||||
# include <errno.h> /* errno */
|
||||
# include <string.h> /* strerror */
|
||||
# include "xsum_output.h" /* XSUM_log */
|
||||
# endif
|
||||
# include <unistd.h> /* isatty */
|
||||
# define XSUM_IS_CONSOLE(stdStream) isatty(fileno(stdStream))
|
||||
#elif defined(MSDOS) || defined(OS2)
|
||||
# include <io.h> /* _isatty */
|
||||
# define XSUM_IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
|
||||
#elif defined(_WIN32)
|
||||
# include <io.h> /* _isatty */
|
||||
# include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */
|
||||
# include <stdio.h> /* FILE */
|
||||
static __inline int XSUM_IS_CONSOLE(FILE* stdStream)
|
||||
{
|
||||
DWORD dummy;
|
||||
return _isatty(_fileno(stdStream)) && GetConsoleMode((HANDLE)_get_osfhandle(_fileno(stdStream)), &dummy);
|
||||
}
|
||||
#else
|
||||
# define XSUM_IS_CONSOLE(stdStream) 0
|
||||
#endif
|
||||
|
||||
#if defined(MSDOS) || defined(OS2) || defined(_WIN32)
|
||||
# include <fcntl.h> /* _O_BINARY */
|
||||
# include <io.h> /* _setmode, _fileno, _get_osfhandle */
|
||||
# if !defined(__DJGPP__)
|
||||
# include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */
|
||||
# include <winioctl.h> /* FSCTL_SET_SPARSE */
|
||||
# define XSUM_SET_BINARY_MODE(file) { int const unused=_setmode(_fileno(file), _O_BINARY); (void)unused; }
|
||||
# else
|
||||
# define XSUM_SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
|
||||
# endif
|
||||
#else
|
||||
# define XSUM_SET_BINARY_MODE(file) ((void)file)
|
||||
#endif
|
||||
|
||||
XSUM_API int XSUM_isConsole(FILE* stream)
|
||||
{
|
||||
return XSUM_IS_CONSOLE(stream);
|
||||
}
|
||||
|
||||
XSUM_API void XSUM_setBinaryMode(FILE* stream)
|
||||
{
|
||||
XSUM_SET_BINARY_MODE(stream);
|
||||
}
|
||||
|
||||
#if !XSUM_WIN32_USE_WCHAR
|
||||
|
||||
XSUM_API FILE* XSUM_fopen(const char* filename, const char* mode)
|
||||
{
|
||||
return fopen(filename, mode);
|
||||
}
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 2, 0)))
|
||||
XSUM_API int XSUM_vfprintf(FILE* stream, const char* format, va_list ap)
|
||||
{
|
||||
return vfprintf(stream, format, ap);
|
||||
}
|
||||
|
||||
static int XSUM_stat(const char* infilename, XSUM_stat_t* statbuf)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return _stat64(infilename, statbuf);
|
||||
#else
|
||||
return stat(infilename, statbuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef XSUM_NO_MAIN
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
#ifdef __OpenBSD__
|
||||
/*
|
||||
* xxhsum(1) does not create or write files, permit reading only.
|
||||
*/
|
||||
if (pledge("stdio rpath", NULL) == -1) {
|
||||
XSUM_log("pledge: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return XSUM_main(argc, argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Unicode helpers for Windows to make UTF-8 act as it should. */
|
||||
#else
|
||||
# include <windows.h>
|
||||
# include <wchar.h>
|
||||
|
||||
/*****************************************************************************
|
||||
* Unicode conversion tools
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Converts a UTF-8 string to UTF-16. Acts like strdup. The string must be freed afterwards.
|
||||
* This version allows keeping the output length.
|
||||
*/
|
||||
static wchar_t* XSUM_widenString(const char* str, int* lenOut)
|
||||
{
|
||||
int const len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||
if (lenOut != NULL) *lenOut = len;
|
||||
if (len == 0) return NULL;
|
||||
{ wchar_t* buf = (wchar_t*)malloc((size_t)len * sizeof(wchar_t));
|
||||
if (buf != NULL) {
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len) == 0) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
} }
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a UTF-16 string to UTF-8. Acts like strdup. The string must be freed afterwards.
|
||||
* This version allows keeping the output length.
|
||||
*/
|
||||
static char* XSUM_narrowString(const wchar_t *str, int *lenOut)
|
||||
{
|
||||
int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
|
||||
if (lenOut != NULL) *lenOut = len;
|
||||
if (len == 0) return NULL;
|
||||
{ char* const buf = (char*)malloc((size_t)len * sizeof(char));
|
||||
if (buf != NULL) {
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, len, NULL, NULL) == 0) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
} }
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* File helpers
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* fopen wrapper that supports UTF-8
|
||||
*
|
||||
* fopen will only accept ANSI filenames, which means that we can't open Unicode filenames.
|
||||
*
|
||||
* In order to open a Unicode filename, we need to convert filenames to UTF-16 and use _wfopen.
|
||||
*/
|
||||
XSUM_API FILE* XSUM_fopen(const char* filename, const char* mode)
|
||||
{
|
||||
FILE* f = NULL;
|
||||
wchar_t* const wide_filename = XSUM_widenString(filename, NULL);
|
||||
if (wide_filename != NULL) {
|
||||
wchar_t* const wide_mode = XSUM_widenString(mode, NULL);
|
||||
if (wide_mode != NULL) {
|
||||
f = _wfopen(wide_filename, wide_mode);
|
||||
free(wide_mode);
|
||||
}
|
||||
free(wide_filename);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/*
|
||||
* stat() wrapper which supports UTF-8 filenames.
|
||||
*/
|
||||
static int XSUM_stat(const char* infilename, XSUM_stat_t* statbuf)
|
||||
{
|
||||
int r = -1;
|
||||
wchar_t* const wide_filename = XSUM_widenString(infilename, NULL);
|
||||
if (wide_filename != NULL) {
|
||||
r = _wstat64(wide_filename, statbuf);
|
||||
free(wide_filename);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case it isn't available, this is what MSVC 2019 defines in stdarg.h.
|
||||
*/
|
||||
#if defined(_MSC_VER) && !defined(__clang__) && !defined(va_copy)
|
||||
# define XSUM_va_copy(destination, source) ((destination) = (source))
|
||||
#else
|
||||
# define XSUM_va_copy(destination, source) va_copy(destination, source)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* vasprintf for Windows.
|
||||
*/
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 2, 0)))
|
||||
static int XSUM_vasprintf(char** strp, const char* format, va_list ap)
|
||||
{
|
||||
int size;
|
||||
va_list copy;
|
||||
/*
|
||||
* To be safe, make a va_copy.
|
||||
*
|
||||
* Note that Microsoft doesn't use va_copy in its sample code:
|
||||
* https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsprintf-vsprintf-l-vswprintf-vswprintf-l-vswprintf-l?view=vs-2019
|
||||
*/
|
||||
XSUM_va_copy(copy, ap);
|
||||
/* Calculate how many characters we need */
|
||||
size = _vscprintf(format, ap);
|
||||
va_end(copy);
|
||||
|
||||
if (size < 0) {
|
||||
*strp = NULL;
|
||||
return size;
|
||||
} else {
|
||||
int ret;
|
||||
*strp = (char*) malloc((size_t)size + 1);
|
||||
if (*strp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* vsprintf into the new buffer */
|
||||
ret = vsprintf(*strp, format, ap);
|
||||
if (ret < 0) {
|
||||
free(*strp);
|
||||
*strp = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fprintf wrapper that supports UTF-8.
|
||||
*
|
||||
* fprintf doesn't properly handle Unicode on Windows.
|
||||
*
|
||||
* Additionally, it is codepage sensitive on console and may crash the program.
|
||||
*
|
||||
* Instead, we use vsnprintf, and either print with fwrite or convert to UTF-16
|
||||
* for console output and use the codepage-independent WriteConsoleW.
|
||||
*
|
||||
* Credit to t-mat: https://github.com/t-mat/xxHash/commit/5691423
|
||||
*/
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 2, 0)))
|
||||
XSUM_API int XSUM_vfprintf(FILE *stream, const char *format, va_list ap)
|
||||
{
|
||||
int result;
|
||||
char* u8_str = NULL;
|
||||
|
||||
/*
|
||||
* Generate the UTF-8 output string with vasprintf.
|
||||
*/
|
||||
result = XSUM_vasprintf(&u8_str, format, ap);
|
||||
|
||||
if (result >= 0) {
|
||||
const size_t nchar = (size_t)result + 1;
|
||||
|
||||
/*
|
||||
* Check if we are outputting to a console. Don't use XSUM_isConsole
|
||||
* directly -- we don't need to call _get_osfhandle twice.
|
||||
*/
|
||||
int fileNb = _fileno(stream);
|
||||
intptr_t handle_raw = _get_osfhandle(fileNb);
|
||||
HANDLE handle = (HANDLE)handle_raw;
|
||||
DWORD dwTemp;
|
||||
|
||||
if (handle_raw < 0) {
|
||||
result = -1;
|
||||
} else if (_isatty(fileNb) && GetConsoleMode(handle, &dwTemp)) {
|
||||
/*
|
||||
* Convert to UTF-16 and output with WriteConsoleW.
|
||||
*
|
||||
* This is codepage independent and works on Windows XP's default
|
||||
* msvcrt.dll.
|
||||
*/
|
||||
int len;
|
||||
wchar_t* const u16_buf = XSUM_widenString(u8_str, &len);
|
||||
if (u16_buf == NULL) {
|
||||
result = -1;
|
||||
} else {
|
||||
if (WriteConsoleW(handle, u16_buf, (DWORD)len - 1, &dwTemp, NULL)) {
|
||||
result = (int)dwTemp;
|
||||
} else {
|
||||
result = -1;
|
||||
}
|
||||
free(u16_buf);
|
||||
}
|
||||
} else {
|
||||
/* fwrite the UTF-8 string if we are printing to a file */
|
||||
result = (int)fwrite(u8_str, 1, nchar - 1, stream);
|
||||
if (result == 0) {
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
free(u8_str);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef XSUM_NO_MAIN
|
||||
/*****************************************************************************
|
||||
* Command Line argument parsing
|
||||
*****************************************************************************/
|
||||
|
||||
/* Converts a UTF-16 argv to UTF-8. */
|
||||
static char** XSUM_convertArgv(int argc, wchar_t* utf16_argv[])
|
||||
{
|
||||
char** const utf8_argv = (char**)malloc((size_t)(argc + 1) * sizeof(char*));
|
||||
if (utf8_argv != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < argc; i++) {
|
||||
utf8_argv[i] = XSUM_narrowString(utf16_argv[i], NULL);
|
||||
if (utf8_argv[i] == NULL) {
|
||||
/* Out of memory, whoops. */
|
||||
while (i-- > 0) {
|
||||
free(utf8_argv[i]);
|
||||
}
|
||||
free(utf8_argv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
utf8_argv[argc] = NULL;
|
||||
}
|
||||
return utf8_argv;
|
||||
}
|
||||
/* Frees arguments returned by XSUM_convertArgv */
|
||||
static void XSUM_freeArgv(int argc, char** argv)
|
||||
{
|
||||
int i;
|
||||
if (argv == NULL) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < argc; i++) {
|
||||
free(argv[i]);
|
||||
}
|
||||
free(argv);
|
||||
}
|
||||
|
||||
static int XSUM_wmain(int argc, wchar_t* utf16_argv[])
|
||||
{
|
||||
/* Convert the UTF-16 arguments to UTF-8. */
|
||||
char** utf8_argv = XSUM_convertArgv(argc, utf16_argv);
|
||||
|
||||
if (utf8_argv == NULL) {
|
||||
/* An unfortunate but incredibly unlikely error. */
|
||||
fprintf(stderr, "xxhsum: error converting command line arguments!\n");
|
||||
abort();
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* MinGW's terminal uses full block buffering for stderr.
|
||||
*
|
||||
* This is nonstandard behavior and causes text to not display until
|
||||
* the buffer fills.
|
||||
*
|
||||
* `setvbuf()` can easily correct this to make text display instantly.
|
||||
*/
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
/* Call our real main function */
|
||||
ret = XSUM_main(argc, (void*)utf8_argv);
|
||||
|
||||
/* Cleanup */
|
||||
XSUM_freeArgv(argc, utf8_argv);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#if XSUM_WIN32_USE_WMAIN
|
||||
|
||||
/*
|
||||
* The preferred method of obtaining the real UTF-16 arguments. Always works
|
||||
* on MSVC, sometimes works on MinGW-w64 depending on the compiler flags.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
int __cdecl wmain(int argc, wchar_t* utf16_argv[])
|
||||
{
|
||||
return XSUM_wmain(argc, utf16_argv);
|
||||
}
|
||||
#else /* !XSUM_WIN32_USE_WMAIN */
|
||||
|
||||
/*
|
||||
* Wrap `XSUM_wmain()` using `main()` and `__wgetmainargs()` on MinGW without
|
||||
* Unicode support.
|
||||
*
|
||||
* `__wgetmainargs()` is used in the CRT startup to retrieve the arguments for
|
||||
* `wmain()`, so we use it on MinGW to emulate `wmain()`.
|
||||
*
|
||||
* It is an internal function and not declared in any public headers, so we
|
||||
* have to declare it manually.
|
||||
*
|
||||
* An alternative that doesn't mess with internal APIs is `GetCommandLineW()`
|
||||
* with `CommandLineToArgvW()`, but the former doesn't expand wildcards and the
|
||||
* latter requires linking to Shell32.dll and its numerous dependencies.
|
||||
*
|
||||
* This method keeps our dependencies to kernel32.dll and the CRT.
|
||||
*
|
||||
* https://docs.microsoft.com/en-us/cpp/c-runtime-library/getmainargs-wgetmainargs?view=vs-2019
|
||||
*/
|
||||
typedef struct {
|
||||
int newmode;
|
||||
} _startupinfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
int __cdecl __wgetmainargs(
|
||||
int* Argc,
|
||||
wchar_t*** Argv,
|
||||
wchar_t*** Env,
|
||||
int DoWildCard,
|
||||
_startupinfo* StartInfo
|
||||
);
|
||||
|
||||
int main(int ansi_argc, const char* ansi_argv[])
|
||||
{
|
||||
int utf16_argc;
|
||||
wchar_t** utf16_argv;
|
||||
wchar_t** utf16_envp; /* Unused but required */
|
||||
_startupinfo startinfo = {0}; /* 0 == don't change new mode */
|
||||
|
||||
/* Get wmain's UTF-16 arguments. Make sure we expand wildcards. */
|
||||
if (__wgetmainargs(&utf16_argc, &utf16_argv, &utf16_envp, 1, &startinfo) < 0)
|
||||
/* In the very unlikely case of an error, use the ANSI arguments. */
|
||||
return XSUM_main(ansi_argc, ansi_argv);
|
||||
|
||||
/* Call XSUM_wmain with our UTF-16 arguments */
|
||||
return XSUM_wmain(utf16_argc, utf16_argv);
|
||||
}
|
||||
|
||||
#endif /* !XSUM_WIN32_USE_WMAIN */
|
||||
#endif /* !XSUM_NO_MAIN */
|
||||
#endif /* XSUM_WIN32_USE_WCHAR */
|
||||
|
||||
|
||||
/*
|
||||
* Determines whether the file at filename is a directory.
|
||||
*/
|
||||
XSUM_API int XSUM_isDirectory(const char* filename)
|
||||
{
|
||||
XSUM_stat_t statbuf;
|
||||
int r = XSUM_stat(filename, &statbuf);
|
||||
#ifdef _MSC_VER
|
||||
if (!r && (statbuf.st_mode & _S_IFDIR)) return 1;
|
||||
#else
|
||||
if (!r && S_ISDIR(statbuf.st_mode)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the filesize of the file at filename.
|
||||
*/
|
||||
XSUM_API XSUM_U64 XSUM_getFileSize(const char* filename)
|
||||
{
|
||||
XSUM_stat_t statbuf;
|
||||
int r = XSUM_stat(filename, &statbuf);
|
||||
if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */
|
||||
return (XSUM_U64)statbuf.st_size;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* xxhsum - Command line interface for xxhash algorithms
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#ifndef XSUM_OS_SPECIFIC_H
|
||||
#define XSUM_OS_SPECIFIC_H
|
||||
|
||||
#include "xsum_config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Declared here to be implemented in user code.
|
||||
*
|
||||
* Functions like main(), but is passed UTF-8 arguments even on Windows.
|
||||
*/
|
||||
XSUM_API int XSUM_main(int argc, const char* argv[]);
|
||||
|
||||
/*
|
||||
* Returns whether stream is a console.
|
||||
*
|
||||
* Functionally equivalent to isatty(fileno(stream)).
|
||||
*/
|
||||
XSUM_API int XSUM_isConsole(FILE* stream);
|
||||
|
||||
/*
|
||||
* Sets stream to pure binary mode (a.k.a. no CRLF conversions).
|
||||
*/
|
||||
XSUM_API void XSUM_setBinaryMode(FILE* stream);
|
||||
|
||||
/*
|
||||
* Returns whether the file at filename is a directory.
|
||||
*/
|
||||
XSUM_API int XSUM_isDirectory(const char* filename);
|
||||
|
||||
/*
|
||||
* Returns the file size of the file at filename.
|
||||
*/
|
||||
XSUM_API XSUM_U64 XSUM_getFileSize(const char* filename);
|
||||
|
||||
/*
|
||||
* UTF-8 stdio wrappers primarily for Windows
|
||||
*/
|
||||
|
||||
/*
|
||||
* fopen() wrapper. Accepts UTF-8 filenames on Windows.
|
||||
*
|
||||
* Specifically, on Windows, the arguments will be converted to UTF-16
|
||||
* and passed to _wfopen().
|
||||
*/
|
||||
XSUM_API FILE* XSUM_fopen(const char* filename, const char* mode);
|
||||
|
||||
/*
|
||||
* vfprintf() wrapper which prints UTF-8 strings to Windows consoles
|
||||
* if applicable.
|
||||
*/
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 2, 0)))
|
||||
XSUM_API int XSUM_vfprintf(FILE* stream, const char* format, va_list ap);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XSUM_OS_SPECIFIC_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* xxhsum - Command line interface for xxhash algorithms
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#include "xsum_output.h"
|
||||
#include "xsum_os_specific.h" /* XSUM_API */
|
||||
|
||||
int XSUM_logLevel = 2;
|
||||
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 1, 2)))
|
||||
XSUM_API int XSUM_log(const char* format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
ret = XSUM_vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 1, 2)))
|
||||
XSUM_API int XSUM_output(const char* format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
ret = XSUM_vfprintf(stdout, format, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 2, 3)))
|
||||
XSUM_API int XSUM_logVerbose(int minLevel, const char* format, ...)
|
||||
{
|
||||
if (XSUM_logLevel >= minLevel) {
|
||||
int ret;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
ret = XSUM_vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* xxhsum - Command line interface for xxhash algorithms
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#ifndef XSUM_OUTPUT_H
|
||||
#define XSUM_OUTPUT_H
|
||||
|
||||
#include "xsum_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* How verbose the output is.
|
||||
*/
|
||||
extern int XSUM_logLevel;
|
||||
|
||||
/*
|
||||
* Same as fprintf(stderr, format, ...)
|
||||
*/
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 1, 2)))
|
||||
XSUM_API int XSUM_log(const char *format, ...);
|
||||
|
||||
/*
|
||||
* Like XSUM_log, but only outputs if XSUM_logLevel >= minLevel.
|
||||
*/
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 2, 3)))
|
||||
XSUM_API int XSUM_logVerbose(int minLevel, const char *format, ...);
|
||||
|
||||
/*
|
||||
* Same as printf(format, ...)
|
||||
*/
|
||||
XSUM_ATTRIBUTE((__format__(__printf__, 1, 2)))
|
||||
XSUM_API int XSUM_output(const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XSUM_OUTPUT_H */
|
||||
@@ -0,0 +1,733 @@
|
||||
/*
|
||||
* xxhsum - Command line interface for xxhash algorithms
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#include "xsum_sanity_check.h"
|
||||
#include "xsum_output.h" /* XSUM_log */
|
||||
#ifndef XXH_STATIC_LINKING_ONLY
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
#endif
|
||||
#include "../xxhash.h"
|
||||
|
||||
#include <stdlib.h> /* exit */
|
||||
#include <assert.h>
|
||||
#include <string.h> /* memcmp */
|
||||
|
||||
/* use #define to make them constant, required for initialization */
|
||||
#define PRIME32 2654435761U
|
||||
#define PRIME64 11400714785074694797ULL
|
||||
|
||||
/*
|
||||
* Fills a test buffer with pseudorandom data.
|
||||
*
|
||||
* This is used in the sanity check - its values must not be changed.
|
||||
*/
|
||||
XSUM_API void XSUM_fillTestBuffer(XSUM_U8* buffer, size_t len)
|
||||
{
|
||||
XSUM_U64 byteGen = PRIME32;
|
||||
size_t i;
|
||||
|
||||
assert(buffer != NULL);
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
buffer[i] = (XSUM_U8)(byteGen>>56);
|
||||
byteGen *= PRIME64;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ************************************************
|
||||
* Self-test:
|
||||
* ensure results consistency across platforms
|
||||
*********************************************** */
|
||||
#if XSUM_NO_TESTS
|
||||
XSUM_API void XSUM_sanityCheck(void)
|
||||
{
|
||||
XSUM_log("This version of xxhsum is not verified.\n");
|
||||
}
|
||||
#else
|
||||
|
||||
/*
|
||||
* Test data vectors
|
||||
*/
|
||||
typedef struct {
|
||||
XSUM_U32 len;
|
||||
XSUM_U32 seed;
|
||||
XSUM_U32 Nresult;
|
||||
} XSUM_testdata32_t;
|
||||
|
||||
typedef struct {
|
||||
XSUM_U32 len;
|
||||
XSUM_U64 seed;
|
||||
XSUM_U64 Nresult;
|
||||
} XSUM_testdata64_t;
|
||||
|
||||
typedef struct {
|
||||
XSUM_U32 len;
|
||||
XSUM_U64 seed;
|
||||
XXH128_hash_t Nresult;
|
||||
} XSUM_testdata128_t;
|
||||
|
||||
#define SECRET_SAMPLE_NBBYTES 5
|
||||
typedef struct {
|
||||
XSUM_U32 seedLen;
|
||||
XSUM_U32 secretLen;
|
||||
XSUM_U8 byte[SECRET_SAMPLE_NBBYTES];
|
||||
} XSUM_testdata_sample_t;
|
||||
|
||||
/* XXH32 */
|
||||
static const XSUM_testdata32_t XSUM_XXH32_testdata[] = {
|
||||
{ 0, 0, 0x02CC5D05U },
|
||||
{ 0, PRIME32, 0x36B78AE7U },
|
||||
{ 1, 0, 0xCF65B03EU },
|
||||
{ 1, PRIME32, 0xB4545AA4U },
|
||||
{ 14, 0, 0x1208E7E2U },
|
||||
{ 14, PRIME32, 0x6AF1D1FEU },
|
||||
{ 222, 0, 0x5BD11DBDU },
|
||||
{ 222, PRIME32, 0x58803C5FU }
|
||||
};
|
||||
|
||||
/* XXH64 */
|
||||
static const XSUM_testdata64_t XSUM_XXH64_testdata[] = {
|
||||
{ 0, 0, 0xEF46DB3751D8E999ULL },
|
||||
{ 0, PRIME32, 0xAC75FDA2929B17EFULL },
|
||||
{ 1, 0, 0xE934A84ADB052768ULL },
|
||||
{ 1, PRIME32, 0x5014607643A9B4C3ULL },
|
||||
{ 4, 0, 0x9136A0DCA57457EEULL },
|
||||
{ 14, 0, 0x8282DCC4994E35C8ULL },
|
||||
{ 14, PRIME32, 0xC3BD6BF63DEB6DF0ULL },
|
||||
{ 222, 0, 0xB641AE8CB691C174ULL },
|
||||
{ 222, PRIME32, 0x20CB8AB7AE10C14AULL }
|
||||
};
|
||||
/*
|
||||
* XXH3:
|
||||
* Due to being a more complex hash function with specializations for certain
|
||||
* lengths, a more extensive test is used for XXH3.
|
||||
*/
|
||||
|
||||
/* XXH3_64bits, seeded */
|
||||
static const XSUM_testdata64_t XSUM_XXH3_testdata[] = {
|
||||
{ 0, 0, 0x2D06800538D394C2ULL }, /* empty string */
|
||||
{ 0, PRIME64, 0xA8A6B918B2F0364AULL },
|
||||
{ 1, 0, 0xC44BDFF4074EECDBULL }, /* 1 - 3 */
|
||||
{ 1, PRIME64, 0x032BE332DD766EF8ULL },
|
||||
{ 6, 0, 0x27B56A84CD2D7325ULL }, /* 4 - 8 */
|
||||
{ 6, PRIME64, 0x84589C116AB59AB9ULL },
|
||||
{ 12, 0, 0xA713DAF0DFBB77E7ULL }, /* 9 - 16 */
|
||||
{ 12, PRIME64, 0xE7303E1B2336DE0EULL },
|
||||
{ 24, 0, 0xA3FE70BF9D3510EBULL }, /* 17 - 32 */
|
||||
{ 24, PRIME64, 0x850E80FC35BDD690ULL },
|
||||
{ 48, 0, 0x397DA259ECBA1F11ULL }, /* 33 - 64 */
|
||||
{ 48, PRIME64, 0xADC2CBAA44ACC616ULL },
|
||||
{ 80, 0, 0xBCDEFBBB2C47C90AULL }, /* 65 - 96 */
|
||||
{ 80, PRIME64, 0xC6DD0CB699532E73ULL },
|
||||
{ 195, 0, 0xCD94217EE362EC3AULL }, /* 129-240 */
|
||||
{ 195, PRIME64, 0xBA68003D370CB3D9ULL },
|
||||
|
||||
{ 403, 0, 0xCDEB804D65C6DEA4ULL }, /* one block, last stripe is overlapping */
|
||||
{ 403, PRIME64, 0x6259F6ECFD6443FDULL },
|
||||
{ 512, 0, 0x617E49599013CB6BULL }, /* one block, finishing at stripe boundary */
|
||||
{ 512, PRIME64, 0x3CE457DE14C27708ULL },
|
||||
{ 2048, 0, 0xDD59E2C3A5F038E0ULL }, /* 2 blocks, finishing at block boundary */
|
||||
{ 2048, PRIME64, 0x66F81670669ABABCULL },
|
||||
{ 2099, 0, 0xC6B9D9B3FC9AC765ULL }, /* 2 blocks + 1 partial block, to detect off-by-one scrambling issues, like #816 */
|
||||
{ 2099, PRIME64, 0x184F316843663974ULL },
|
||||
{ 2240, 0, 0x6E73A90539CF2948ULL }, /* 3 blocks, finishing at stripe boundary */
|
||||
{ 2240, PRIME64, 0x757BA8487D1B5247ULL },
|
||||
{ 2367, 0, 0xCB37AEB9E5D361EDULL }, /* 3 blocks, last stripe is overlapping */
|
||||
{ 2367, PRIME64, 0xD2DB3415B942B42AULL }
|
||||
};
|
||||
/* XXH3_64bits, custom secret */
|
||||
static const XSUM_testdata64_t XSUM_XXH3_withSecret_testdata[] = {
|
||||
{ 0, 0, 0x3559D64878C5C66CULL }, /* empty string */
|
||||
{ 1, 0, 0x8A52451418B2DA4DULL }, /* 1 - 3 */
|
||||
{ 6, 0, 0x82C90AB0519369ADULL }, /* 4 - 8 */
|
||||
{ 12, 0, 0x14631E773B78EC57ULL }, /* 9 - 16 */
|
||||
{ 24, 0, 0xCDD5542E4A9D9FE8ULL }, /* 17 - 32 */
|
||||
{ 48, 0, 0x33ABD54D094B2534ULL }, /* 33 - 64 */
|
||||
{ 80, 0, 0xE687BA1684965297ULL }, /* 65 - 96 */
|
||||
{ 195, 0, 0xA057273F5EECFB20ULL }, /* 129-240 */
|
||||
|
||||
{ 403, 0, 0x14546019124D43B8ULL }, /* one block, last stripe is overlapping */
|
||||
{ 512, 0, 0x7564693DD526E28DULL }, /* one block, finishing at stripe boundary */
|
||||
{ 2048, 0, 0xD32E975821D6519FULL }, /* >= 2 blodcks, at least one scrambling */
|
||||
{ 2367, 0, 0x293FA8E5173BB5E7ULL }, /* >= 2 blocks, at least one scrambling, last stripe unaligned */
|
||||
|
||||
{ 64*10*3, 0, 0x751D2EC54BC6038BULL } /* exactly 3 full blocks, not a multiple of 256 */
|
||||
};
|
||||
/* XXH3_128bits, seeded */
|
||||
static const XSUM_testdata128_t XSUM_XXH128_testdata[] = {
|
||||
{ 0, 0, { 0x6001C324468D497FULL, 0x99AA06D3014798D8ULL } }, /* empty string */
|
||||
{ 0, PRIME32, { 0x5444F7869C671AB0ULL, 0x92220AE55E14AB50ULL } },
|
||||
{ 1, 0, { 0xC44BDFF4074EECDBULL, 0xA6CD5E9392000F6AULL } }, /* 1 - 3 */
|
||||
{ 1, PRIME32, { 0xB53D5557E7F76F8DULL, 0x89B99554BA22467CULL } },
|
||||
{ 6, 0, { 0x3E7039BDDA43CFC6ULL, 0x082AFE0B8162D12AULL } }, /* 4 - 8 */
|
||||
{ 6, PRIME32, { 0x269D8F70BE98856EULL, 0x5A865B5389ABD2B1ULL } },
|
||||
{ 12, 0, { 0x061A192713F69AD9ULL, 0x6E3EFD8FC7802B18ULL } }, /* 9 - 16 */
|
||||
{ 12, PRIME32, { 0x9BE9F9A67F3C7DFBULL, 0xD7E09D518A3405D3ULL } },
|
||||
{ 24, 0, { 0x1E7044D28B1B901DULL, 0x0CE966E4678D3761ULL } }, /* 17 - 32 */
|
||||
{ 24, PRIME32, { 0xD7304C54EBAD40A9ULL, 0x3162026714A6A243ULL } },
|
||||
{ 48, 0, { 0xF942219AED80F67BULL, 0xA002AC4E5478227EULL } }, /* 33 - 64 */
|
||||
{ 48, PRIME32, { 0x7BA3C3E453A1934EULL, 0x163ADDE36C072295ULL } },
|
||||
{ 81, 0, { 0x5E8BAFB9F95FB803ULL, 0x4952F58181AB0042ULL } }, /* 65 - 96 */
|
||||
{ 81, PRIME32, { 0x703FBB3D7A5F755CULL, 0x2724EC7ADC750FB6ULL } },
|
||||
{ 222, 0, { 0xF1AEBD597CEC6B3AULL, 0x337E09641B948717ULL } }, /* 129-240 */
|
||||
{ 222, PRIME32, { 0xAE995BB8AF917A8DULL, 0x91820016621E97F1ULL } },
|
||||
|
||||
{ 403, 0, { 0xCDEB804D65C6DEA4ULL, 0x1B6DE21E332DD73DULL } }, /* one block, last stripe is overlapping */
|
||||
{ 403, PRIME64, { 0x6259F6ECFD6443FDULL, 0xBED311971E0BE8F2ULL } },
|
||||
{ 512, 0, { 0x617E49599013CB6BULL, 0x18D2D110DCC9BCA1ULL } }, /* one block, finishing at stripe boundary */
|
||||
{ 512, PRIME64, { 0x3CE457DE14C27708ULL, 0x925D06B8EC5B8040ULL } },
|
||||
{ 2048, 0, { 0xDD59E2C3A5F038E0ULL, 0xF736557FD47073A5ULL } }, /* 2 blocks, finishing at block boundary */
|
||||
{ 2048, PRIME32, { 0x230D43F30206260BULL, 0x7FB03F7E7186C3EAULL } },
|
||||
{ 2240, 0, { 0x6E73A90539CF2948ULL, 0xCCB134FBFA7CE49DULL } }, /* 3 blocks, finishing at stripe boundary */
|
||||
{ 2240, PRIME32, { 0xED385111126FBA6FULL, 0x50A1FE17B338995FULL } },
|
||||
{ 2367, 0, { 0xCB37AEB9E5D361EDULL, 0xE89C0F6FF369B427ULL } }, /* 3 blocks, last stripe is overlapping */
|
||||
{ 2367, PRIME32, { 0x6F5360AE69C2F406ULL, 0xD23AAE4B76C31ECBULL } }
|
||||
};
|
||||
|
||||
/* XXH128, custom secret */
|
||||
static const XSUM_testdata128_t XSUM_XXH128_withSecret_testdata[] = {
|
||||
{ 0, 0, { 0x005923CCEECBE8AEULL, 0x5F70F4EA232F1D38ULL } }, /* empty string */
|
||||
{ 1, 0, { 0x8A52451418B2DA4DULL, 0x3A66AF5A9819198EULL } }, /* 1 - 3 */
|
||||
{ 6, 0, { 0x0B61C8ACA7D4778FULL, 0x376BD91B6432F36DULL } }, /* 4 - 8 */
|
||||
{ 12, 0, { 0xAF82F6EBA263D7D8ULL, 0x90A3C2D839F57D0FULL } } /* 9 - 16 */
|
||||
};
|
||||
|
||||
#define SECRET_SIZE_MAX 9867
|
||||
static const XSUM_testdata_sample_t XSUM_XXH3_generateSecret_testdata[] = {
|
||||
{ 0, 192, { 0xE7, 0x8C, 0x77, 0x77, 0x00 } },
|
||||
{ 1, 240, { 0x2B, 0x3E, 0xDE, 0xC1, 0x00 } },
|
||||
{ XXH3_SECRET_SIZE_MIN - 1, 277, { 0xE8, 0x39, 0x6C, 0xCC, 0x7B } },
|
||||
{ XXH3_SECRET_DEFAULT_SIZE + 500, SECRET_SIZE_MAX, { 0xD6, 0x1C, 0x41, 0x17, 0xB3 } }
|
||||
};
|
||||
|
||||
static void XSUM_checkResult32(XXH32_hash_t r1, XXH32_hash_t r2)
|
||||
{
|
||||
static int nbTests = 1;
|
||||
if (r1!=r2) {
|
||||
XSUM_log("\rError: 32-bit hash test %i: Internal sanity check failed!\n", nbTests);
|
||||
XSUM_log("\rGot 0x%08X, expected 0x%08X.\n", (unsigned)r1, (unsigned)r2);
|
||||
XSUM_log("\rNote: If you modified the hash functions, make sure to either update the values\n"
|
||||
"or temporarily recompile with XSUM_NO_TESTS=1.\n");
|
||||
exit(1);
|
||||
}
|
||||
nbTests++;
|
||||
}
|
||||
|
||||
static void XSUM_checkResult64(XXH64_hash_t r1, XXH64_hash_t r2)
|
||||
{
|
||||
static int nbTests = 1;
|
||||
if (r1!=r2) {
|
||||
XSUM_log("\rError: 64-bit hash test %i: Internal sanity check failed!\n", nbTests);
|
||||
XSUM_log("\rGot 0x%08X%08XULL, expected 0x%08X%08XULL.\n",
|
||||
(unsigned)(r1>>32), (unsigned)r1, (unsigned)(r2>>32), (unsigned)r2);
|
||||
XSUM_log("\rNote: If you modified the hash functions, make sure to either update the values\n"
|
||||
"or temporarily recompile with XSUM_NO_TESTS=1.\n");
|
||||
exit(1);
|
||||
}
|
||||
nbTests++;
|
||||
}
|
||||
|
||||
static void XSUM_checkResult128(XXH128_hash_t r1, XXH128_hash_t r2)
|
||||
{
|
||||
static int nbTests = 1;
|
||||
if ((r1.low64 != r2.low64) || (r1.high64 != r2.high64)) {
|
||||
XSUM_log("\rError: 128-bit hash test %i: Internal sanity check failed.\n", nbTests);
|
||||
XSUM_log("\rGot { 0x%08X%08XULL, 0x%08X%08XULL }, expected { 0x%08X%08XULL, 0x%08X%08XULL } \n",
|
||||
(unsigned)(r1.low64>>32), (unsigned)r1.low64, (unsigned)(r1.high64>>32), (unsigned)r1.high64,
|
||||
(unsigned)(r2.low64>>32), (unsigned)r2.low64, (unsigned)(r2.high64>>32), (unsigned)r2.high64 );
|
||||
XSUM_log("\rNote: If you modified the hash functions, make sure to either update the values\n"
|
||||
"or temporarily recompile with XSUM_NO_TESTS=1.\n");
|
||||
exit(1);
|
||||
}
|
||||
nbTests++;
|
||||
}
|
||||
|
||||
|
||||
static void XSUM_testXXH32(const void* data, const XSUM_testdata32_t* testData)
|
||||
{
|
||||
XXH32_state_t *state = XXH32_createState();
|
||||
size_t pos;
|
||||
|
||||
size_t len = testData->len;
|
||||
XSUM_U32 seed = testData->seed;
|
||||
XSUM_U32 Nresult = testData->Nresult;
|
||||
|
||||
if (len == 0) {
|
||||
data = NULL;
|
||||
} else {
|
||||
assert(data != NULL);
|
||||
}
|
||||
|
||||
assert(state != NULL);
|
||||
|
||||
XSUM_checkResult32(XXH32(data, len, seed), Nresult);
|
||||
|
||||
(void)XXH32_reset(state, seed);
|
||||
(void)XXH32_update(state, data, len);
|
||||
XSUM_checkResult32(XXH32_digest(state), Nresult);
|
||||
|
||||
(void)XXH32_reset(state, seed);
|
||||
for (pos=0; pos<len; pos++)
|
||||
(void)XXH32_update(state, ((const char*)data)+pos, 1);
|
||||
XSUM_checkResult32(XXH32_digest(state), Nresult);
|
||||
XXH32_freeState(state);
|
||||
}
|
||||
|
||||
static void XSUM_testXXH64(const void* data, const XSUM_testdata64_t* testData)
|
||||
{
|
||||
XXH64_state_t *state = XXH64_createState();
|
||||
size_t pos;
|
||||
|
||||
size_t len = (size_t)testData->len;
|
||||
XSUM_U64 seed = testData->seed;
|
||||
XSUM_U64 Nresult = testData->Nresult;
|
||||
|
||||
if (len == 0) {
|
||||
data = NULL;
|
||||
} else {
|
||||
assert(data != NULL);
|
||||
}
|
||||
|
||||
assert(state != NULL);
|
||||
|
||||
XSUM_checkResult64(XXH64(data, len, seed), Nresult);
|
||||
|
||||
(void)XXH64_reset(state, seed);
|
||||
(void)XXH64_update(state, data, len);
|
||||
XSUM_checkResult64(XXH64_digest(state), Nresult);
|
||||
|
||||
(void)XXH64_reset(state, seed);
|
||||
for (pos=0; pos<len; pos++)
|
||||
(void)XXH64_update(state, ((const char*)data)+pos, 1);
|
||||
XSUM_checkResult64(XXH64_digest(state), Nresult);
|
||||
XXH64_freeState(state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to get "random" (but actually 100% reproducible) lengths for
|
||||
* XSUM_XXH3_randomUpdate.
|
||||
*/
|
||||
static XSUM_U32 XSUM_rand(void)
|
||||
{
|
||||
static XSUM_U64 seed = PRIME32;
|
||||
seed *= PRIME64;
|
||||
return (XSUM_U32)(seed >> 40);
|
||||
}
|
||||
|
||||
/*
|
||||
* Technically, XXH3_64bits_update is identical to XXH3_128bits_update as of
|
||||
* v0.8.0, but we treat them as separate.
|
||||
*/
|
||||
typedef XXH_errorcode (*XSUM_XXH3_update_t)(XXH3_state_t* state, const void* input, size_t length);
|
||||
|
||||
/*
|
||||
* Runs the passed XXH3_update variant on random lengths. This is to test the
|
||||
* more complex logic of the update function, catching bugs like this one:
|
||||
* https://github.com/Cyan4973/xxHash/issues/378
|
||||
*/
|
||||
static void XSUM_XXH3_randomUpdate(XXH3_state_t* state, const void* data,
|
||||
size_t len, XSUM_XXH3_update_t update_fn)
|
||||
{
|
||||
size_t p = 0;
|
||||
while (p < len) {
|
||||
size_t const modulo = len > 2 ? len : 2;
|
||||
size_t l = (size_t)(XSUM_rand()) % modulo;
|
||||
if (p + l > len) l = len - p;
|
||||
(void)update_fn(state, (const char*)data+p, l);
|
||||
p += l;
|
||||
}
|
||||
}
|
||||
|
||||
static void XSUM_testXXH3(const void* data, const XSUM_testdata64_t* testData)
|
||||
{
|
||||
size_t len = testData->len;
|
||||
XSUM_U64 seed = testData->seed;
|
||||
XSUM_U64 Nresult = testData->Nresult;
|
||||
if (len == 0) {
|
||||
data = NULL;
|
||||
} else {
|
||||
assert(data != NULL);
|
||||
}
|
||||
{ XSUM_U64 const Dresult = XXH3_64bits_withSeed(data, len, seed);
|
||||
XSUM_checkResult64(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* check that the no-seed variant produces same result as seed==0 */
|
||||
if (seed == 0) {
|
||||
XSUM_U64 const Dresult = XXH3_64bits(data, len);
|
||||
XSUM_checkResult64(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* check that the combination of
|
||||
* XXH3_generateSecret_fromSeed() and XXH3_64bits_withSecretandSeed()
|
||||
* results in exactly the same hash generation as XXH3_64bits_withSeed() */
|
||||
{ char secretBuffer[XXH3_SECRET_DEFAULT_SIZE+1];
|
||||
char* const secret = secretBuffer + 1; /* intentional unalignment */
|
||||
XXH3_generateSecret_fromSeed(secret, seed);
|
||||
{ XSUM_U64 const Dresult = XXH3_64bits_withSecretandSeed(data, len, secret, XXH3_SECRET_DEFAULT_SIZE, seed);
|
||||
XSUM_checkResult64(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* check that XXH3_64bits_withSecretandSeed()
|
||||
* results in exactly the same return value as XXH3_64bits_withSeed()
|
||||
* when len <= XXH3_MIDSIZE_MAX, whatever the content of @secret */
|
||||
memset(secret, 0x99, 9);
|
||||
if (len <= XXH3_MIDSIZE_MAX) {
|
||||
XSUM_U64 const Dresult = XXH3_64bits_withSecretandSeed(data, len, secret, XXH3_SECRET_DEFAULT_SIZE, seed);
|
||||
XSUM_checkResult64(Dresult, Nresult);
|
||||
}
|
||||
}
|
||||
|
||||
/* streaming API test */
|
||||
{ XXH3_state_t* const state = XXH3_createState();
|
||||
assert(state != NULL);
|
||||
/* single ingestion */
|
||||
(void)XXH3_64bits_reset_withSeed(state, seed);
|
||||
(void)XXH3_64bits_update(state, data, len);
|
||||
XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
|
||||
|
||||
/* random ingestion */
|
||||
(void)XXH3_64bits_reset_withSeed(state, seed);
|
||||
XSUM_XXH3_randomUpdate(state, data, len, &XXH3_64bits_update);
|
||||
XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
|
||||
|
||||
/* byte by byte ingestion */
|
||||
{ size_t pos;
|
||||
(void)XXH3_64bits_reset_withSeed(state, seed);
|
||||
for (pos=0; pos<len; pos++)
|
||||
(void)XXH3_64bits_update(state, ((const char*)data)+pos, 1);
|
||||
XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
|
||||
}
|
||||
|
||||
/* check that streaming with a combination of
|
||||
* XXH3_generateSecret_fromSeed() and XXH3_64bits_reset_withSecretandSeed()
|
||||
* results in exactly the same hash generation as XXH3_64bits_reset_withSeed() */
|
||||
{ char secretBuffer[XXH3_SECRET_DEFAULT_SIZE+1];
|
||||
char* const secret = secretBuffer + 1; /* intentional unalignment */
|
||||
XXH3_generateSecret_fromSeed(secret, seed);
|
||||
/* single ingestion */
|
||||
(void)XXH3_64bits_reset_withSecretandSeed(state, secret, XXH3_SECRET_DEFAULT_SIZE, seed);
|
||||
(void)XXH3_64bits_update(state, data, len);
|
||||
XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
|
||||
|
||||
/* check that XXH3_64bits_withSecretandSeed()
|
||||
* results in exactly the same return value as XXH3_64bits_withSeed()
|
||||
* when len <= XXH3_MIDSIZE_MAX, whatever the content of @secret */
|
||||
if (len <= XXH3_MIDSIZE_MAX) {
|
||||
/* single ingestion */
|
||||
memset(secret, 0x99, 9);
|
||||
(void)XXH3_64bits_reset_withSecretandSeed(state, secret, XXH3_SECRET_DEFAULT_SIZE, seed);
|
||||
(void)XXH3_64bits_update(state, data, len);
|
||||
XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
|
||||
}
|
||||
}
|
||||
|
||||
XXH3_freeState(state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void XSUM_testXXH3_withSecret(const void* data, const void* secret,
|
||||
size_t secretSize, const XSUM_testdata64_t* testData)
|
||||
{
|
||||
size_t len = (size_t)testData->len;
|
||||
XSUM_U64 Nresult = testData->Nresult;
|
||||
|
||||
if (len == 0) {
|
||||
data = NULL;
|
||||
} else {
|
||||
assert(data != NULL);
|
||||
}
|
||||
{ XSUM_U64 const Dresult = XXH3_64bits_withSecret(data, len, secret, secretSize);
|
||||
XSUM_checkResult64(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* check that XXH3_64bits_withSecretandSeed()
|
||||
* results in exactly the same return value as XXH3_64bits_withSecret() */
|
||||
if (len > XXH3_MIDSIZE_MAX)
|
||||
{ XSUM_U64 const Dresult = XXH3_64bits_withSecretandSeed(data, len, secret, secretSize, 0);
|
||||
XSUM_checkResult64(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* streaming API test */
|
||||
{ XXH3_state_t *state = XXH3_createState();
|
||||
assert(state != NULL);
|
||||
(void)XXH3_64bits_reset_withSecret(state, secret, secretSize);
|
||||
(void)XXH3_64bits_update(state, data, len);
|
||||
XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
|
||||
|
||||
/* random ingestion */
|
||||
(void)XXH3_64bits_reset_withSecret(state, secret, secretSize);
|
||||
XSUM_XXH3_randomUpdate(state, data, len, &XXH3_64bits_update);
|
||||
XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
|
||||
|
||||
/* byte by byte ingestion */
|
||||
{ size_t pos;
|
||||
(void)XXH3_64bits_reset_withSecret(state, secret, secretSize);
|
||||
for (pos=0; pos<len; pos++)
|
||||
(void)XXH3_64bits_update(state, ((const char*)data)+pos, 1);
|
||||
XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
|
||||
}
|
||||
|
||||
/* check that XXH3_64bits_reset_withSecretandSeed()
|
||||
* results in exactly the same return value as XXH3_64bits_reset_withSecret()
|
||||
* when len > XXH3_MIDSIZE_MAX, whatever the value of @seed */
|
||||
if (len > XXH3_MIDSIZE_MAX) {
|
||||
/* single ingestion */
|
||||
(void)XXH3_64bits_reset_withSecretandSeed(state, secret, secretSize, 17);
|
||||
(void)XXH3_64bits_update(state, data, len);
|
||||
XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
|
||||
}
|
||||
|
||||
XXH3_freeState(state);
|
||||
}
|
||||
}
|
||||
|
||||
static void XSUM_testXXH128(const void* data, const XSUM_testdata128_t* testData)
|
||||
{
|
||||
size_t len = (size_t)testData->len;
|
||||
XSUM_U64 seed = testData->seed;
|
||||
XXH128_hash_t const Nresult = testData->Nresult;
|
||||
if (len == 0) {
|
||||
data = NULL;
|
||||
} else {
|
||||
assert(data != NULL);
|
||||
}
|
||||
|
||||
{ XXH128_hash_t const Dresult = XXH3_128bits_withSeed(data, len, seed);
|
||||
XSUM_checkResult128(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* check that XXH128() is identical to XXH3_128bits_withSeed() */
|
||||
{ XXH128_hash_t const Dresult2 = XXH128(data, len, seed);
|
||||
XSUM_checkResult128(Dresult2, Nresult);
|
||||
}
|
||||
|
||||
/* check that the no-seed variant produces same result as seed==0 */
|
||||
if (seed == 0) {
|
||||
XXH128_hash_t const Dresult = XXH3_128bits(data, len);
|
||||
XSUM_checkResult128(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* check that the combination of
|
||||
* XXH3_generateSecret_fromSeed() and XXH3_128bits_withSecretandSeed()
|
||||
* results in exactly the same hash generation as XXH3_64bits_withSeed() */
|
||||
{ char secretBuffer[XXH3_SECRET_DEFAULT_SIZE+1];
|
||||
char* const secret = secretBuffer + 1; /* intentional unalignment */
|
||||
XXH3_generateSecret_fromSeed(secret, seed);
|
||||
{ XXH128_hash_t const Dresult = XXH3_128bits_withSecretandSeed(data, len, secret, XXH3_SECRET_DEFAULT_SIZE, seed);
|
||||
XSUM_checkResult128(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* check that XXH3_128bits_withSecretandSeed()
|
||||
* results in exactly the same return value as XXH3_128bits_withSeed()
|
||||
* if len <= XXH3_MIDSIZE_MAX, whatever the content of @secret */
|
||||
memset(secret, 0x99, 9);
|
||||
if (len <= XXH3_MIDSIZE_MAX) {
|
||||
XXH128_hash_t const Dresult = XXH3_128bits_withSecretandSeed(data, len, secret, XXH3_SECRET_DEFAULT_SIZE, seed);
|
||||
XSUM_checkResult128(Dresult, Nresult);
|
||||
}
|
||||
}
|
||||
|
||||
/* streaming API test */
|
||||
{ XXH3_state_t *state = XXH3_createState();
|
||||
assert(state != NULL);
|
||||
|
||||
/* single ingestion */
|
||||
(void)XXH3_128bits_reset_withSeed(state, seed);
|
||||
(void)XXH3_128bits_update(state, data, len);
|
||||
XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
|
||||
|
||||
/* random ingestion */
|
||||
(void)XXH3_128bits_reset_withSeed(state, seed);
|
||||
XSUM_XXH3_randomUpdate(state, data, len, &XXH3_128bits_update);
|
||||
XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
|
||||
|
||||
/* byte by byte ingestion */
|
||||
{ size_t pos;
|
||||
(void)XXH3_128bits_reset_withSeed(state, seed);
|
||||
for (pos=0; pos<len; pos++)
|
||||
(void)XXH3_128bits_update(state, ((const char*)data)+pos, 1);
|
||||
XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
|
||||
}
|
||||
|
||||
/* check that streaming with a combination of
|
||||
* XXH3_generateSecret_fromSeed() and XXH3_128bits_reset_withSecretandSeed()
|
||||
* results in exactly the same hash generation as XXH3_128bits_reset_withSeed() */
|
||||
{ char secretBuffer[XXH3_SECRET_DEFAULT_SIZE+1];
|
||||
char* const secret = secretBuffer + 1; /* intentional unalignment */
|
||||
XXH3_generateSecret_fromSeed(secret, seed);
|
||||
/* single ingestion */
|
||||
(void)XXH3_128bits_reset_withSecretandSeed(state, secret, XXH3_SECRET_DEFAULT_SIZE, seed);
|
||||
(void)XXH3_128bits_update(state, data, len);
|
||||
XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
|
||||
|
||||
/* check that XXH3_128bits_reset_withSecretandSeed()
|
||||
* results in exactly the same return value as XXH3_128bits_reset_withSeed()
|
||||
* if len <= XXH3_MIDSIZE_MAX, whatever the content of @secret */
|
||||
if (len <= XXH3_MIDSIZE_MAX) {
|
||||
/* single ingestion */
|
||||
memset(secret, 0x99, 9);
|
||||
(void)XXH3_128bits_reset_withSecretandSeed(state, secret, XXH3_SECRET_DEFAULT_SIZE, seed);
|
||||
(void)XXH3_128bits_update(state, data, len);
|
||||
XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
|
||||
}
|
||||
}
|
||||
|
||||
XXH3_freeState(state);
|
||||
}
|
||||
}
|
||||
|
||||
static void XSUM_testXXH128_withSecret(const void* data, const void* secret, size_t secretSize, const XSUM_testdata128_t* testData)
|
||||
{
|
||||
size_t len = testData->len;
|
||||
XXH128_hash_t Nresult = testData->Nresult;
|
||||
if (len == 0) {
|
||||
data = NULL;
|
||||
} else {
|
||||
assert(data != NULL);
|
||||
}
|
||||
{ XXH128_hash_t const Dresult = XXH3_128bits_withSecret(data, len, secret, secretSize);
|
||||
XSUM_checkResult128(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* check that XXH3_128bits_withSecretandSeed()
|
||||
* results in exactly the same return value as XXH3_128bits_withSecret() */
|
||||
if (len > XXH3_MIDSIZE_MAX)
|
||||
{ XXH128_hash_t const Dresult = XXH3_128bits_withSecretandSeed(data, len, secret, secretSize, 0);
|
||||
XSUM_checkResult128(Dresult, Nresult);
|
||||
}
|
||||
|
||||
/* streaming API test */
|
||||
{ XXH3_state_t* const state = XXH3_createState();
|
||||
assert(state != NULL);
|
||||
(void)XXH3_128bits_reset_withSecret(state, secret, secretSize);
|
||||
(void)XXH3_128bits_update(state, data, len);
|
||||
XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
|
||||
|
||||
/* random ingestion */
|
||||
(void)XXH3_128bits_reset_withSecret(state, secret, secretSize);
|
||||
XSUM_XXH3_randomUpdate(state, data, len, &XXH3_128bits_update);
|
||||
XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
|
||||
|
||||
/* byte by byte ingestion */
|
||||
{ size_t pos;
|
||||
(void)XXH3_128bits_reset_withSecret(state, secret, secretSize);
|
||||
for (pos=0; pos<len; pos++)
|
||||
(void)XXH3_128bits_update(state, ((const char*)data)+pos, 1);
|
||||
XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
|
||||
}
|
||||
|
||||
/* check that XXH3_128bits_reset_withSecretandSeed()
|
||||
* results in exactly the same return value as XXH3_128bits_reset_withSecret() */
|
||||
if (len > XXH3_MIDSIZE_MAX) {
|
||||
/* single ingestion */
|
||||
(void)XXH3_128bits_reset_withSecretandSeed(state, secret, secretSize, 0);
|
||||
(void)XXH3_128bits_update(state, data, len);
|
||||
XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
|
||||
}
|
||||
|
||||
XXH3_freeState(state);
|
||||
}
|
||||
}
|
||||
|
||||
static void XSUM_testSecretGenerator(const void* customSeed, const XSUM_testdata_sample_t* testData)
|
||||
{
|
||||
static int nbTests = 1;
|
||||
const int sampleIndex[SECRET_SAMPLE_NBBYTES] = { 0, 62, 131, 191, 241 }; /* position of sampled bytes */
|
||||
XSUM_U8 secretBuffer[SECRET_SIZE_MAX] = {0};
|
||||
XSUM_U8 samples[SECRET_SAMPLE_NBBYTES];
|
||||
int i;
|
||||
|
||||
assert(testData->secretLen <= SECRET_SIZE_MAX);
|
||||
XXH3_generateSecret(secretBuffer, testData->secretLen, customSeed, testData->seedLen);
|
||||
for (i=0; i<SECRET_SAMPLE_NBBYTES; i++) {
|
||||
samples[i] = secretBuffer[sampleIndex[i]];
|
||||
}
|
||||
if (memcmp(samples, testData->byte, sizeof(testData->byte))) {
|
||||
XSUM_log("\rError: Secret generation test %i: Internal sanity check failed. \n", nbTests);
|
||||
XSUM_log("\rGot { 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X }, expected { 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X } \n",
|
||||
samples[0], samples[1], samples[2], samples[3], samples[4],
|
||||
testData->byte[0], testData->byte[1], testData->byte[2], testData->byte[3], testData->byte[4] );
|
||||
exit(1);
|
||||
}
|
||||
nbTests++;
|
||||
}
|
||||
|
||||
/*!
|
||||
* XSUM_sanityCheck():
|
||||
* Runs a sanity check before the benchmark.
|
||||
*
|
||||
* Exits on an incorrect output.
|
||||
*/
|
||||
XSUM_API void XSUM_sanityCheck(void)
|
||||
{
|
||||
size_t i;
|
||||
#define SANITY_BUFFER_SIZE 2367
|
||||
XSUM_U8 sanityBuffer[SANITY_BUFFER_SIZE];
|
||||
const void* const secret = sanityBuffer + 7;
|
||||
const size_t secretSize = XXH3_SECRET_SIZE_MIN + 11;
|
||||
assert(sizeof(sanityBuffer) >= 7 + secretSize);
|
||||
|
||||
XSUM_fillTestBuffer(sanityBuffer, sizeof(sanityBuffer));
|
||||
|
||||
/* XXH32 */
|
||||
for (i = 0; i < (sizeof(XSUM_XXH32_testdata)/sizeof(XSUM_XXH32_testdata[0])); i++) {
|
||||
XSUM_testXXH32(sanityBuffer, &XSUM_XXH32_testdata[i]);
|
||||
}
|
||||
/* XXH64 */
|
||||
for (i = 0; i < (sizeof(XSUM_XXH64_testdata)/sizeof(XSUM_XXH64_testdata[0])); i++) {
|
||||
XSUM_testXXH64(sanityBuffer, &XSUM_XXH64_testdata[i]);
|
||||
}
|
||||
/* XXH3_64bits, seeded */
|
||||
for (i = 0; i < (sizeof(XSUM_XXH3_testdata)/sizeof(XSUM_XXH3_testdata[0])); i++) {
|
||||
XSUM_testXXH3(sanityBuffer, &XSUM_XXH3_testdata[i]);
|
||||
}
|
||||
/* XXH3_64bits, custom secret */
|
||||
for (i = 0; i < (sizeof(XSUM_XXH3_withSecret_testdata)/sizeof(XSUM_XXH3_withSecret_testdata[0])); i++) {
|
||||
XSUM_testXXH3_withSecret(sanityBuffer, secret, secretSize, &XSUM_XXH3_withSecret_testdata[i]);
|
||||
}
|
||||
/* XXH128 */
|
||||
for (i = 0; i < (sizeof(XSUM_XXH128_testdata)/sizeof(XSUM_XXH128_testdata[0])); i++) {
|
||||
XSUM_testXXH128(sanityBuffer, &XSUM_XXH128_testdata[i]);
|
||||
}
|
||||
/* XXH128 with custom Secret */
|
||||
for (i = 0; i < (sizeof(XSUM_XXH128_withSecret_testdata)/sizeof(XSUM_XXH128_withSecret_testdata[0])); i++) {
|
||||
XSUM_testXXH128_withSecret(sanityBuffer, secret, secretSize, &XSUM_XXH128_withSecret_testdata[i]);
|
||||
}
|
||||
/* secret generator */
|
||||
for (i = 0; i < (sizeof(XSUM_XXH3_generateSecret_testdata)/sizeof(XSUM_XXH3_generateSecret_testdata[0])); i++) {
|
||||
assert(XSUM_XXH3_generateSecret_testdata[i].seedLen <= SANITY_BUFFER_SIZE);
|
||||
XSUM_testSecretGenerator(sanityBuffer, &XSUM_XXH3_generateSecret_testdata[i]);
|
||||
}
|
||||
|
||||
XSUM_logVerbose(3, "\r%70s\r", ""); /* Clean display line */
|
||||
XSUM_logVerbose(3, "Sanity check -- all tests ok\n");
|
||||
}
|
||||
|
||||
#endif /* !XSUM_NO_TESTS */
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* xxhsum - Command line interface for xxhash algorithms
|
||||
* Copyright (C) 2013-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://www.xxhash.com
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#ifndef XSUM_SANITY_CHECK_H
|
||||
#define XSUM_SANITY_CHECK_H
|
||||
|
||||
#include "xsum_config.h" /* XSUM_API, XSUM_U8 */
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Runs a series of self-tests.
|
||||
*
|
||||
* Exits if any of these tests fail, printing a message to stderr.
|
||||
*
|
||||
* If XSUM_NO_TESTS is defined to non-zero,
|
||||
* this will instead print a warning if this is called (e.g. via xxhsum -b).
|
||||
*/
|
||||
XSUM_API void XSUM_sanityCheck(void);
|
||||
|
||||
/*
|
||||
* Fills a test buffer with pseudorandom data.
|
||||
*
|
||||
* This is used in the sanity check and the benchmarks.
|
||||
* Its values must not be changed.
|
||||
*/
|
||||
XSUM_API void XSUM_fillTestBuffer(XSUM_U8* buffer, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XSUM_SANITY_CHECK_H */
|
||||
@@ -1,35 +1,40 @@
|
||||
.
|
||||
.TH "XXHSUM" "1" "December 2019" "xxhsum 0.7.2" "User Commands"
|
||||
.TH "XXHSUM" "1" "May 2024" "xxhsum 0.8.3" "User Commands"
|
||||
.
|
||||
.SH "NAME"
|
||||
\fBxxhsum\fR \- print or check xxHash non\-cryptographic checksums
|
||||
.
|
||||
.SH "SYNOPSIS"
|
||||
\fBxxhsum [<OPTION>]\.\.\. [<FILE>]\.\.\.\fR
|
||||
.
|
||||
.br
|
||||
\fBxxhsum \-b [<OPTION>]\.\.\.\fR
|
||||
\fBxxhsum\fR [\fIOPTION\fR]\.\.\. [\fIFILE\fR]\.\.\. \fBxxhsum \-b\fR [\fIOPTION\fR]\.\.\.
|
||||
.
|
||||
.P
|
||||
\fBxxh32sum\fR is equivalent to \fBxxhsum \-H0\fR
|
||||
.
|
||||
.br
|
||||
\fBxxh64sum\fR is equivalent to \fBxxhsum \-H1\fR
|
||||
.
|
||||
.br
|
||||
\fBxxh128sum\fR is equivalent to \fBxxhsum \-H2\fR
|
||||
\fBxxh32sum\fR is equivalent to \fBxxhsum \-H0\fR, \fBxxh64sum\fR is equivalent to \fBxxhsum \-H1\fR, \fBxxh128sum\fR is equivalent to \fBxxhsum \-H2\fR, \fBxxh3sum\fR is equivalent to \fBxxhsum \-H3\fR\.
|
||||
.
|
||||
.SH "DESCRIPTION"
|
||||
Print or check xxHash (32, 64 or 128 bits) checksums\. When \fIFILE\fR is \fB\-\fR, read standard input\.
|
||||
Print or check xxHash (32, 64 or 128 bits) checksums\. When no \fIFILE\fR, read standard input, except if it\'s the console\. When \fIFILE\fR is \fB\-\fR, read standard input even if it\'s the console\.
|
||||
.
|
||||
.P
|
||||
\fBxxhsum\fR supports a command line syntax similar but not identical to md5sum(1)\. Differences are: \fBxxhsum\fR doesn\'t have text/binary mode switch (\fB\-b\fR, \fB\-t\fR); \fBxxhsum\fR always treats files as binary files; \fBxxhsum\fR has a hash bit width switch (\fB\-H\fR);
|
||||
\fBxxhsum\fR supports a command line syntax similar but not identical to md5sum(1)\. Differences are:
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fBxxhsum\fR doesn\'t have text mode switch (\fB\-t\fR)
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fBxxhsum\fR doesn\'t have short binary mode switch (\fB\-b\fR)
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fBxxhsum\fR always treats files as binary file
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fBxxhsum\fR has a hash selection switch (\fB\-H\fR)
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
As xxHash is a fast non\-cryptographic checksum algorithm, \fBxxhsum\fR should not be used for security related purposes\.
|
||||
.
|
||||
.P
|
||||
\fBxxhsum \-b\fR invokes benchmark mode\. See \fIOPTIONS\fR and \fIEXAMPLES\fR for details\.
|
||||
\fBxxhsum \-b\fR invokes benchmark mode\. See OPTIONS and EXAMPLES for details\.
|
||||
.
|
||||
.SH "OPTIONS"
|
||||
.
|
||||
@@ -39,11 +44,15 @@ Displays xxhsum version and exits
|
||||
.
|
||||
.TP
|
||||
\fB\-H\fR\fIHASHTYPE\fR
|
||||
Hash selection\. \fIHASHTYPE\fR means \fB0\fR=32bits, \fB1\fR=64bits, \fB2\fR=128bits\. Default value is \fB1\fR (64bits)
|
||||
Hash selection\. \fIHASHTYPE\fR means \fB0\fR=XXH32, \fB1\fR=XXH64, \fB2\fR=XXH128, \fB3\fR=XXH3\. Alternatively, \fIHASHTYPE\fR \fB32\fR=XXH32, \fB64\fR=XXH64, \fB128\fR=XXH128\. Default value is \fB1\fR (XXH64)
|
||||
.
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
Remove status messages like "Loading\.\.\." written to \fBstderr\fR \.
|
||||
\fB\-\-binary\fR
|
||||
Read in binary mode\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-tag\fR
|
||||
Output in the BSD style\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-little\-endian\fR
|
||||
@@ -53,8 +62,7 @@ Set output hexadecimal checksum value as little endian convention\. By default,
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Displays help and exits
|
||||
.
|
||||
.P
|
||||
\fBThe following four options are useful only when verifying checksums (\fB\-c\fR)\fR
|
||||
.SS "The following options are useful only when verifying checksums (\-c):"
|
||||
.
|
||||
.TP
|
||||
\fB\-c\fR, \fB\-\-check\fR \fIFILE\fR
|
||||
@@ -62,7 +70,7 @@ Read xxHash sums from \fIFILE\fR and check them
|
||||
.
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
On top of removing status messages written to \fBstderr\fR, also don\'t print OK for each successfully verified file
|
||||
Don\'t print OK for each successfully verified file
|
||||
.
|
||||
.TP
|
||||
\fB\-\-strict\fR
|
||||
@@ -76,12 +84,15 @@ Don\'t output anything\. Status code shows success\.
|
||||
\fB\-w\fR, \fB\-\-warn\fR
|
||||
Emit a warning message about each improperly formatted checksum line\.
|
||||
.
|
||||
.P
|
||||
\fBThe following options are useful only benchmark purpose\fR
|
||||
.SS "The following options are useful only benchmark purpose:"
|
||||
.
|
||||
.TP
|
||||
\fB\-b\fR
|
||||
Benchmark mode\. See \fIEXAMPLES\fR for details\.
|
||||
Benchmark mode\. See EXAMPLES for details\.
|
||||
.
|
||||
.TP
|
||||
\fB\-b#\fR
|
||||
Specify ID of variant to be tested\. Multiple variants can be selected, separated by a \',\' comma\.
|
||||
.
|
||||
.TP
|
||||
\fB\-B\fR\fIBLOCKSIZE\fR
|
||||
@@ -135,16 +146,26 @@ $ xxhsum \-c xyz\.xxh32 qux\.xxh64
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Benchmark xxHash algorithm for 16384 bytes data in 10 times\. \fBxxhsum\fR benchmarks all xxHash variants and output results to standard output\.
|
||||
.
|
||||
.br
|
||||
The first column is the algorithm, the second column is the source data size in bytes, the third column is the number of hashes generated per second (throughput), and finally, the last column translates speed in megabytes per second\.
|
||||
Benchmark xxHash algorithm\. By default, \fBxxhsum\fR benchmarks xxHash main variants on a synthetic sample of 100 KB, and print results into standard output\. The first column is the algorithm, the second column is the source data size in bytes, the third column is the number of hashes generated per second (throughput), and finally the last column translates speed in megabytes per second\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ xxhsum \-b \-i10 \-B16384
|
||||
$ xxhsum \-b
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
In the following example, the sample to hash is set to 16384 bytes, the variants to be benched are selected by their IDs, and each benchmark test is repeated 10 times, for increased accuracy\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ xxhsum \-b1,2,3 \-i10 \-B16384
|
||||
.
|
||||
.fi
|
||||
.
|
||||
@@ -0,0 +1,177 @@
|
||||
xxhsum(1) -- print or check xxHash non-cryptographic checksums
|
||||
==============================================================
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
|
||||
`xxhsum` [*OPTION*]... [*FILE*]...
|
||||
|
||||
`xxhsum -b` [*OPTION*]...
|
||||
|
||||
`xxh32sum` is equivalent to `xxhsum -H0`,
|
||||
`xxh64sum` is equivalent to `xxhsum -H1`,
|
||||
`xxh128sum` is equivalent to `xxhsum -H2`,
|
||||
`xxh3sum` is equivalent to `xxhsum -H3`.
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Print or check xxHash (32, 64 or 128 bits) checksums.
|
||||
When no *FILE*, read standard input, except if it's the console.
|
||||
When *FILE* is `-`, read standard input even if it's the console.
|
||||
|
||||
`xxhsum` supports a command line syntax similar but not identical to md5sum(1). Differences are:
|
||||
|
||||
* `xxhsum` doesn't have text mode switch (`-t`)
|
||||
* `xxhsum` doesn't have short binary mode switch (`-b`)
|
||||
* `xxhsum` always treats files as binary file
|
||||
* `xxhsum` has a hash selection switch (`-H`)
|
||||
|
||||
As xxHash is a fast non-cryptographic checksum algorithm,
|
||||
`xxhsum` should not be used for security related purposes.
|
||||
|
||||
`xxhsum -b` invokes benchmark mode. See OPTIONS and EXAMPLES for details.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
* `-H`*HASHTYPE*:
|
||||
Hash selection. *HASHTYPE* means `0`=XXH32, `1`=XXH64, `2`=XXH128, `3`=XXH3.
|
||||
Alternatively, *HASHTYPE* `32`=XXH32, `64`=XXH64, `128`=XXH128.
|
||||
Default value is `1` (XXH64)
|
||||
|
||||
* `--binary`:
|
||||
Read in binary mode.
|
||||
|
||||
* `--tag`:
|
||||
Output in the BSD style.
|
||||
|
||||
* `--little-endian`:
|
||||
Set output hexadecimal checksum value as little endian convention.
|
||||
By default, value is displayed as big endian.
|
||||
|
||||
* `-V`, `--version`:
|
||||
Displays xxhsum version and exits
|
||||
|
||||
* `-h`, `--help`:
|
||||
Displays help and exits
|
||||
|
||||
### Advanced file input options
|
||||
|
||||
* `--files-from`, `--filelist` *FILE*:
|
||||
Read filenames from *FILE* and generate hashes for them.
|
||||
`stdin` is also a valid way to provide filenames (when no *FILE* or `-` provided).
|
||||
Valid format is one filename per line, which can include embedded spaces, etc with no need for quotes, escapes, etc.
|
||||
A line commencing with '\\' will enable the convention used in the encoding of filenames against output hashes,
|
||||
whereby subsequent \\\\, \n and \r seqeuences are converted to the single
|
||||
character 0x5C, 0x0A and 0x0D respectively.
|
||||
|
||||
### The following options are useful only for checksum verification:
|
||||
|
||||
* `-c`, `--check` *FILE*:
|
||||
Read xxHash sums from *FILE* and check them
|
||||
|
||||
* `--strict`:
|
||||
Return an error code if any line in *FILE* is invalid,
|
||||
not just if some checksums are wrong.
|
||||
This policy is disabled by default,
|
||||
though UI will prompt an informational message
|
||||
if any line in the file is detected invalid.
|
||||
|
||||
* `-w`, `--warn`:
|
||||
Emit a warning message about each improperly formatted line in *FILE*.
|
||||
|
||||
* `-q`, `--quiet`:
|
||||
Don't print OK for each successfully verified hash
|
||||
|
||||
* `--status`:
|
||||
Don't output anything. Only generate a Status code to show success.
|
||||
|
||||
### The following options are useful only benchmark purpose:
|
||||
|
||||
* `-b`:
|
||||
Benchmark mode. See EXAMPLES for details.
|
||||
|
||||
* `-b#`:
|
||||
Specify ID of variant to be tested.
|
||||
Multiple variants can be selected, separated by a ',' comma.
|
||||
|
||||
* `-B`*BLOCKSIZE*:
|
||||
Only useful for benchmark mode (`-b`). See *EXAMPLES* for details.
|
||||
<BLOCKSIZE> specifies benchmark mode's test data block size in bytes.
|
||||
Default value is 102400
|
||||
|
||||
* `-i`*ITERATIONS*:
|
||||
Only useful for benchmark mode (`-b`). See *EXAMPLES* for details.
|
||||
<ITERATIONS> specifies number of iterations in benchmark. Single iteration
|
||||
lasts approximately 1000 milliseconds. Default value is 3
|
||||
|
||||
EXIT STATUS
|
||||
-----------
|
||||
|
||||
`xxhsum` exit `0` on success, `1` if at least one file couldn't be read or
|
||||
doesn't have the same checksum as the `-c` option.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
Output xxHash (64bit) checksum values of specific files to standard output
|
||||
|
||||
$ xxhsum -H1 foo bar baz
|
||||
|
||||
Output xxHash (32bit and 64bit) checksum values of specific files to standard
|
||||
output, and redirect it to `xyz.xxh32` and `qux.xxh64`
|
||||
|
||||
$ xxhsum -H0 foo bar baz > xyz.xxh32
|
||||
$ xxhsum -H1 foo bar baz > qux.xxh64
|
||||
|
||||
Read xxHash sums from specific files and check them
|
||||
|
||||
$ xxhsum -c xyz.xxh32 qux.xxh64
|
||||
|
||||
Produce a list of files, then generate hashes for that list
|
||||
|
||||
$ find . -type f -name '*.[ch]' > c-files.txt
|
||||
$ xxhsum --files-from c-files.txt
|
||||
|
||||
Read the list of files from standard input to avoid the need for an intermediate file
|
||||
|
||||
$ find . -type f -name '*.[ch]' | xxhsum --files-from -
|
||||
|
||||
Note that if shell expansion, length of argument list, clarity of use of spaces in filenames, etc allow it then the same output as the previous example can be generated like this
|
||||
|
||||
$ xxhsum `find . -name '*.[ch]'`
|
||||
|
||||
Benchmark xxHash algorithm.
|
||||
By default, `xxhsum` benchmarks xxHash main variants
|
||||
on a synthetic sample of 100 KB,
|
||||
and print results into standard output.
|
||||
The first column is the algorithm,
|
||||
the second column is the source data size in bytes,
|
||||
the third column is the number of hashes generated per second (throughput),
|
||||
and finally the last column translates speed in megabytes per second.
|
||||
|
||||
$ xxhsum -b
|
||||
|
||||
In the following example,
|
||||
the sample to hash is set to 16384 bytes,
|
||||
the variants to be benched are selected by their IDs,
|
||||
and each benchmark test is repeated 10 times, for increased accuracy.
|
||||
|
||||
$ xxhsum -b1,2,3 -i10 -B16384
|
||||
|
||||
BUGS
|
||||
----
|
||||
|
||||
Report bugs at: https://github.com/Cyan4973/xxHash/issues/
|
||||
|
||||
AUTHOR
|
||||
------
|
||||
|
||||
Yann Collet
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
md5sum(1)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "xxhash",
|
||||
"version": "0.8.2",
|
||||
"repo": "Cyan4973/xxhash",
|
||||
"description": "Extremely fast non-cryptographic hash algorithm",
|
||||
"keywords": ["xxhash", "hashing"],
|
||||
"license": "BSD-2-Clause",
|
||||
"src": [
|
||||
"xxhash.c",
|
||||
"xxhash.h"
|
||||
]
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
#
|
||||
# For details, see <https://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR)
|
||||
cmake_minimum_required (VERSION 3.10 FATAL_ERROR)
|
||||
|
||||
set(XXHASH_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||
|
||||
@@ -25,14 +25,10 @@ if("${CMAKE_VERSION}" VERSION_LESS "3.13")
|
||||
else()
|
||||
cmake_policy (SET CMP0077 NEW)
|
||||
endif()
|
||||
if("${CMAKE_VERSION}" VERSION_LESS "3.0")
|
||||
project(xxHash C)
|
||||
else()
|
||||
cmake_policy (SET CMP0048 NEW)
|
||||
project(xxHash
|
||||
VERSION ${XXHASH_VERSION_STRING}
|
||||
LANGUAGES C)
|
||||
endif()
|
||||
cmake_policy (SET CMP0048 NEW)
|
||||
project(xxHash
|
||||
VERSION ${XXHASH_VERSION_STRING}
|
||||
LANGUAGES C)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Project build type" FORCE)
|
||||
@@ -43,8 +39,17 @@ if(NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "xxHash build type: ${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
|
||||
# Enable assert() statements in debug builds
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
if("${CMAKE_VERSION}" VERSION_LESS "3.12")
|
||||
# add_compile_definitions is not available for older cmake => do nothing
|
||||
else()
|
||||
add_compile_definitions(XXH_DEBUGLEVEL=1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared library" ON)
|
||||
set(XXHASH_BUILD_XXHSUM ON CACHE BOOL "Build the xxhsum binary")
|
||||
option(XXHASH_BUILD_XXHSUM "Build the xxhsum binary" ON)
|
||||
|
||||
# If XXHASH is being bundled in another project, we don't want to
|
||||
# install anything. However, we want to let people override this, so
|
||||
@@ -66,8 +71,26 @@ mark_as_advanced(XXHASH_BUNDLED_MODE)
|
||||
include(CMakeDependentOption)
|
||||
CMAKE_DEPENDENT_OPTION(BUILD_SHARED_LIBS "Build shared libraries" ON "NOT XXHASH_BUNDLED_MODE" OFF)
|
||||
|
||||
# detect architecture for DISPATCH mode
|
||||
CMAKE_HOST_SYSTEM_INFORMATION(RESULT PLATFORM QUERY OS_PLATFORM)
|
||||
message(STATUS "Architecture: ${PLATFORM}")
|
||||
|
||||
# libxxhash
|
||||
add_library(xxhash "${XXHASH_DIR}/xxhash.c")
|
||||
if((DEFINED DISPATCH) AND (DEFINED PLATFORM))
|
||||
# Only support DISPATCH option on x86_64.
|
||||
if(("${PLATFORM}" STREQUAL "x86_64") OR ("${PLATFORM}" STREQUAL "AMD64"))
|
||||
set(XXHSUM_DISPATCH ON)
|
||||
message(STATUS "Enable xxHash dispatch mode")
|
||||
add_library(xxhash "${XXHASH_DIR}/xxh_x86dispatch.c"
|
||||
"${XXHASH_DIR}/xxhash.c"
|
||||
)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXXHSUM_DISPATCH=1")
|
||||
else()
|
||||
add_library(xxhash "${XXHASH_DIR}/xxhash.c")
|
||||
endif()
|
||||
else()
|
||||
add_library(xxhash "${XXHASH_DIR}/xxhash.c")
|
||||
endif()
|
||||
add_library(${PROJECT_NAME}::xxhash ALIAS xxhash)
|
||||
|
||||
target_include_directories(xxhash
|
||||
@@ -78,12 +101,24 @@ if (BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(xxhash PUBLIC XXH_EXPORT)
|
||||
endif ()
|
||||
set_target_properties(xxhash PROPERTIES
|
||||
SOVERSION "${XXHASH_VERSION_STRING}"
|
||||
SOVERSION "${XXHASH_LIB_SOVERSION}"
|
||||
VERSION "${XXHASH_VERSION_STRING}")
|
||||
|
||||
if(XXHASH_BUILD_XXHSUM)
|
||||
set(XXHSUM_DIR "${XXHASH_DIR}/cli")
|
||||
# xxhsum
|
||||
add_executable(xxhsum "${XXHASH_DIR}/xxhsum.c")
|
||||
set(XXHSUM_SOURCES)
|
||||
if (XXHSUM_DISPATCH)
|
||||
list(APPEND XXHSUM_SOURCES "${XXHASH_DIR}/xxh_x86dispatch.c")
|
||||
endif()
|
||||
list(APPEND XXHSUM_SOURCES "${XXHSUM_DIR}/xxhsum.c"
|
||||
"${XXHSUM_DIR}/xsum_arch.c"
|
||||
"${XXHSUM_DIR}/xsum_os_specific.c"
|
||||
"${XXHSUM_DIR}/xsum_output.c"
|
||||
"${XXHSUM_DIR}/xsum_sanity_check.c"
|
||||
"${XXHSUM_DIR}/xsum_bench.c"
|
||||
)
|
||||
add_executable(xxhsum ${XXHSUM_SOURCES})
|
||||
add_executable(${PROJECT_NAME}::xxhsum ALIAS xxhsum)
|
||||
|
||||
target_link_libraries(xxhsum PRIVATE xxhash)
|
||||
@@ -95,40 +130,28 @@ include (CheckCCompilerFlag)
|
||||
if (XXHASH_C_FLAGS)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${XXHASH_C_FLAGS}")
|
||||
endif()
|
||||
foreach (flag
|
||||
-Wall -Wextra -Wcast-qual -Wcast-align -Wshadow
|
||||
-Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement
|
||||
-Wstrict-prototypes -Wundef)
|
||||
# Because https://gcc.gnu.org/wiki/FAQ#wnowarning
|
||||
string(REGEX REPLACE "\\-Wno\\-(.+)" "-W\\1" flag_to_test "${flag}")
|
||||
string(REGEX REPLACE "[^a-zA-Z0-9]+" "_" test_name "CFLAG_${flag_to_test}")
|
||||
|
||||
check_c_compiler_flag("${ADD_COMPILER_FLAGS_PREPEND} ${flag_to_test}" ${test_name})
|
||||
|
||||
if(${test_name})
|
||||
set(CMAKE_C_FLAGS "${flag} ${CMAKE_C_FLAGS}")
|
||||
endif()
|
||||
|
||||
unset(test_name)
|
||||
unset(flag_to_test)
|
||||
endforeach (flag)
|
||||
|
||||
if(NOT XXHASH_BUNDLED_MODE)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(TARGETS xxhash
|
||||
EXPORT xxHashTargets
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
install(FILES "${XXHASH_DIR}/xxhash.h"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
install(FILES "${XXHASH_DIR}/xxh3.h"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
if(DISPATCH)
|
||||
install(FILES "${XXHASH_DIR}/xxh_x86dispatch.h"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
endif()
|
||||
if(XXHASH_BUILD_XXHSUM)
|
||||
install(TARGETS xxhsum
|
||||
EXPORT xxHashTargets
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
install(FILES "${XXHASH_DIR}/xxhsum.1"
|
||||
install(FILES "${XXHSUM_DIR}/xxhsum.1"
|
||||
DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
|
||||
endif(XXHASH_BUILD_XXHSUM)
|
||||
|
||||
@@ -145,23 +168,28 @@ if(NOT XXHASH_BUNDLED_MODE)
|
||||
${PROJECT_SOURCE_DIR}/xxHashConfig.cmake.in
|
||||
${xxHash_PROJECT_CONFIG}
|
||||
INSTALL_DESTINATION ${xxHash_CONFIG_INSTALL_DIR})
|
||||
if("${CMAKE_VERSION}" VERSION_LESS "3.0")
|
||||
set(XXHASH_EXPORT_SET xxhash)
|
||||
if(XXHASH_BUILD_XXHSUM)
|
||||
set(XXHASH_EXPORT_SET ${XXHASH_EXPORT_SET} xxhsum)
|
||||
endif()
|
||||
export(TARGETS ${XXHASH_EXPORT_SET}
|
||||
FILE ${xxHash_TARGETS_CONFIG}
|
||||
NAMESPACE ${PROJECT_NAME}::)
|
||||
else()
|
||||
export(EXPORT xxHashTargets
|
||||
FILE ${xxHash_TARGETS_CONFIG}
|
||||
NAMESPACE ${PROJECT_NAME}::)
|
||||
endif()
|
||||
|
||||
install(FILES ${xxHash_PROJECT_CONFIG} ${xxHash_VERSION_CONFIG}
|
||||
DESTINATION ${xxHash_CONFIG_INSTALL_DIR})
|
||||
install(EXPORT xxHashTargets
|
||||
DESTINATION ${xxHash_CONFIG_INSTALL_DIR}
|
||||
NAMESPACE ${PROJECT_NAME}::)
|
||||
|
||||
# configure and install pkg-config
|
||||
include(JoinPaths.cmake)
|
||||
set(PREFIX ${CMAKE_INSTALL_PREFIX})
|
||||
set(EXECPREFIX "\${prefix}")
|
||||
join_paths(INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
join_paths(LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
|
||||
set(VERSION "${XXHASH_VERSION_STRING}")
|
||||
configure_file(${XXHASH_DIR}/libxxhash.pc.in ${CMAKE_BINARY_DIR}/libxxhash.pc @ONLY)
|
||||
|
||||
install(FILES ${CMAKE_BINARY_DIR}/libxxhash.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
endif(NOT XXHASH_BUNDLED_MODE)
|
||||
|
||||
include(CPack)
|
||||
@@ -0,0 +1,23 @@
|
||||
# This module provides function for joining paths
|
||||
# known from most languages
|
||||
#
|
||||
# SPDX-License-Identifier: (MIT OR CC0-1.0)
|
||||
# Copyright 2020 Jan Tojnar
|
||||
# https://github.com/jtojnar/cmake-snips
|
||||
#
|
||||
# Modelled after Python’s os.path.join
|
||||
# https://docs.python.org/3.7/library/os.path.html#os.path.join
|
||||
# Windows not supported
|
||||
function(join_paths joined_path first_path_segment)
|
||||
set(temp_path "${first_path_segment}")
|
||||
foreach(current_segment IN LISTS ARGN)
|
||||
if(NOT ("${current_segment}" STREQUAL ""))
|
||||
if(IS_ABSOLUTE "${current_segment}")
|
||||
set(temp_path "${current_segment}")
|
||||
else()
|
||||
set(temp_path "${temp_path}/${current_segment}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
set(${joined_path} "${temp_path}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -16,6 +16,7 @@ Where possible options are:
|
||||
- `-DXXHASH_BUILD_XXHSUM=<ON|OFF>`: build the command line binary. ON by default
|
||||
- `-DBUILD_SHARED_LIBS=<ON|OFF>`: build dynamic library. ON by default.
|
||||
- `-DCMAKE_INSTALL_PREFIX=<path>`: use custom install prefix path.
|
||||
- `-DDISPATCH=<ON|OFF>`: enable dispatch mode. OFF by default.
|
||||
|
||||
Add lines into downstream CMakeLists.txt:
|
||||
|
||||
@@ -26,7 +27,7 @@ Add lines into downstream CMakeLists.txt:
|
||||
### Way 2: Add subdirectory
|
||||
Add lines into downstream CMakeLists.txt:
|
||||
|
||||
option(BUILD_SHARE_LIBS "Build shared libs" OFF) #optional
|
||||
option(BUILD_SHARED_LIBS "Build shared libs" OFF) #optional
|
||||
...
|
||||
set(XXHASH_BUILD_ENABLE_INLINE_API OFF) #optional
|
||||
set(XXHASH_BUILD_XXHSUM OFF) #optional
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
module xxhash where
|
||||
|
||||
/**
|
||||
* The 32-bit variant of xxHash. The first argument is the sequence
|
||||
* of L bytes to hash. The second argument is a seed value.
|
||||
*/
|
||||
XXH32 : {L} (fin L) => [L][8] -> [32] -> [32]
|
||||
XXH32 input seed = XXH32_avalanche acc1
|
||||
where (stripes16 # stripes4 # stripes1) = input
|
||||
accR = foldl XXH32_rounds (XXH32_init seed) (split stripes16 : [L/16][16][8])
|
||||
accL = `(L % 2^^32) + if (`L:Integer) < 16
|
||||
then seed + PRIME32_5
|
||||
else XXH32_converge accR
|
||||
acc4 = foldl XXH32_digest4 accL (split stripes4 : [(L%16)/4][4][8])
|
||||
acc1 = foldl XXH32_digest1 acc4 (stripes1 : [L%4][8])
|
||||
|
||||
/**
|
||||
* The 64-bit variant of xxHash. The first argument is the sequence
|
||||
* of L bytes to hash. The second argument is a seed value.
|
||||
*/
|
||||
XXH64 : {L} (fin L) => [L][8] -> [64] -> [64]
|
||||
XXH64 input seed = XXH64_avalanche acc1
|
||||
where (stripes32 # stripes8 # stripes4 # stripes1) = input
|
||||
accR = foldl XXH64_rounds (XXH64_init seed) (split stripes32 : [L/32][32][8])
|
||||
accL = `(L % 2^^64) + if (`L:Integer) < 32
|
||||
then seed + PRIME64_5
|
||||
else XXH64_converge accR
|
||||
acc8 = foldl XXH64_digest8 accL (split stripes8 : [(L%32)/8][8][8])
|
||||
acc4 = foldl XXH64_digest4 acc8 (split stripes4 : [(L%8)/4][4][8])
|
||||
acc1 = foldl XXH64_digest1 acc4 (stripes1 : [L%4][8])
|
||||
|
||||
private
|
||||
|
||||
//Utility functions
|
||||
|
||||
/**
|
||||
* Combines a sequence of bytes into a word using the little-endian
|
||||
* convention.
|
||||
*/
|
||||
toLE bytes = join (reverse bytes)
|
||||
|
||||
//32-bit xxHash helper functions
|
||||
|
||||
//32-bit prime number constants
|
||||
PRIME32_1 = 0x9E3779B1 : [32]
|
||||
PRIME32_2 = 0x85EBCA77 : [32]
|
||||
PRIME32_3 = 0xC2B2AE3D : [32]
|
||||
PRIME32_4 = 0x27D4EB2F : [32]
|
||||
PRIME32_5 = 0x165667B1 : [32]
|
||||
|
||||
/**
|
||||
* The property shows that the hexadecimal representation of the
|
||||
* PRIME32 constants is the same as the binary representation.
|
||||
*/
|
||||
property PRIME32s_as_bits_correct =
|
||||
(PRIME32_1 == 0b10011110001101110111100110110001) /\
|
||||
(PRIME32_2 == 0b10000101111010111100101001110111) /\
|
||||
(PRIME32_3 == 0b11000010101100101010111000111101) /\
|
||||
(PRIME32_4 == 0b00100111110101001110101100101111) /\
|
||||
(PRIME32_5 == 0b00010110010101100110011110110001)
|
||||
|
||||
/**
|
||||
* This function initializes the four internal accumulators of XXH32.
|
||||
*/
|
||||
XXH32_init : [32] -> [4][32]
|
||||
XXH32_init seed = [acc1, acc2, acc3, acc4]
|
||||
where acc1 = seed + PRIME32_1 + PRIME32_2
|
||||
acc2 = seed + PRIME32_2
|
||||
acc3 = seed + 0
|
||||
acc4 = seed - PRIME32_1
|
||||
|
||||
/**
|
||||
* This processes a single lane of the main round function of XXH32.
|
||||
*/
|
||||
XXH32_round : [32] -> [32] -> [32]
|
||||
XXH32_round accN laneN = ((accN + laneN * PRIME32_2) <<< 13) * PRIME32_1
|
||||
|
||||
/**
|
||||
* This is the main round function of XXH32 and processes a stripe,
|
||||
* i.e. 4 lanes with 4 bytes each.
|
||||
*/
|
||||
XXH32_rounds : [4][32] -> [16][8] -> [4][32]
|
||||
XXH32_rounds accs stripe =
|
||||
[ XXH32_round accN (toLE laneN) | accN <- accs | laneN <- split stripe ]
|
||||
|
||||
/**
|
||||
* This function combines the four lane accumulators into a single
|
||||
* 32-bit value.
|
||||
*/
|
||||
XXH32_converge : [4][32] -> [32]
|
||||
XXH32_converge [acc1, acc2, acc3, acc4] =
|
||||
(acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18)
|
||||
|
||||
/**
|
||||
* This function digests a four byte lane
|
||||
*/
|
||||
XXH32_digest4 : [32] -> [4][8] -> [32]
|
||||
XXH32_digest4 acc lane = ((acc + toLE lane * PRIME32_3) <<< 17) * PRIME32_4
|
||||
|
||||
/**
|
||||
* This function digests a single byte lane
|
||||
*/
|
||||
XXH32_digest1 : [32] -> [8] -> [32]
|
||||
XXH32_digest1 acc lane = ((acc + (0 # lane) * PRIME32_5) <<< 11) * PRIME32_1
|
||||
|
||||
/**
|
||||
* This function ensures that all input bits have a chance to impact
|
||||
* any bit in the output digest, resulting in an unbiased
|
||||
* distribution.
|
||||
*/
|
||||
XXH32_avalanche : [32] -> [32]
|
||||
XXH32_avalanche acc0 = acc5
|
||||
where acc1 = acc0 ^ (acc0 >> 15)
|
||||
acc2 = acc1 * PRIME32_2
|
||||
acc3 = acc2 ^ (acc2 >> 13)
|
||||
acc4 = acc3 * PRIME32_3
|
||||
acc5 = acc4 ^ (acc4 >> 16)
|
||||
|
||||
//64-bit xxHash helper functions
|
||||
|
||||
//64-bit prime number constants
|
||||
PRIME64_1 = 0x9E3779B185EBCA87 : [64]
|
||||
PRIME64_2 = 0xC2B2AE3D27D4EB4F : [64]
|
||||
PRIME64_3 = 0x165667B19E3779F9 : [64]
|
||||
PRIME64_4 = 0x85EBCA77C2B2AE63 : [64]
|
||||
PRIME64_5 = 0x27D4EB2F165667C5 : [64]
|
||||
|
||||
/**
|
||||
* The property shows that the hexadecimal representation of the
|
||||
* PRIME64 constants is the same as the binary representation.
|
||||
*/
|
||||
property PRIME64s_as_bits_correct =
|
||||
(PRIME64_1 == 0b1001111000110111011110011011000110000101111010111100101010000111) /\
|
||||
(PRIME64_2 == 0b1100001010110010101011100011110100100111110101001110101101001111) /\
|
||||
(PRIME64_3 == 0b0001011001010110011001111011000110011110001101110111100111111001) /\
|
||||
(PRIME64_4 == 0b1000010111101011110010100111011111000010101100101010111001100011) /\
|
||||
(PRIME64_5 == 0b0010011111010100111010110010111100010110010101100110011111000101)
|
||||
|
||||
/**
|
||||
* This function initializes the four internal accumulators of XXH64.
|
||||
*/
|
||||
XXH64_init : [64] -> [4][64]
|
||||
XXH64_init seed = [acc1, acc2, acc3, acc4]
|
||||
where acc1 = seed + PRIME64_1 + PRIME64_2
|
||||
acc2 = seed + PRIME64_2
|
||||
acc3 = seed + 0
|
||||
acc4 = seed - PRIME64_1
|
||||
|
||||
/**
|
||||
* This processes a single lane of the main round function of XXH64.
|
||||
*/
|
||||
XXH64_round : [64] -> [64] -> [64]
|
||||
XXH64_round accN laneN = ((accN + laneN * PRIME64_2) <<< 31) * PRIME64_1
|
||||
|
||||
/**
|
||||
* This is the main round function of XXH64 and processes a stripe,
|
||||
* i.e. 4 lanes with 8 bytes each.
|
||||
*/
|
||||
XXH64_rounds : [4][64] -> [32][8] -> [4][64]
|
||||
XXH64_rounds accs stripe =
|
||||
[ XXH64_round accN (toLE laneN) | accN <- accs | laneN <- split stripe ]
|
||||
|
||||
/**
|
||||
* This is a helper function, used to merge the four lane accumulators.
|
||||
*/
|
||||
mergeAccumulator : [64] -> [64] -> [64]
|
||||
mergeAccumulator acc accN = (acc ^ XXH64_round 0 accN) * PRIME64_1 + PRIME64_4
|
||||
|
||||
/**
|
||||
* This function combines the four lane accumulators into a single
|
||||
* 64-bit value.
|
||||
*/
|
||||
XXH64_converge : [4][64] -> [64]
|
||||
XXH64_converge [acc1, acc2, acc3, acc4] =
|
||||
foldl mergeAccumulator ((acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18)) [acc1, acc2, acc3, acc4]
|
||||
|
||||
/**
|
||||
* This function digests an eight byte lane
|
||||
*/
|
||||
XXH64_digest8 : [64] -> [8][8] -> [64]
|
||||
XXH64_digest8 acc lane = ((acc ^ XXH64_round 0 (toLE lane)) <<< 27) * PRIME64_1 + PRIME64_4
|
||||
|
||||
/**
|
||||
* This function digests a four byte lane
|
||||
*/
|
||||
XXH64_digest4 : [64] -> [4][8] -> [64]
|
||||
XXH64_digest4 acc lane = ((acc ^ (0 # toLE lane) * PRIME64_1) <<< 23) * PRIME64_2 + PRIME64_3
|
||||
|
||||
/**
|
||||
* This function digests a single byte lane
|
||||
*/
|
||||
XXH64_digest1 : [64] -> [8] -> [64]
|
||||
XXH64_digest1 acc lane = ((acc ^ (0 # lane) * PRIME64_5) <<< 11) * PRIME64_1
|
||||
|
||||
/**
|
||||
* This function ensures that all input bits have a chance to impact
|
||||
* any bit in the output digest, resulting in an unbiased
|
||||
* distribution.
|
||||
*/
|
||||
XXH64_avalanche : [64] -> [64]
|
||||
XXH64_avalanche acc0 = acc5
|
||||
where acc1 = acc0 ^ (acc0 >> 33)
|
||||
acc2 = acc1 * PRIME64_2
|
||||
acc3 = acc2 ^ (acc2 >> 29)
|
||||
acc4 = acc3 * PRIME64_3
|
||||
acc5 = acc4 ^ (acc4 >> 32)
|
||||
@@ -16,7 +16,7 @@ Distribution of this document is unlimited.
|
||||
|
||||
### Version
|
||||
|
||||
0.1.1 (10/10/18)
|
||||
0.2.0 (29/06/23)
|
||||
|
||||
|
||||
Table of Contents
|
||||
@@ -24,6 +24,10 @@ Table of Contents
|
||||
- [Introduction](#introduction)
|
||||
- [XXH32 algorithm description](#xxh32-algorithm-description)
|
||||
- [XXH64 algorithm description](#xxh64-algorithm-description)
|
||||
- [XXH3 algorithm description](#xxh3-algorithm-overview)
|
||||
- [Small inputs](#xxh3-algorithm-description-for-small-inputs)
|
||||
- [Medium inputs](#xxh3-algorithm-description-for-medium-inputs)
|
||||
- [Large inputs](#xxh3-algorithm-description-for-large-inputs)
|
||||
- [Performance considerations](#performance-considerations)
|
||||
- [Reference Implementation](#reference-implementation)
|
||||
|
||||
@@ -43,13 +47,20 @@ However, a given variant shall produce exactly the same output, irrespective of
|
||||
### Operation notations
|
||||
|
||||
All operations are performed modulo {32,64} bits. Arithmetic overflows are expected.
|
||||
`XXH32` uses 32-bit modular operations. `XXH64` uses 64-bit modular operations.
|
||||
`XXH32` uses 32-bit modular operations.
|
||||
`XXH64` and `XXH3` use 64-bit modular operations.
|
||||
When an operation ingests input or secret as multi-bytes values, it reads it using little-endian convention.
|
||||
|
||||
- `+`: denotes modular addition
|
||||
- `-`: denotes modular subtraction
|
||||
- `*`: denotes modular multiplication
|
||||
- **Exception:** In `XXH3`, if it is in the form `(u128)x * (u128)y`, it denotes 64-bit by 64-bit normal multiplication into a full 128-bit result.
|
||||
- `X <<< s`: denotes the value obtained by circularly shifting (rotating) `X` left by `s` bit positions.
|
||||
- `X >> s`: denotes the value obtained by shifting `X` right by s bit positions. Upper `s` bits become `0`.
|
||||
- `X << s`: denotes the value obtained by shifting `X` left by s bit positions. Lower `s` bits become `0`.
|
||||
- `X xor Y`: denotes the bit-wise XOR of `X` and `Y` (same width).
|
||||
- `X | Y`: denotes the bit-wise OR of `X` and `Y` (same width).
|
||||
- `~X`: denotes the bit-wise negation of `X`.
|
||||
|
||||
|
||||
XXH32 Algorithm Description
|
||||
@@ -63,11 +74,13 @@ The algorithm collect and transform input in _stripes_ of 16 bytes. The transfor
|
||||
|
||||
The algorithm uses 32-bits addition, multiplication, rotate, shift and xor operations. Many operations require some 32-bits prime number constants, all defined below:
|
||||
|
||||
static const u32 PRIME32_1 = 0x9E3779B1U; // 0b10011110001101110111100110110001
|
||||
static const u32 PRIME32_2 = 0x85EBCA77U; // 0b10000101111010111100101001110111
|
||||
static const u32 PRIME32_3 = 0xC2B2AE3DU; // 0b11000010101100101010111000111101
|
||||
static const u32 PRIME32_4 = 0x27D4EB2FU; // 0b00100111110101001110101100101111
|
||||
static const u32 PRIME32_5 = 0x165667B1U; // 0b00010110010101100110011110110001
|
||||
```c
|
||||
static const u32 PRIME32_1 = 0x9E3779B1U; // 0b10011110001101110111100110110001
|
||||
static const u32 PRIME32_2 = 0x85EBCA77U; // 0b10000101111010111100101001110111
|
||||
static const u32 PRIME32_3 = 0xC2B2AE3DU; // 0b11000010101100101010111000111101
|
||||
static const u32 PRIME32_4 = 0x27D4EB2FU; // 0b00100111110101001110101100101111
|
||||
static const u32 PRIME32_5 = 0x165667B1U; // 0b00010110010101100110011110110001
|
||||
```
|
||||
|
||||
These constants are prime numbers, and feature a good mix of bits 1 and 0, neither too regular, nor too dissymmetric. These properties help dispersion capabilities.
|
||||
|
||||
@@ -75,10 +88,12 @@ These constants are prime numbers, and feature a good mix of bits 1 and 0, neith
|
||||
|
||||
Each accumulator gets an initial value based on optional `seed` input. Since the `seed` is optional, it can be `0`.
|
||||
|
||||
u32 acc1 = seed + PRIME32_1 + PRIME32_2;
|
||||
u32 acc2 = seed + PRIME32_2;
|
||||
u32 acc3 = seed + 0;
|
||||
u32 acc4 = seed - PRIME32_1;
|
||||
```c
|
||||
u32 acc1 = seed + PRIME32_1 + PRIME32_2;
|
||||
u32 acc2 = seed + PRIME32_2;
|
||||
u32 acc3 = seed + 0;
|
||||
u32 acc4 = seed - PRIME32_1;
|
||||
```
|
||||
|
||||
#### Special case: input is less than 16 bytes
|
||||
|
||||
@@ -86,7 +101,9 @@ When the input is too small (< 16 bytes), the algorithm will not process any str
|
||||
|
||||
In this case, a simplified initialization is performed, using a single accumulator:
|
||||
|
||||
u32 acc = seed + PRIME32_5;
|
||||
```c
|
||||
u32 acc = seed + PRIME32_5;
|
||||
```
|
||||
|
||||
The algorithm then proceeds directly to step 4.
|
||||
|
||||
@@ -100,9 +117,11 @@ Each lane read its associated 32-bit value using __little-endian__ convention.
|
||||
|
||||
For each {lane, accumulator}, the update process is called a _round_, and applies the following formula:
|
||||
|
||||
accN = accN + (laneN * PRIME32_2);
|
||||
accN = accN <<< 13;
|
||||
accN = accN * PRIME32_1;
|
||||
```c
|
||||
accN = accN + (laneN * PRIME32_2);
|
||||
accN = accN <<< 13;
|
||||
accN = accN * PRIME32_1;
|
||||
```
|
||||
|
||||
This shuffles the bits so that any bit from input _lane_ impacts several bits in output _accumulator_. All operations are performed modulo 2^32.
|
||||
|
||||
@@ -113,13 +132,17 @@ When that happens, move to step 3.
|
||||
|
||||
All 4 lane accumulators from the previous steps are merged to produce a single remaining accumulator of the same width (32-bit). The associated formula is as follows:
|
||||
|
||||
acc = (acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18);
|
||||
```c
|
||||
acc = (acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18);
|
||||
```
|
||||
|
||||
### Step 4. Add input length
|
||||
|
||||
The input total length is presumed known at this stage. This step is just about adding the length to accumulator, so that it participates to final mixing.
|
||||
|
||||
acc = acc + (u32)inputLength;
|
||||
```c
|
||||
acc = acc + (u32)inputLength;
|
||||
```
|
||||
|
||||
Note that, if input length is so large that it requires more than 32-bits, only the lower 32-bits are added to the accumulator.
|
||||
|
||||
@@ -128,19 +151,21 @@ Note that, if input length is so large that it requires more than 32-bits, only
|
||||
There may be up to 15 bytes remaining to consume from the input.
|
||||
The final stage will digest them according to following pseudo-code:
|
||||
|
||||
while (remainingLength >= 4) {
|
||||
lane = read_32bit_little_endian(input_ptr);
|
||||
acc = acc + lane * PRIME32_3;
|
||||
acc = (acc <<< 17) * PRIME32_4;
|
||||
input_ptr += 4; remainingLength -= 4;
|
||||
}
|
||||
```c
|
||||
while (remainingLength >= 4) {
|
||||
lane = read_32bit_little_endian(input_ptr);
|
||||
acc = acc + lane * PRIME32_3;
|
||||
acc = (acc <<< 17) * PRIME32_4;
|
||||
input_ptr += 4; remainingLength -= 4;
|
||||
}
|
||||
|
||||
while (remainingLength >= 1) {
|
||||
lane = read_byte(input_ptr);
|
||||
acc = acc + lane * PRIME32_5;
|
||||
acc = (acc <<< 11) * PRIME32_1;
|
||||
input_ptr += 1; remainingLength -= 1;
|
||||
}
|
||||
while (remainingLength >= 1) {
|
||||
lane = read_byte(input_ptr);
|
||||
acc = acc + lane * PRIME32_5;
|
||||
acc = (acc <<< 11) * PRIME32_1;
|
||||
input_ptr += 1; remainingLength -= 1;
|
||||
}
|
||||
```
|
||||
|
||||
This process ensures that all input bytes are present in the final mix.
|
||||
|
||||
@@ -148,11 +173,13 @@ This process ensures that all input bytes are present in the final mix.
|
||||
|
||||
The final mix ensures that all input bits have a chance to impact any bit in the output digest, resulting in an unbiased distribution. This is also called avalanche effect.
|
||||
|
||||
acc = acc xor (acc >> 15);
|
||||
acc = acc * PRIME32_2;
|
||||
acc = acc xor (acc >> 13);
|
||||
acc = acc * PRIME32_3;
|
||||
acc = acc xor (acc >> 16);
|
||||
```c
|
||||
acc = acc xor (acc >> 15);
|
||||
acc = acc * PRIME32_2;
|
||||
acc = acc xor (acc >> 13);
|
||||
acc = acc * PRIME32_3;
|
||||
acc = acc xor (acc >> 16);
|
||||
```
|
||||
|
||||
### Step 7. Output
|
||||
|
||||
@@ -172,22 +199,26 @@ The algorithm collects and transforms input in _stripes_ of 32 bytes. The transf
|
||||
|
||||
The algorithm uses 64-bit addition, multiplication, rotate, shift and xor operations. Many operations require some 64-bit prime number constants, all defined below:
|
||||
|
||||
static const u64 PRIME64_1 = 0x9E3779B185EBCA87ULL; // 0b1001111000110111011110011011000110000101111010111100101010000111
|
||||
static const u64 PRIME64_2 = 0xC2B2AE3D27D4EB4FULL; // 0b1100001010110010101011100011110100100111110101001110101101001111
|
||||
static const u64 PRIME64_3 = 0x165667B19E3779F9ULL; // 0b0001011001010110011001111011000110011110001101110111100111111001
|
||||
static const u64 PRIME64_4 = 0x85EBCA77C2B2AE63ULL; // 0b1000010111101011110010100111011111000010101100101010111001100011
|
||||
static const u64 PRIME64_5 = 0x27D4EB2F165667C5ULL; // 0b0010011111010100111010110010111100010110010101100110011111000101
|
||||
```c
|
||||
static const u64 PRIME64_1 = 0x9E3779B185EBCA87ULL; // 0b1001111000110111011110011011000110000101111010111100101010000111
|
||||
static const u64 PRIME64_2 = 0xC2B2AE3D27D4EB4FULL; // 0b1100001010110010101011100011110100100111110101001110101101001111
|
||||
static const u64 PRIME64_3 = 0x165667B19E3779F9ULL; // 0b0001011001010110011001111011000110011110001101110111100111111001
|
||||
static const u64 PRIME64_4 = 0x85EBCA77C2B2AE63ULL; // 0b1000010111101011110010100111011111000010101100101010111001100011
|
||||
static const u64 PRIME64_5 = 0x27D4EB2F165667C5ULL; // 0b0010011111010100111010110010111100010110010101100110011111000101
|
||||
```
|
||||
|
||||
These constants are prime numbers, and feature a good mix of bits 1 and 0, neither too regular, nor too dissymmetric. These properties help dispersion capabilities.
|
||||
|
||||
### Step 1. Initialise internal accumulators
|
||||
### Step 1. Initialize internal accumulators
|
||||
|
||||
Each accumulator gets an initial value based on optional `seed` input. Since the `seed` is optional, it can be `0`.
|
||||
|
||||
u64 acc1 = seed + PRIME64_1 + PRIME64_2;
|
||||
u64 acc2 = seed + PRIME64_2;
|
||||
u64 acc3 = seed + 0;
|
||||
u64 acc4 = seed - PRIME64_1;
|
||||
```c
|
||||
u64 acc1 = seed + PRIME64_1 + PRIME64_2;
|
||||
u64 acc2 = seed + PRIME64_2;
|
||||
u64 acc3 = seed + 0;
|
||||
u64 acc4 = seed - PRIME64_1;
|
||||
```
|
||||
|
||||
#### Special case: input is less than 32 bytes
|
||||
|
||||
@@ -195,7 +226,9 @@ When the input is too small (< 32 bytes), the algorithm will not process any str
|
||||
|
||||
In this case, a simplified initialization is performed, using a single accumulator:
|
||||
|
||||
u64 acc = seed + PRIME64_5;
|
||||
```c
|
||||
u64 acc = seed + PRIME64_5;
|
||||
```
|
||||
|
||||
The algorithm then proceeds directly to step 4.
|
||||
|
||||
@@ -209,10 +242,12 @@ Each lane read its associated 64-bit value using __little-endian__ convention.
|
||||
|
||||
For each {lane, accumulator}, the update process is called a _round_, and applies the following formula:
|
||||
|
||||
round(accN,laneN):
|
||||
accN = accN + (laneN * PRIME64_2);
|
||||
accN = accN <<< 31;
|
||||
return accN * PRIME64_1;
|
||||
```c
|
||||
round(accN,laneN):
|
||||
accN = accN + (laneN * PRIME64_2);
|
||||
accN = accN <<< 31;
|
||||
return accN * PRIME64_1;
|
||||
```
|
||||
|
||||
This shuffles the bits so that any bit from input _lane_ impacts several bits in output _accumulator_. All operations are performed modulo 2^64.
|
||||
|
||||
@@ -225,52 +260,60 @@ All 4 lane accumulators from previous steps are merged to produce a single remai
|
||||
|
||||
Note that accumulator convergence is more complex than 32-bit variant, and requires to define another function called _mergeAccumulator()_:
|
||||
|
||||
mergeAccumulator(acc,accN):
|
||||
acc = acc xor round(0, accN);
|
||||
acc = acc * PRIME64_1
|
||||
return acc + PRIME64_4;
|
||||
```c
|
||||
mergeAccumulator(acc,accN):
|
||||
acc = acc xor round(0, accN);
|
||||
acc = acc * PRIME64_1;
|
||||
return acc + PRIME64_4;
|
||||
```
|
||||
|
||||
which is then used in the convergence formula:
|
||||
|
||||
acc = (acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18);
|
||||
acc = mergeAccumulator(acc, acc1);
|
||||
acc = mergeAccumulator(acc, acc2);
|
||||
acc = mergeAccumulator(acc, acc3);
|
||||
acc = mergeAccumulator(acc, acc4);
|
||||
```c
|
||||
acc = (acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18);
|
||||
acc = mergeAccumulator(acc, acc1);
|
||||
acc = mergeAccumulator(acc, acc2);
|
||||
acc = mergeAccumulator(acc, acc3);
|
||||
acc = mergeAccumulator(acc, acc4);
|
||||
```
|
||||
|
||||
### Step 4. Add input length
|
||||
|
||||
The input total length is presumed known at this stage. This step is just about adding the length to accumulator, so that it participates to final mixing.
|
||||
|
||||
acc = acc + inputLength;
|
||||
```c
|
||||
acc = acc + inputLength;
|
||||
```
|
||||
|
||||
### Step 5. Consume remaining input
|
||||
|
||||
There may be up to 31 bytes remaining to consume from the input.
|
||||
The final stage will digest them according to following pseudo-code:
|
||||
|
||||
while (remainingLength >= 8) {
|
||||
lane = read_64bit_little_endian(input_ptr);
|
||||
acc = acc xor round(0, lane);
|
||||
acc = (acc <<< 27) * PRIME64_1;
|
||||
acc = acc + PRIME64_4;
|
||||
input_ptr += 8; remainingLength -= 8;
|
||||
}
|
||||
```c
|
||||
while (remainingLength >= 8) {
|
||||
lane = read_64bit_little_endian(input_ptr);
|
||||
acc = acc xor round(0, lane);
|
||||
acc = (acc <<< 27) * PRIME64_1;
|
||||
acc = acc + PRIME64_4;
|
||||
input_ptr += 8; remainingLength -= 8;
|
||||
}
|
||||
|
||||
if (remainingLength >= 4) {
|
||||
lane = read_32bit_little_endian(input_ptr);
|
||||
acc = acc xor (lane * PRIME64_1);
|
||||
acc = (acc <<< 23) * PRIME64_2;
|
||||
acc = acc + PRIME64_3;
|
||||
input_ptr += 4; remainingLength -= 4;
|
||||
}
|
||||
if (remainingLength >= 4) {
|
||||
lane = read_32bit_little_endian(input_ptr);
|
||||
acc = acc xor (lane * PRIME64_1);
|
||||
acc = (acc <<< 23) * PRIME64_2;
|
||||
acc = acc + PRIME64_3;
|
||||
input_ptr += 4; remainingLength -= 4;
|
||||
}
|
||||
|
||||
while (remainingLength >= 1) {
|
||||
lane = read_byte(input_ptr);
|
||||
acc = acc xor (lane * PRIME64_5);
|
||||
acc = (acc <<< 11) * PRIME64_1;
|
||||
input_ptr += 1; remainingLength -= 1;
|
||||
}
|
||||
while (remainingLength >= 1) {
|
||||
lane = read_byte(input_ptr);
|
||||
acc = acc xor (lane * PRIME64_5);
|
||||
acc = (acc <<< 11) * PRIME64_1;
|
||||
input_ptr += 1; remainingLength -= 1;
|
||||
}
|
||||
```
|
||||
|
||||
This process ensures that all input bytes are present in the final mix.
|
||||
|
||||
@@ -278,11 +321,13 @@ This process ensures that all input bytes are present in the final mix.
|
||||
|
||||
The final mix ensures that all input bits have a chance to impact any bit in the output digest, resulting in an unbiased distribution. This is also called avalanche effect.
|
||||
|
||||
acc = acc xor (acc >> 33);
|
||||
acc = acc * PRIME64_2;
|
||||
acc = acc xor (acc >> 29);
|
||||
acc = acc * PRIME64_3;
|
||||
acc = acc xor (acc >> 32);
|
||||
```c
|
||||
acc = acc xor (acc >> 33);
|
||||
acc = acc * PRIME64_2;
|
||||
acc = acc xor (acc >> 29);
|
||||
acc = acc * PRIME64_3;
|
||||
acc = acc xor (acc >> 32);
|
||||
```
|
||||
|
||||
### Step 7. Output
|
||||
|
||||
@@ -290,6 +335,462 @@ The `XXH64()` function produces an unsigned 64-bit value as output.
|
||||
|
||||
For systems which require to store and/or display the result in binary or hexadecimal format, the canonical format is defined to reproduce the same value as the natural decimal format, hence follows __big-endian__ convention (most significant byte first).
|
||||
|
||||
XXH3 Algorithm Overview
|
||||
-------------------------------------
|
||||
|
||||
XXH3 comes in two different versions: XXH3-64 and XXH3-128 (or XXH128), producing 64 and 128 bits of output, respectively.
|
||||
|
||||
XXH3 uses different algorithms for small (0-16 bytes), medium (17-240 bytes), and large (241+ bytes) inputs. The algorithms for small and medium inputs are optimized for performance. The three algorithms are described in the following sections.
|
||||
|
||||
Many operations require some 64-bit prime number constants, which are mostly the same constants used in XXH32 and XXH64, all defined below:
|
||||
|
||||
```c
|
||||
static const u64 PRIME32_1 = 0x9E3779B1U; // 0b10011110001101110111100110110001
|
||||
static const u64 PRIME32_2 = 0x85EBCA77U; // 0b10000101111010111100101001110111
|
||||
static const u64 PRIME32_3 = 0xC2B2AE3DU; // 0b11000010101100101010111000111101
|
||||
static const u64 PRIME64_1 = 0x9E3779B185EBCA87ULL; // 0b1001111000110111011110011011000110000101111010111100101010000111
|
||||
static const u64 PRIME64_2 = 0xC2B2AE3D27D4EB4FULL; // 0b1100001010110010101011100011110100100111110101001110101101001111
|
||||
static const u64 PRIME64_3 = 0x165667B19E3779F9ULL; // 0b0001011001010110011001111011000110011110001101110111100111111001
|
||||
static const u64 PRIME64_4 = 0x85EBCA77C2B2AE63ULL; // 0b1000010111101011110010100111011111000010101100101010111001100011
|
||||
static const u64 PRIME64_5 = 0x27D4EB2F165667C5ULL; // 0b0010011111010100111010110010111100010110010101100110011111000101
|
||||
static const u64 PRIME_MX1 = 0x165667919E3779F9ULL; // 0b0001011001010110011001111001000110011110001101110111100111111001
|
||||
static const u64 PRIME_MX2 = 0x9FB21C651E98DF25ULL; // 0b1001111110110010000111000110010100011110100110001101111100100101
|
||||
```
|
||||
|
||||
The `XXH3_64bits()` function produces an unsigned 64-bit value.
|
||||
The `XXH3_128bits()` function produces a `XXH128_hash_t` struct containing `low64` and `high64` - the lower and higher 64-bit half values of the result, respectively.
|
||||
|
||||
For systems requiring storing and/or displaying the result in binary or hexadecimal format, the canonical format is defined to reproduce the same value as the natural decimal format, hence following **big-endian** convention (most significant byte first).
|
||||
|
||||
### Seed and Secret
|
||||
|
||||
XXH3 provides seeded hashing by introducing two configurable constants used in the hashing process: the seed and the secret. The seed is an unsigned 64-bit value, and the secret is an array of bytes that is at least 136 bytes in size. The default seed is 0, and the default secret is the following 192-byte value:
|
||||
|
||||
```c
|
||||
static const u8 defaultSecret[192] = {
|
||||
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
|
||||
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
|
||||
0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
|
||||
0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
|
||||
0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
|
||||
0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
|
||||
0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
|
||||
0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
|
||||
0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
|
||||
0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
|
||||
0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
|
||||
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
|
||||
};
|
||||
```
|
||||
|
||||
The seed and the secret can be optionally specified using the `*_withSecret` and `*_withSeed` versions of the hash function.
|
||||
|
||||
The seed and the secret cannot be specified simultaneously (`*_withSecretAndSeed` is actually `*_withSeed` for short and medium inputs <= 240 bytes, and `*_withSecret` for large inputs). When one is specified, the other one uses the default value.
|
||||
There is one exception though: when input is large (> 240 bytes) and a seed is given, a secret is derived from the seed value and the default secret using the following procedure:
|
||||
|
||||
```c
|
||||
deriveSecret(u64 seed):
|
||||
u64 derivedSecret[24] = defaultSecret[0:192];
|
||||
for (i = 0; i < 12; i++) {
|
||||
derivedSecret[i*2] += seed;
|
||||
derivedSecret[i*2+1] -= seed;
|
||||
}
|
||||
return derivedSecret; // convert to u8[192] (little-endian)
|
||||
```
|
||||
|
||||
The derivation treats the secrets as 24 64-bit values. In XXH3 algorithms, the secret is always read similarly by treating a contiguous segment of the array as one or more 32-bit or 64-bit values. **The secret values are always read using little-endian convention**.
|
||||
|
||||
### Final Mixing Step (avalanche)
|
||||
|
||||
To make sure that all input bits have a chance to impact any bit in the output digest (avalanche effect), the final step of the XXH3 algorithm is usually one of the two fixed operations that mix the bits in a 64-bit value. These operations are denoted `avalanche()` and `avalanche_XXH64()` in the following XXH3 description.
|
||||
|
||||
```c
|
||||
avalanche(u64 x):
|
||||
x = x xor (x >> 37);
|
||||
x = x * PRIME_MX1;
|
||||
x = x xor (x >> 32);
|
||||
return x;
|
||||
|
||||
avalanche_XXH64(u64 x):
|
||||
x = x xor (x >> 33);
|
||||
x = x * PRIME64_2;
|
||||
x = x xor (x >> 29);
|
||||
x = x * PRIME64_3;
|
||||
x = x xor (x >> 32);
|
||||
return x;
|
||||
```
|
||||
|
||||
XXH3 Algorithm Description (for small inputs)
|
||||
-------------------------------------
|
||||
|
||||
The algorithm for small inputs (0-16 bytes of input) is further divided into 4 cases: empty, 1-3 bytes, 4-8 bytes, and 9-16 bytes of input.
|
||||
|
||||
The algorithm uses byte-swap operations. The byte-swap operation reverses the byte order in a 32-bit or 64-bit value. It is denoted `bswap32` and `bswap64` for its 32-bit and 64-bit versions, respectively.
|
||||
|
||||
### Empty input
|
||||
|
||||
The hash of empty input is calculated from the seed and a segment of the secret:
|
||||
|
||||
```c
|
||||
XXH3_64_empty():
|
||||
u64 secretWords[2] = secret[56:72];
|
||||
return avalanche_XXH64(seed xor secretWords[0] xor secretWords[1]);
|
||||
|
||||
XXH3_128_empty():
|
||||
u64 secretWords[4] = secret[64:96];
|
||||
return {avalanche_XXH64(seed xor secretWords[0] xor secretWords[1]), // lower half
|
||||
avalanche_XXH64(seed xor secretWords[2] xor secretWords[3])}; // higher half
|
||||
```
|
||||
|
||||
### 1-3 bytes of input
|
||||
|
||||
The algorithm starts from a single 32-bit value combining the input bytes and its length:
|
||||
|
||||
```c
|
||||
u32 combined = (u32)input[inputLength-1] | ((u32)inputLength << 8) |
|
||||
((u32)input[0] << 16) | ((u32)input[inputLength>>1] << 24);
|
||||
// LSB 8 16 24 MSB
|
||||
// | last byte | length | first byte | middle-or-last byte |
|
||||
```
|
||||
|
||||
Then the final output is calculated from the value and the first 8 bytes (XXH3-64) or 16 bytes (XXH3-128) of the secret to produce the final result. The secret here is read as 32-bit values instead of the usual 64-bit values.
|
||||
|
||||
```c
|
||||
XXH3_64_1to3():
|
||||
u32 secretWords[2] = secret[0:8];
|
||||
u64 value = ((u64)(secretWords[0] xor secretWords[1]) + seed) xor (u64)combined;
|
||||
return avalanche_XXH64(value);
|
||||
|
||||
XXH3_128_1to3():
|
||||
u32 secretWords[4] = secret[0:16];
|
||||
u64 low = ((u64)(secretWords[0] xor secretWords[1]) + seed) xor (u64)combined;
|
||||
u64 high = ((u64)(secretWords[2] xor secretWords[3]) - seed) xor (u64)(bswap32(combined) <<< 13);
|
||||
// note that the bswap32(combined) <<< 13 above is 32-bit rotate
|
||||
return {avalanche_XXH64(low), // lower half
|
||||
avalanche_XXH64(high)}; // higher half
|
||||
```
|
||||
|
||||
Note that the XXH3-64 result is the lower half of XXH3-128 result.
|
||||
|
||||
### 4-8 bytes of input
|
||||
|
||||
The algorithm starts from reading the first and last 4 bytes of the input as little-endian 32-bit values, and a modified seed:
|
||||
|
||||
```c
|
||||
u32 inputFirst = input[0:4];
|
||||
u32 inputLast = input[inputLength-4:inputLength];
|
||||
u64 modifiedSeed = seed xor ((u64)bswap32((u32)lowerHalf(seed)) << 32);
|
||||
```
|
||||
|
||||
Again, these values are combined with a segment of the secret to produce the final value.
|
||||
|
||||
```c
|
||||
XXH3_64_4to8():
|
||||
u64 secretWords[2] = secret[8:24];
|
||||
u64 combined = (u64)inputLast | ((u64)inputFirst << 32);
|
||||
u64 value = ((secretWords[0] xor secretWords[1]) - modifiedSeed) xor combined;
|
||||
value = value xor (value <<< 49) xor (value <<< 24);
|
||||
value = value * PRIME_MX2;
|
||||
value = value xor ((value >> 35) + inputLength);
|
||||
value = value * PRIME_MX2;
|
||||
value = value xor (value >> 28);
|
||||
return value;
|
||||
|
||||
XXH3_128_4to8():
|
||||
u64 secretWords[2] = secret[16:32];
|
||||
u64 combined = (u64)inputFirst | ((u64)inputLast << 32);
|
||||
u64 value = ((secretWords[0] xor secretWords[1]) + modifiedSeed) xor combined;
|
||||
u128 mulResult = (u128)value * (u128)(PRIME64_1 + (inputLength << 2));
|
||||
u64 high = higherHalf(mulResult); // mulResult >> 64
|
||||
u64 low = lowerHalf(mulResult); // mulResult & 0xFFFFFFFFFFFFFFFF
|
||||
high = high + (low << 1);
|
||||
low = low xor (high >> 3);
|
||||
low = low xor (low >> 35);
|
||||
low = low * PRIME_MX2;
|
||||
low = low xor (low >> 28);
|
||||
high = avalanche(high);
|
||||
return {low, high};
|
||||
```
|
||||
|
||||
### 9-16 bytes of input
|
||||
|
||||
The algorithm starts from reading the first and last 8 bytes of the input as little-endian 64-bit values:
|
||||
|
||||
```c
|
||||
u64 inputFirst = input[0:8];
|
||||
u64 inputLast = input[inputLength-8:inputLength];
|
||||
```
|
||||
|
||||
Once again, these values are combined with a segment of the secret to produce the final value.
|
||||
|
||||
```c
|
||||
XXH3_64_9to16():
|
||||
u64 secretWords[4] = secret[24:56];
|
||||
u64 low = ((secretWords[0] xor secretWords[1]) + seed) xor inputFirst;
|
||||
u64 high = ((secretWords[2] xor secretWords[3]) - seed) xor inputLast;
|
||||
u128 mulResult = (u128)low * (u128)high;
|
||||
u64 value = inputLength + bswap64(low) + high + (u64)(lowerHalf(mulResult) xor higherHalf(mulResult));
|
||||
return avalanche(value);
|
||||
|
||||
XXH3_128_9to16():
|
||||
u64 secretWords[4] = secret[32:64];
|
||||
u64 val1 = ((secretWords[0] xor secretWords[1]) - seed) xor inputFirst xor inputLast;
|
||||
u64 val2 = ((secretWords[2] xor secretWords[3]) + seed) xor inputLast;
|
||||
u128 mulResult = (u128)val1 * (u128)PRIME64_1;
|
||||
u64 low = lowerHalf(mulResult) + ((u64)(inputLength - 1) << 54);
|
||||
u64 high = higherHalf(mulResult) + ((u64)higherHalf(val2) << 32) + (u64)lowerHalf(val2) * PRIME32_2;
|
||||
// the above line can also be simplified to higherHalf(mulResult) + val2 + (u64)lowerHalf(val2) * (PRIME32_2 - 1);
|
||||
low = low xor bswap64(high);
|
||||
// the following three lines are in fact a 128x64 -> 128 multiplication ({low,high} = (u128){low,high} * PRIME64_2)
|
||||
u128 mulResult2 = (u128)low * (u128)PRIME64_2;
|
||||
low = lowerHalf(mulResult2);
|
||||
high = higherHalf(mulResult2) + high * PRIME64_2;
|
||||
return {avalanche(low), // lower half
|
||||
avalanche(high)}; // higher half
|
||||
```
|
||||
|
||||
|
||||
XXH3 Algorithm Description (for medium inputs)
|
||||
-------------------------------------
|
||||
|
||||
This algorithm is used for medium inputs (17-240 bytes of input). Its internal hash state is stored inside 1 (XXH3-64) or 2 (XXH3-128) "accumulators", each storing an unsigned 64-bit value.
|
||||
|
||||
### Step 1. Initialize internal accumulators
|
||||
|
||||
The accumulator(s) are initialized based on the input length.
|
||||
|
||||
```c
|
||||
// For XXH3-64
|
||||
u64 acc = inputLength * PRIME64_1;
|
||||
|
||||
// For XXH3-128
|
||||
u64 acc[2] = {inputLength * PRIME64_1, 0};
|
||||
```
|
||||
|
||||
### Step 2. Process the input
|
||||
|
||||
This step is further divided into two cases: one for 17-128 bytes of input, and one for 129-240 bytes of input.
|
||||
|
||||
#### Mixing operation
|
||||
|
||||
This step uses a mixing operation that mixes a 16-byte segment of data, a 16-byte segment of secret and the seed into a 64-bit value as a building block. This operation treat the segment of data and secret as little-endian 64-bit values.
|
||||
|
||||
```c
|
||||
mixStep(u8 data[16], size secretOffset, u64 seed):
|
||||
u64 dataWords[2] = data[0:16];
|
||||
u64 secretWords[2] = secret[secretOffset:secretOffset+16];
|
||||
u128 mulResult = (u128)(dataWords[0] xor (secretWords[0] + seed)) *
|
||||
(u128)(dataWords[1] xor (secretWords[1] - seed));
|
||||
return lowerHalf(mulResult) xor higherHalf(mulResult);
|
||||
```
|
||||
|
||||
The mixing operation is always invoked in groups of two in XXH3-128, where two 16-byte segments of data are mixed with a 32-byte segment of secret, and the accumulators are updated accordingly.
|
||||
|
||||
```c
|
||||
mixTwoChunks(u8 data1[16], u8 data2[16], size secretOffset, u64 seed):
|
||||
u64 dataWords1[2] = data1[0:16]; // again, little-endian conversion
|
||||
u64 dataWords2[2] = data2[0:16];
|
||||
acc[0] = acc[0] + mixStep(data1, secretOffset, seed);
|
||||
acc[1] = acc[1] + mixStep(data2, secretOffset + 16, seed);
|
||||
acc[0] = acc[0] xor (dataWords2[0] + dataWords2[1]);
|
||||
acc[1] = acc[1] xor (dataWords1[0] + dataWords1[1]);
|
||||
```
|
||||
|
||||
The input is split into several 16-byte chunks and mixed, and the result is added to the accumulator(s).
|
||||
|
||||
#### 17-128 bytes of input
|
||||
|
||||
The input is read as *N* 16-byte chunks starting from the beginning and *N* chunks starting from the end, where *N* is the smallest number that these 2*N* chunks cover the whole input. These chunks are paired up and mixed, and the results are accumulated to the accumulator(s).
|
||||
|
||||
```c
|
||||
// the loop variable `i` should be signed to avoid underflow in implementation
|
||||
processInput_XXH3_64_17to128():
|
||||
u64 numRounds = ((inputLength - 1) >> 5) + 1;
|
||||
for (i = numRounds - 1; i >= 0; i--) {
|
||||
size offsetStart = i*16;
|
||||
size offsetEnd = inputLength - i*16 - 16;
|
||||
acc += mixStep(input[offsetStart:offsetStart+16], i*32, seed);
|
||||
acc += mixStep(input[offsetEnd:offsetEnd+16], i*32+16, seed);
|
||||
}
|
||||
|
||||
processInput_XXH3_128_17to128():
|
||||
u64 numRounds = ((inputLength - 1) >> 5) + 1;
|
||||
for (i = numRounds - 1; i >= 0; i--) {
|
||||
size offsetStart = i*16;
|
||||
size offsetEnd = inputLength - i*16 - 16;
|
||||
mixTwoChunks(input[offsetStart:offsetStart+16], input[offsetEnd:offsetEnd+16], i*32, seed);
|
||||
}
|
||||
```
|
||||
|
||||
#### 129-240 bytes of input
|
||||
|
||||
The input is split into 16-byte (XXH3-64) or 32-byte (XXH3-128) chunks. The first 128 bytes are first mixed chunk by chunk, followed by an intermediate avalanche operation. Then the remaining full chunks are processed, and finally the last 16/32 bytes are treated as a chunk to process.
|
||||
|
||||
```c
|
||||
processInput_XXH3_64_129to240():
|
||||
u64 numChunks = inputLength >> 4;
|
||||
for (i = 0; i < 8; i++) {
|
||||
acc += mixStep(input[i*16:i*16+16], i*16, seed);
|
||||
}
|
||||
acc = avalanche(acc);
|
||||
for (i = 8; i < numChunks; i++) {
|
||||
acc += mixStep(input[i*16:i*16+16], (i-8)*16 + 3, seed);
|
||||
}
|
||||
acc += mixStep(input[inputLength-16:inputLength], 119, seed);
|
||||
|
||||
processInput_XXH3_128_129to240():
|
||||
u64 numChunks = inputLength >> 5;
|
||||
for (i = 0; i < 4; i++) {
|
||||
mixTwoChunks(input[i*32:i*32+16], input[i*32+16:i*32+32], i*32, seed);
|
||||
}
|
||||
acc[0] = avalanche(acc[0]);
|
||||
acc[1] = avalanche(acc[1]);
|
||||
for (i = 4; i < numChunks; i++) {
|
||||
mixTwoChunks(input[i*32:i*32+16], input[i*32+16:i*32+32], (i-4)*32 + 3, seed);
|
||||
}
|
||||
// note that the half-chunk order and the seed is different here
|
||||
mixTwoChunks(input[inputLength-16:inputLength], input[inputLength-32:inputLength-16], 103, (u64)0 - seed);
|
||||
```
|
||||
|
||||
### Step 3. Finalization
|
||||
|
||||
The final result is extracted from the accumulator(s).
|
||||
|
||||
```c
|
||||
XXH3_64_17to240():
|
||||
return avalanche(acc);
|
||||
|
||||
XXH3_128_17to240():
|
||||
u64 low = acc[0] + acc[1];
|
||||
u64 high = (acc[0] * PRIME64_1) + (acc[1] * PRIME64_4) + (((u64)inputLength - seed) * PRIME64_2);
|
||||
return {avalanche(low), // lower half
|
||||
(u64)0 - avalanche(high)}; // higher half
|
||||
```
|
||||
|
||||
XXH3 Algorithm Description (for large inputs)
|
||||
-------------------------------------
|
||||
|
||||
This algorithm is used for inputs larger than 240 bytes. The internal hash state is stored inside 8 "accumulators", each one storing an unsigned 64-bit value.
|
||||
|
||||
### Step 1. Initialize internal accumulators
|
||||
|
||||
The accumulators are initialized to fixed constants:
|
||||
|
||||
```c
|
||||
u64 acc[8] = {
|
||||
PRIME32_3, PRIME64_1, PRIME64_2, PRIME64_3,
|
||||
PRIME64_4, PRIME32_2, PRIME64_5, PRIME32_1};
|
||||
```
|
||||
|
||||
### Step 2. Process blocks
|
||||
|
||||
The input is consumed and processed one full block at a time. The size of the block depends on the length of the secret. Specifically, a block consists of several 64-byte stripes. The number of stripes per block is `floor((secretLength-64)/8)` . For the default 192-byte secret, there are 16 stripes in a block, and thus the block size is 1024 bytes.
|
||||
|
||||
```c
|
||||
secretLength = lengthInBytes(secret); // default 192; at least 136
|
||||
stripesPerBlock = (secretLength-64) / 8; // default 16; at least 9
|
||||
blockSize = 64 * stripesPerBlock; // default 1024; at least 576
|
||||
```
|
||||
|
||||
The process of processing a full block is called a *round*. It consists of the following two sub-steps:
|
||||
|
||||
#### Step 2-1. Process stripes in the block
|
||||
|
||||
A stripe is evenly divided into 8 lanes, of 8 bytes each. In an accumulation step, one stripe and a 64-byte contiguous segment of the secret are used to update the accumulators. Each lane reads its associated 64-bit value using little-endian convention.
|
||||
|
||||
The accumulation step applies the following procedure:
|
||||
|
||||
```c
|
||||
accumulate(u64 stripe[8], size secretOffset):
|
||||
u64 secretWords[8] = secret[secretOffset:secretOffset+64];
|
||||
for (i = 0; i < 8; i++) {
|
||||
u64 value = stripe[i] xor secretWords[i];
|
||||
acc[i xor 1] = acc[i xor 1] + stripe[i];
|
||||
acc[i] = acc[i] + (u64)lowerHalf(value) * (u64)higherHalf(value);
|
||||
// (value and 0xFFFFFFFF) * (value >> 32)
|
||||
}
|
||||
```
|
||||
|
||||
The accumulation step is repeated for all stripes in a block, using different segments of the secret, starting from the first 64 bytes for the first stripe, and offset by 8 bytes for each following round:
|
||||
|
||||
```c
|
||||
round_accumulate(u8 block[blockSize]):
|
||||
for (n = 0; n < stripesPerBlock; n++) {
|
||||
u64 stripe[8] = block[n*64:n*64+64]; // 64 bytes = 8 u64s
|
||||
accumulate(stripe, n*8);
|
||||
}
|
||||
```
|
||||
|
||||
#### Step 2-2. Scramble accumulators
|
||||
|
||||
After the accumulation steps are finished for all stripes in the block, the accumulators are scrambled using the last 64 bytes of the secret.
|
||||
|
||||
```c
|
||||
round_scramble():
|
||||
u64 secretWords[8] = secret[secretLength-64:secretLength];
|
||||
for (i = 0; i < 8; i++) {
|
||||
acc[i] = acc[i] xor (acc[i] >> 47);
|
||||
acc[i] = acc[i] xor secretWords[i];
|
||||
acc[i] = acc[i] * PRIME32_1;
|
||||
}
|
||||
```
|
||||
|
||||
A round is thus a `round_accumulate` followed by a `round_scramble`:
|
||||
|
||||
```c
|
||||
round(u8 block[blockSize]):
|
||||
round_accumulate(block);
|
||||
round_scramble();
|
||||
```
|
||||
|
||||
Step 2 is looped to consume the input until there are less than or equal to `blockSize` bytes of input left. Note that we leave the last block to the next step even if it is a full block.
|
||||
|
||||
### Step 3. Process the last block and the last 64 bytes
|
||||
|
||||
Accumulation steps are run for the stripes in the last block, except for the last stripe (whether it is full or not). After that, run a final accumulation step by treating the last 64 bytes as a stripe. Note that the last 64 bytes might overlap with the second-to-last block.
|
||||
|
||||
```c
|
||||
// len is the size of the last block (1 <= len <= blockSize)
|
||||
lastRound(u8 block[], size len, u64 lastStripe[8]):
|
||||
size nFullStripes = (len-1)/64;
|
||||
for (n = 0; n < nFullStripes; n++) {
|
||||
u64 stripe[8] = block[n*64:n*64+64];
|
||||
accumulate(stripe, n * 8);
|
||||
}
|
||||
accumulate(lastStripe, secretLength - 71);
|
||||
```
|
||||
|
||||
### Step 4. Finalization
|
||||
|
||||
In the finalization step, a merging procedure is used to extract a single 64-bit value from the accumulators, using an initial seed value and a 64-byte segment of the secret.
|
||||
|
||||
```c
|
||||
finalMerge(u64 initValue, size secretOffset):
|
||||
u64 secretWords[8] = secret[secretOffset:secretOffset+64];
|
||||
u64 result = initValue;
|
||||
for (i = 0; i < 4; i++) {
|
||||
// 64-bit by 64-bit multiplication to 128-bit full result
|
||||
u128 mulResult = (u128)(acc[i*2] xor secretWords[i*2]) *
|
||||
(u128)(acc[i*2+1] xor secretWords[i*2+1]);
|
||||
result = result + (lowerHalf(mulResult) xor higherHalf(mulResult));
|
||||
// (mulResult and 0xFFFFFFFFFFFFFFFF) xor (mulResult >> 64)
|
||||
}
|
||||
return avalanche(result);
|
||||
```
|
||||
|
||||
XXH3-128 runs the merging procedure twice for the two halves of the result, using different secret segments and different initial values derived from the total input length.
|
||||
The XXH3-64 result is just the lower half of the XXH3-128 result.
|
||||
|
||||
```c
|
||||
XXH3_64_large():
|
||||
return finalMerge((u64)inputLength * PRIME64_1, 11);
|
||||
|
||||
XXH3_128_large():
|
||||
return {finalMerge((u64)inputLength * PRIME64_1, 11), // lower half
|
||||
finalMerge(~((u64)inputLength * PRIME64_2), secretLength - 75)}; // higher half
|
||||
```
|
||||
|
||||
|
||||
Performance considerations
|
||||
----------------------------------
|
||||
|
||||
@@ -301,6 +802,8 @@ On 64-bit systems, the 64-bit variant `XXH64` is generally faster to compute, so
|
||||
|
||||
On 32-bit systems though, positions are reversed: `XXH64` performance is reduced, due to its usage of 64-bit arithmetic. `XXH32` becomes a faster variant.
|
||||
|
||||
Finally, when vector operations are possible, `XXH3` is likely the faster variant.
|
||||
|
||||
|
||||
Reference Implementation
|
||||
----------------------------------------
|
||||
@@ -312,6 +815,6 @@ It links to the [github project page](https://github.com/Cyan4973/xxHash) where
|
||||
|
||||
Version changes
|
||||
--------------------
|
||||
v0.7.3: Minor fixes
|
||||
v0.2.0: added XXH3 specification, by Adrien Wu
|
||||
v0.1.1: added a note on rationale for selection of constants
|
||||
v0.1.0: initial release
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <stdint.h>
|
||||
#include "xxhash.h"
|
||||
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
volatile XXH64_hash_t hash64 = XXH64(data, size, 0);
|
||||
(void)hash64;
|
||||
volatile XXH32_hash_t hash32 = XXH32(data, size, 0);
|
||||
(void)hash32;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
# xxHash - Extremely fast hash algorithm
|
||||
# Copyright (C) 2012-2021, Yann Collet, Facebook
|
||||
# BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
prefix=@PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
includedir=${prefix}/include
|
||||
libdir=${exec_prefix}/lib
|
||||
exec_prefix=@EXECPREFIX@
|
||||
includedir=@INCLUDEDIR@
|
||||
libdir=@LIBDIR@
|
||||
|
||||
Name: xxhash
|
||||
Description: extremely fast hash algorithm
|
||||
URL: https://www.xxhash.com/
|
||||
URL: http://www.xxhash.com/
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lxxhash
|
||||
Cflags: -I${includedir}
|
||||
@@ -1,7 +1,35 @@
|
||||
CFLAGS += -Wall -Wextra -g
|
||||
# ################################################################
|
||||
# xxHash Makefile
|
||||
# Copyright (C) 2012-2021 Yann Collet
|
||||
#
|
||||
# GPL v2 License
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# You can contact the author at:
|
||||
# - xxHash homepage: https://www.xxhash.com
|
||||
# - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
# ################################################################
|
||||
|
||||
CFLAGS += -Wall -Wextra -Wundef -g
|
||||
|
||||
CP = cp
|
||||
NM = nm
|
||||
GREP = grep
|
||||
XXHSUM_DIR = ..
|
||||
XXHSUM = $(XXHSUM_DIR)/xxhsum
|
||||
|
||||
# Define *.exe as extension for Windows systems
|
||||
ifneq (,$(filter Windows%,$(OS)))
|
||||
@@ -23,7 +51,7 @@ default: all
|
||||
all: test
|
||||
|
||||
.PHONY: test
|
||||
test: test_multiInclude test_unicode
|
||||
test: test_multiInclude test_unicode test_sanity
|
||||
|
||||
.PHONY: test_multiInclude
|
||||
test_multiInclude:
|
||||
@@ -35,20 +63,26 @@ test_multiInclude:
|
||||
# compile with xxhash.o, to detect duplicated symbols
|
||||
$(MAKE) multiInclude_withxxhash
|
||||
@$(MAKE) clean
|
||||
# Note: XXH_INLINE_ALL with XXH_NAMESPACE is currently disabled
|
||||
# compile with XXH_NAMESPACE
|
||||
# CPPFLAGS=-DXXH_NAMESPACE=TESTN_ $(MAKE) multiInclude_withxxhash
|
||||
# compile with XXH_NAMESPACE before XXH_INLINE_ALL
|
||||
CPPFLAGS=-DXXH_NAMESPACE=TESTN_ $(MAKE) multiInclude
|
||||
# no symbol prefixed TESTN_ should exist
|
||||
# ! $(NM) multiInclude_withxxhash | $(GREP) TESTN_
|
||||
#$(MAKE) clean
|
||||
# compile with XXH_NAMESPACE and without xxhash.o
|
||||
# CPPFLAGS=-DXXH_NAMESPACE=TESTN_ $(MAKE) multiInclude
|
||||
# no symbol prefixed TESTN_ should exist
|
||||
# ! $(NM) multiInclude | $(GREP) TESTN_
|
||||
#@$(MAKE) clean
|
||||
! $(NM) multiInclude | $(GREP) TESTN_
|
||||
$(MAKE) clean
|
||||
# compile xxhash.o with XXH_NAMESPACE
|
||||
CPPFLAGS=-DXXH_NAMESPACE=TESTN_ $(MAKE) multiInclude_withxxhash
|
||||
# symbols prefixed TESTN_ should exist in xxhash.o (though not be invoked)
|
||||
$(NM) multiInclude_withxxhash | $(GREP) TESTN_
|
||||
$(MAKE) clean
|
||||
|
||||
xxhsum$(EXT): ../xxhash.c ../xxhash.h ../xxh3.h ../xxhsum.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) ../xxhash.c ../xxhsum.c -o $@
|
||||
.PHONY: test_ppc_redefine
|
||||
test_ppc_redefine: ppc_define.c
|
||||
@$(MAKE) clean
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $^
|
||||
|
||||
.PHONY: $(XXHSUM)
|
||||
$(XXHSUM):
|
||||
$(MAKE) -C $(XXHSUM_DIR) xxhsum
|
||||
$(CP) $(XXHSUM) .
|
||||
|
||||
# Make sure that Unicode filenames work.
|
||||
# https://github.com/Cyan4973/xxHash/issues/293
|
||||
@@ -58,7 +92,7 @@ test_unicode:
|
||||
@echo "Skipping Unicode test, your terminal doesn't appear to support UTF-8."
|
||||
@echo "Try with ENABLE_UNICODE=1"
|
||||
else
|
||||
test_unicode: xxhsum$(EXT) generate_unicode_test.c
|
||||
test_unicode: $(XXHSUM) generate_unicode_test.c
|
||||
# Generate a Unicode filename test dynamically
|
||||
# to keep UTF-8 out of the source tree.
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) generate_unicode_test.c -o generate_unicode_test$(EXT)
|
||||
@@ -66,6 +100,28 @@ test_unicode: xxhsum$(EXT) generate_unicode_test.c
|
||||
$(SHELL) ./unicode_test.sh
|
||||
endif
|
||||
|
||||
.PHONY: test_filename_escape
|
||||
test_filename_escape: $(XXHSUM)
|
||||
./filename-escape.sh
|
||||
|
||||
.PHONY: test_cli_comment_line
|
||||
test_cli_comment_line: $(XXHSUM)
|
||||
$(SHELL) ./cli-comment-line.sh
|
||||
|
||||
.PHONY: test_cli_ignore_missing
|
||||
test_cli_ignore_missing: $(XXHSUM)
|
||||
$(SHELL) ./cli-ignore-missing.sh
|
||||
|
||||
.PHONY: test_sanity
|
||||
test_sanity: sanity_test.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) sanity_test.c -o sanity_test$(EXT)
|
||||
$(RUN_ENV) ./sanity_test$(EXT)
|
||||
|
||||
.PHONY: sanity_test_vectors.h
|
||||
sanity_test_vectors.h: sanity_test_vectors_generator.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) sanity_test_vectors_generator.c -o sanity_test_vectors_generator$(EXT)
|
||||
./sanity_test_vectors_generator$(EXT)
|
||||
|
||||
xxhash.o: ../xxhash.c ../xxhash.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -c -o $@ $<
|
||||
|
||||
@@ -75,4 +131,5 @@ multiInclude_withxxhash: multiInclude.o xxhash.o
|
||||
clean:
|
||||
@$(RM) *.o
|
||||
@$(RM) multiInclude multiInclude_withxxhash
|
||||
@$(RM) *.unicode generate_unicode_test$(EXT) unicode_test.* xxhsum$(EXT)
|
||||
@$(RM) *.unicode generate_unicode_test$(EXT) unicode_test.* xxhsum*
|
||||
@$(RM) sanity_test$(EXT) sanity_test_vectors_generator$(EXT)
|
||||
@@ -4,6 +4,7 @@
|
||||
benchHash
|
||||
benchHash32
|
||||
benchHash_avx2
|
||||
benchHash_avx512
|
||||
benchHash_hw
|
||||
|
||||
# test files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ################################################################
|
||||
# xxHash Makefile
|
||||
# Copyright (C) Yann Collet 2012-present
|
||||
# xxHash benchHash Makefile
|
||||
# Copyright (C) 2019-2021 Yann Collet
|
||||
#
|
||||
# GPL v2 License
|
||||
#
|
||||
@@ -29,7 +29,8 @@
|
||||
|
||||
CPPFLAGS += -I../.. # directory of xxHash source files
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -std=c99 -Wall -Wextra -Wstrict-aliasing=1
|
||||
CFLAGS += -Wall -Wextra -Wstrict-aliasing=1 \
|
||||
-std=c99
|
||||
CFLAGS += $(MOREFLAGS) # custom way to add flags
|
||||
CXXFLAGS ?= -O3
|
||||
LDFLAGS += $(MOREFLAGS)
|
||||
@@ -48,11 +49,14 @@ benchHash32: CXXFLAGS += -m32
|
||||
benchHash_avx2: CFLAGS += -mavx2
|
||||
benchHash_avx2: CXXFLAGS += -mavx2
|
||||
|
||||
benchHash_avx512: CFLAGS += -mavx512f
|
||||
benchHash_avx512: CXXFLAGS += -mavx512f
|
||||
|
||||
benchHash_hw: CPPFLAGS += -DHARDWARE_SUPPORT
|
||||
benchHash_hw: CFLAGS += -mavx2 -maes
|
||||
benchHash_hw: CXXFLAGS += -mavx2 -mpclmul -std=c++14
|
||||
|
||||
benchHash benchHash32 benchHash_avx2 benchHash_nosimd benchHash_hw: $(OBJ_LIST)
|
||||
benchHash benchHash32 benchHash_avx2 benchHash_avx512 benchHash_nosimd benchHash_hw: $(OBJ_LIST)
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
|
||||
@@ -64,4 +68,4 @@ benchHash.o: benchHash.h
|
||||
|
||||
|
||||
clean:
|
||||
$(RM) *.o benchHash benchHash32 benchHash_avx2 benchHash_hw
|
||||
$(RM) *.o benchHash benchHash32 benchHash_avx2 benchHash_avx512 benchHash_hw
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hash benchmark module
|
||||
* Part of the xxHash project
|
||||
* Copyright (C) 2019-present, Yann Collet
|
||||
* Copyright (C) 2019-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <stdlib.h> // malloc
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "benchHash.h"
|
||||
|
||||
@@ -104,6 +105,7 @@ bench_hash_internal(BMK_benchFn_t hashfn, void* payload,
|
||||
};
|
||||
BMK_runOutcome_t result;
|
||||
|
||||
memset(&result, 0, sizeof(result));
|
||||
while (!BMK_isCompleted_TimedFn(txf)) {
|
||||
result = BMK_benchTimedFn(txf, params);
|
||||
assert(BMK_isSuccessful_runOutcome(result));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hash benchmark module
|
||||
* Part of the xxHash project
|
||||
* Copyright (C) 2019-present, Yann Collet
|
||||
* Copyright (C) 2019-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (C) 2016-2021 Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
@@ -90,6 +90,7 @@ static BMK_runOutcome_t BMK_runOutcome_error(size_t errorResult)
|
||||
static BMK_runOutcome_t BMK_setValid_runTime(BMK_runTime_t runTime)
|
||||
{
|
||||
BMK_runOutcome_t outcome;
|
||||
memset(&outcome, 0, sizeof(outcome));
|
||||
outcome.error_tag_never_ever_use_directly = 0;
|
||||
outcome.internal_never_ever_use_directly = runTime;
|
||||
return outcome;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (C) 2016-2021 Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* CSV Display module for the hash benchmark program
|
||||
* Part of the xxHash project
|
||||
* Copyright (C) 2019-present, Yann Collet
|
||||
* Copyright (C) 2019-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
@@ -48,7 +48,7 @@ static void bench_oneHash_largeInput(Bench_Entry hashDesc, int minlog, int maxlo
|
||||
double const nbhps = bench_hash(hashDesc.hash, BMK_throughput,
|
||||
inputSize, BMK_fixedSize,
|
||||
BENCH_LARGE_TOTAL_MS, BENCH_LARGE_ITER_MS);
|
||||
printf(",%9.1f", nbhps * inputSize / MB_UNIT); fflush(NULL);
|
||||
printf(",%6.0f", nbhps * inputSize / MB_UNIT); fflush(NULL);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@@ -77,14 +77,15 @@ static void bench_throughput_oneHash_smallInputs(Bench_Entry hashDesc, size_t si
|
||||
double const nbhps = bench_hash(hashDesc.hash, BMK_throughput,
|
||||
s, BMK_fixedSize,
|
||||
BENCH_SMALL_TOTAL_MS, BENCH_SMALL_ITER_MS);
|
||||
printf(",%11.1f", nbhps); fflush(NULL);
|
||||
printf(",%10.0f", nbhps); fflush(NULL);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void bench_throughput_smallInputs(Bench_Entry const* hashDescTable, int nbHashes, size_t sizeMin, size_t sizeMax)
|
||||
{
|
||||
printf("Throughput small inputs of fixed size : \n");
|
||||
printf("Throughput small inputs of fixed size (from %zu to %zu bytes): \n",
|
||||
sizeMin, sizeMax);
|
||||
for (int i=0; i<nbHashes; i++)
|
||||
bench_throughput_oneHash_smallInputs(hashDescTable[i], sizeMin, sizeMax);
|
||||
}
|
||||
@@ -100,7 +101,7 @@ static void bench_latency_oneHash_smallInputs(Bench_Entry hashDesc, size_t size_
|
||||
double const nbhps = bench_hash(hashDesc.hash, BMK_latency,
|
||||
s, BMK_fixedSize,
|
||||
BENCH_SMALL_TOTAL_MS, BENCH_SMALL_ITER_MS);
|
||||
printf(",%11.1f", nbhps); fflush(NULL);
|
||||
printf(",%10.0f", nbhps); fflush(NULL);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@@ -123,7 +124,7 @@ static void bench_randomInputLength_withOneHash(Bench_Entry hashDesc, size_t siz
|
||||
double const nbhps = bench_hash(hashDesc.hash, BMK_throughput,
|
||||
s, BMK_randomSize,
|
||||
BENCH_SMALL_TOTAL_MS, BENCH_SMALL_ITER_MS);
|
||||
printf(",%11.1f", nbhps); fflush(NULL);
|
||||
printf(",%10.0f", nbhps); fflush(NULL);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@@ -146,7 +147,7 @@ static void bench_latency_oneHash_randomInputLength(Bench_Entry hashDesc, size_t
|
||||
double const nbhps = bench_hash(hashDesc.hash, BMK_latency,
|
||||
s, BMK_randomSize,
|
||||
BENCH_SMALL_TOTAL_MS, BENCH_SMALL_ITER_MS);
|
||||
printf(",%11.1f", nbhps); fflush(NULL);
|
||||
printf(",%10.0f", nbhps); fflush(NULL);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* CSV Display module for the hash benchmark program
|
||||
* Part of the xxHash project
|
||||
* Copyright (C) 2019-present, Yann Collet
|
||||
* Copyright (C) 2019-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* List hash algorithms to benchmark
|
||||
* Part of xxHash project
|
||||
* Copyright (C) 2019-present, Yann Collet
|
||||
* Copyright (C) 2019-2021 Yann Collet
|
||||
*
|
||||
* GPL v2 License
|
||||
*
|
||||
@@ -63,8 +63,8 @@
|
||||
*/
|
||||
|
||||
/* === xxHash === */
|
||||
|
||||
#include "xxh3.h"
|
||||
#define XXH_INLINE_ALL
|
||||
#include "xxhash.h"
|
||||
|
||||
size_t XXH32_wrapper(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Main program to benchmark hash functions
|
||||
* Part of the xxHash project
|
||||
* Copyright (C) 2019-present, Yann Collet
|
||||
* Copyright (C) 2019-2021 Yann Collet
|
||||
* GPL v2 License
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -74,7 +74,7 @@ static int readIntFromChar(const char** stringPtr)
|
||||
|
||||
|
||||
/**
|
||||
* longCommand():
|
||||
* isCommand():
|
||||
* Checks if string is the same as longCommand.
|
||||
* If yes, @return 1, otherwise @return 0
|
||||
*/
|
||||
@@ -169,7 +169,7 @@ static int badusage(const char* exename)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
const char* const exename = argv[0];
|
||||
int hashNb = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (C) 2019-2021 Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-2021 Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
|
||||
Loaded 100 of 480 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user