Skip to content

Commit

Permalink
Merge pull request #18 from 4eUeP/main
Browse files Browse the repository at this point in the history
Support crc32c
  • Loading branch information
TeofilC authored Dec 13, 2023
2 parents 05bcd56 + 1fa5048 commit 4b03b47
Show file tree
Hide file tree
Showing 10 changed files with 361 additions and 46 deletions.
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

0 comments on commit 4b03b47

Please sign in to comment.