Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support crc32c #18

Merged
merged 4 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions .github/workflows/haskell-ci.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# This GitHub workflow config has been generated by a script via
#
# haskell-ci 'github' 'digest.cabal'
# haskell-ci 'github' '--distribution' 'focal' '--submodules' 'digest.cabal'
#
# To regenerate the script (for example after adjusting tested-with) run
#
# haskell-ci regenerate
#
# For more information, see https://github.com/haskell-CI/haskell-ci
#
# version: 0.15.20221107
# version: 0.16.6
#
# REGENDATA ("0.15.20221107",["github","digest.cabal"])
# REGENDATA ("0.16.6",["github","--distribution","focal","--submodules","digest.cabal"])
#
name: Haskell-CI
on:
Expand All @@ -23,7 +23,7 @@ jobs:
timeout-minutes:
60
container:
image: buildpack-deps:bionic
image: buildpack-deps:focal
continue-on-error: ${{ matrix.allow-failure }}
strategy:
matrix:
Expand Down Expand Up @@ -55,10 +55,10 @@ jobs:
apt-get update
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
mkdir -p "$HOME/.ghcup/bin"
curl -sL https://downloads.haskell.org/ghcup/0.1.18.0/x86_64-linux-ghcup-0.1.18.0 > "$HOME/.ghcup/bin/ghcup"
curl -sL https://downloads.haskell.org/ghcup/0.1.19.2/x86_64-linux-ghcup-0.1.19.2 > "$HOME/.ghcup/bin/ghcup"
chmod a+x "$HOME/.ghcup/bin/ghcup"
"$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
"$HOME/.ghcup/bin/ghcup" install cabal 3.6.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
"$HOME/.ghcup/bin/ghcup" install cabal 3.10.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
env:
HCKIND: ${{ matrix.compilerKind }}
HCNAME: ${{ matrix.compiler }}
Expand All @@ -74,7 +74,7 @@ jobs:
echo "HC=$HC" >> "$GITHUB_ENV"
echo "HCPKG=$HOME/.ghcup/bin/$HCKIND-pkg-$HCVER" >> "$GITHUB_ENV"
echo "HADDOCK=$HOME/.ghcup/bin/haddock-$HCVER" >> "$GITHUB_ENV"
echo "CABAL=$HOME/.ghcup/bin/cabal-3.6.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"
HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
Expand Down Expand Up @@ -124,16 +124,17 @@ jobs:
- name: install cabal-plan
run: |
mkdir -p $HOME/.cabal/bin
curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc cabal-plan.xz' | sha256sum -c -
curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.7.3.0/cabal-plan-0.7.3.0-x86_64-linux.xz > cabal-plan.xz
echo 'f62ccb2971567a5f638f2005ad3173dba14693a45154c1508645c52289714cb2 cabal-plan.xz' | sha256sum -c -
xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
rm -f cabal-plan.xz
chmod a+x $HOME/.cabal/bin/cabal-plan
cabal-plan --version
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
path: source
submodules: "true"
- name: initial cabal.project for sdist
run: |
touch cabal.project
Expand Down Expand Up @@ -166,8 +167,8 @@ jobs:
run: |
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
cabal-plan
- name: cache
uses: actions/cache@v2
- name: restore cache
uses: actions/cache/restore@v3
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
Expand All @@ -188,8 +189,14 @@ jobs:
${CABAL} -vnormal check
- name: haddock
run: |
$CABAL v2-haddock --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
$CABAL v2-haddock --disable-documentation --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
- name: unconstrained build
run: |
rm -f cabal.project.local
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
- name: save cache
uses: actions/cache/save@v3
if: always()
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "external/crc32c"]
path = external/crc32c
url = https://github.com/google/crc32c.git
72 changes: 72 additions & 0 deletions Data/Digest/CRC32C.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnliftedFFITypes #-}

module Data.Digest.CRC32C
( CRC32C
, crc32c
, crc32cUpdate
) where

import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Short as BSS
import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
import Data.Word
import Foreign.C.Types
import Foreign.Ptr
import GHC.Exts (ByteArray#)
import System.IO.Unsafe (unsafeDupablePerformIO)

#if !MIN_VERSION_bytestring(0, 11, 1)
import qualified Data.ByteString.Short.Internal as BSS
#endif

class CRC32C a where
-- | Compute CRC32C checksum
crc32c :: a -> Word32
crc32c = crc32cUpdate 0

-- | Given the CRC32C checksum of a string, compute CRC32C of its
-- concatenation with another string (t.i., incrementally update
-- the CRC32C hash value)
crc32cUpdate :: Word32 -> a -> Word32

instance CRC32C BS.ByteString where
crc32c bs = unsafeDupablePerformIO $
unsafeUseAsCStringLen bs $ \(ptr, len) ->
crc32c_value (castPtr ptr) (fromIntegral len)

crc32cUpdate cks bs = unsafeDupablePerformIO $
unsafeUseAsCStringLen bs $ \(ptr, len) ->
crc32c_extend cks (castPtr ptr) (fromIntegral len)

instance CRC32C BL.ByteString where
crc32cUpdate = BL.foldlChunks crc32cUpdate

instance CRC32C [Word8] where
crc32cUpdate n = (crc32cUpdate n) . BL.pack

instance CRC32C BSS.ShortByteString where
crc32c sbs@(BSS.SBS ba#) = unsafeDupablePerformIO $
-- Must be unsafe ffi
crc32c_value' ba# (fromIntegral $ BSS.length sbs)

crc32cUpdate cks sbs@(BSS.SBS ba#) = unsafeDupablePerformIO $
-- Must be unsafe ffi
crc32c_extend' cks ba# (fromIntegral $ BSS.length sbs)

-------------------------------------------------------------------------------

foreign import ccall unsafe "crc32c/crc32c.h crc32c_value"
crc32c_value :: Ptr Word8 -> CSize -> IO Word32

foreign import ccall unsafe "crc32c/crc32c.h crc32c_extend"
crc32c_extend :: Word32 -> Ptr Word8 -> CSize -> IO Word32

foreign import ccall unsafe "crc32c/crc32c.h crc32c_value"
crc32c_value' :: ByteArray# -> CSize -> IO Word32

foreign import ccall unsafe "crc32c/crc32c.h crc32c_extend"
crc32c_extend' :: Word32 -> ByteArray# -> CSize -> IO Word32
147 changes: 114 additions & 33 deletions digest.cabal
Original file line number Diff line number Diff line change
@@ -1,51 +1,132 @@
name: digest
version: 0.0.1.7
x-revision: 1
copyright: (c) 2009 Eugene Kirpichov
license: BSD2
license-file: LICENSE
author: Eugene Kirpichov <ekirpichov@gmail.com>
maintainer: Eugene Kirpichov <ekirpichov@gmail.com>
category: Cryptography
synopsis: CRC32 and Adler32 hashes for bytestrings
description: This package provides efficient hash implementations for
strict and lazy bytestrings. For now, CRC32 and Adler32 are supported;
they are implemented as FFI bindings to efficient code from zlib.
stability: provisional
build-type: Simple
cabal-version: >= 1.10
tested-with:
GHC==8.10.7
, GHC==9.0.2
, GHC==9.2.5
, GHC==9.4.3
cabal-version: 2.4
name: digest
version: 0.0.1.7
x-revision: 1
copyright: (c) 2009 Eugene Kirpichov
license: BSD-2-Clause
license-file: LICENSE
author: Eugene Kirpichov <ekirpichov@gmail.com>
maintainer: Eugene Kirpichov <ekirpichov@gmail.com>
category: Cryptography
synopsis: CRC32 and Adler32 hashes for bytestrings
description:
This package provides efficient hash implementations for
strict and lazy bytestrings. For now, CRC32 and Adler32 are supported;
they are implemented as FFI bindings to efficient code from zlib.

stability: provisional
build-type: Simple
tested-with: GHC ==8.10.7 || ==9.0.2 || ==9.2.5 || ==9.4.3
extra-source-files:
CHANGELOG.md
external/crc32c/include/crc32c/crc32c.h
external/crc32c/LICENSE
external/crc32c/src/*.h
include/crc32c/crc32c_config.h
testing/trivial-reference.c
testing/trivial.expected
testing/trivial.hs
CHANGELOG.md

flag pkg-config
default: True
manual: True
description: Use @pkg-config(1)@ to locate @zlib@ library.

-- TODO: auto detect
flag have_builtin_prefetch
default: False
manual: True
description: The cxx compiler has the __builtin_prefetch intrinsic.

-- TODO: auto detect
flag have_mm_prefetch
default: False
manual: True
description:
Targeting X86 and the compiler has the _mm_prefetch intrinsic.

-- TODO: auto detect
flag have_sse42
default: False
manual: True
description:
Can be enabled to improve performance of CRC32C if targeting X86 and
the compiler has the _mm_crc32_u{8,32,64} intrinsics.

-- TODO: auto detect
flag have_arm64_crc32c
default: False
manual: True
description:
Targeting ARM and the compiler has the __crc32c{b,h,w,d} and the
vmull_p64 intrinsics.

-- TODO: auto detect
flag have_strong_getauxval
default: False
manual: True
description:
The system libraries have the getauxval function in the <sys/auxv.h> header.
Should be true on Linux and Android API level 20+.

-- TODO: auto detect
flag have_weak_getauxval
default: False
manual: True
description:
The compiler supports defining getauxval as a weak symbol.
Should be true for any compiler that supports __attribute__((weak)).

source-repository head
type: git
type: git
location: https://github.com/TeofilC/digest

library
exposed-modules: Data.Digest.CRC32,
Data.Digest.Adler32
default-extensions: CPP, ForeignFunctionInterface
default-language: Haskell2010
build-depends:
base < 5
, bytestring >= 0.9 && < 0.13
includes: zlib.h
ghc-options: -Wall
if flag(pkg-config) && !os(windows) && !os(freebsd)
exposed-modules:
Data.Digest.Adler32
Data.Digest.CRC32
Data.Digest.CRC32C

default-extensions:
CPP
ForeignFunctionInterface

default-language: Haskell2010
build-depends:
, base >=4.12 && <5
, bytestring >=0.10 && <0.13

includes: zlib.h
include-dirs: include external/crc32c/include
cxx-options: -std=c++11
cxx-sources:
external/crc32c/src/crc32c.cc
external/crc32c/src/crc32c_portable.cc

if flag(have_builtin_prefetch)
cxx-options: -DHAVE_BUILTIN_PREFETCH

if flag(have_mm_prefetch)
cxx-options: -DHAVE_MM_PREFETCH

if (arch(x86_64) && flag(have_sse42))
cxx-options: -DHAVE_SSE42 -msse4.2
cxx-sources: external/crc32c/src/crc32c_sse42.cc

if (arch(aarch64) && flag(have_arm64_crc32c))
cxx-options: -DHAVE_ARM64_CRC32C
cxx-sources: external/crc32c/src/crc32c_arm64.cc

if flag(have_strong_getauxval)
cxx-options: -DHAVE_STRONG_GETAUXVAL

if flag(have_weak_getauxval)
cxx-options: -DHAVE_WEAK_GETAUXVAL

ghc-options: -Wall

if ((flag(pkg-config) && !os(windows)) && !os(freebsd))
pkgconfig-depends: zlib

else
build-depends: zlib
1 change: 1 addition & 0 deletions external/crc32c
Submodule crc32c added at 21fc8e
49 changes: 49 additions & 0 deletions include/crc32c/crc32c_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Also see: external/crc32c/src/crc32c_config.h.in
#ifndef CRC32C_CRC32C_CONFIG_H_
#define CRC32C_CRC32C_CONFIG_H_

// From GHC
#include <MachDeps.h>

#ifdef WORDS_BIGENDIAN
// Define to 1 if building for a big-endian platform.
#define BYTE_ORDER_BIG_ENDIAN 1
#else
#define BYTE_ORDER_BIG_ENDIAN 0
#endif

// Set by cabal flag 'have_builtin_prefetch'
//
// Define to 1 if the compiler has the __builtin_prefetch intrinsic.
//#define HAVE_BUILTIN_PREFETCH 0

// Set by cabal flag 'have_mm_prefetch'
//
// Define to 1 if targeting X86 and the compiler has the _mm_prefetch intrinsic.
//#define HAVE_MM_PREFETCH 0

// Set by cabal flag 'have_sse42'
//
// Define to 1 if targeting X86 and the compiler has the _mm_crc32_u{8,32,64}
// intrinsics.
//#define HAVE_SSE42 0

// Set by cabal flag 'have_arm64_crc32c'
//
// Define to 1 if targeting ARM and the compiler has the __crc32c{b,h,w,d} and
// the vmull_p64 intrinsics.
//#define HAVE_ARM64_CRC32C 0

// Set by cabal flag 'have_strong_getauxval'
//
// Define to 1 if the system libraries have the getauxval function in the
// <sys/auxv.h> header. Should be true on Linux and Android API level 20+.
//#define HAVE_STRONG_GETAUXVAL 0

// Set by cabal flag 'have_weak_getauxval'
//
// Define to 1 if the compiler supports defining getauxval as a weak symbol.
// Should be true for any compiler that supports __attribute__((weak)).
//#define HAVE_WEAK_GETAUXVAL 0

#endif // CRC32C_CRC32C_CONFIG_H_
Loading