packages feed

crc32c 0.0.0 → 0.2.2

raw patch · 14 files changed

Files

+ ChangeLog.md view
@@ -0,0 +1,18 @@+0.2.2+---++- Use system-cxx-std-lib for specifying C++ linkage++++0.2.1+---++- Fix build on aarch64.++++0.2.0+---++- Fix MacOS, Windows Build
README.md view
@@ -1,4 +1,3 @@-# crc32c-[![Build Status](https://travis-ci.org/leptonyu/crc32c.svg?branch=master)](https://travis-ci.org/leptonyu/crc32c)+# crc32c [![Hackage](https://img.shields.io/hackage/v/crc32c.svg)](https://hackage.haskell.org/package/crc32c) [![Build Status](https://travis-ci.org/leptonyu/crc32c.svg?branch=master)](https://travis-ci.org/leptonyu/crc32c) Haskell bindings for [crc32c](https://github.com/google/crc32c) 
+ bench/Bench.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE BangPatterns #-}+module Main where++import qualified Data.ByteString as BS+import           Data.ByteString (ByteString)+import           Data.Word+import           Criterion.Main++import           Data.Digest.CRC32C++main =+  defaultMain [+    env (pure (largeByteString (2^8) 42)) $ \bs ->+    bench "crc32c small (2^8)" $ whnf crc32c bs++  , env (pure (largeByteString (2^16) 42)) $ \bs ->+    bench "crc32c large (2^16)" $ whnf crc32c bs++  , env (pure (largeByteString (2^16+1) 42)) $ \bs ->+    bench "crc32c large (2^16+1)" $ whnf crc32c bs+  ]++largeByteString :: Int -> Word -> ByteString+largeByteString n seed =+    fst $ BS.unfoldrN n (Just . step) seed+  where+    -- C11 example linear congruential generator+    step :: Word -> (Word8, Word)+    step rng = (w8, rng')+      where+        !rng' = rng * 1103515245 + 12345+        !w8   = fromIntegral (rng' `div` 65536)+
crc32c.cabal view
@@ -1,27 +1,23 @@-cabal-version: 1.12---- This file has been generated from package.yaml by hpack version 0.31.1.------ see: https://github.com/sol/hpack------ hash: 90e286fde5d013c853cdb6ad9ef6c03ad8eea828fa98d136baf253d357d78dee+cabal-version: 2.2  name:           crc32c-version:        0.0.0-synopsis:       Haskell bindings for crc32c+version:        0.2.2+description:    Haskell bindings for crc32c+synopsis:       crc32c category:       FFI, Raw homepage:       https://github.com/leptonyu/crc32c#readme author:         Daniel YU maintainer:     leptonyu@gmail.com copyright:      (c) Daniel YU-license:        BSD3+license:        BSD-3-Clause license-file:   LICENSE build-type:     Simple extra-source-files:     README.md+    ChangeLog.md     include/LICENSE     include/crc32c_arm64.h-    include/crc32c_arm64_linux_check.h+    include/crc32c_arm64_check.h     include/crc32c_internal.h     include/crc32c_prefetch.h     include/crc32c_read_le.h@@ -34,45 +30,52 @@ library   exposed-modules:       Data.Digest.CRC32C-  other-modules:-      Data.Digest.CRC32C.Internal   hs-source-dirs:       src+  build-depends:+      base >=4.9 && <5+    , bytestring >=0.11.5+  default-language: Haskell2010+   include-dirs:       include-  c-sources:+  cxx-sources:       include/crc32c.cc       include/crc32c_arm64.cc       include/crc32c_portable.cc       include/crc32c_sse42.cc-  extra-libraries:-      stdc++-  build-tools:-      c2hs-  build-depends:-      base >=4.9 && <5-    , bytestring >=0.10.8.2 && <0.11-  if arch(x86_64)-    cc-options: -std=c++11 -D__HAVE_SSE42=1 -D__HAVE_ARM64_CRC32C=0 -msse4.2+  cxx-options: -std=c++11+  if impl(ghc >= 9.4)+    build-depends: system-cxx-std-lib   else-    if arch(arm)-      cc-options: -std=c++11 -D__HAVE_SSE42=0 -D__HAVE_ARM64_CRC32C=1-    else-      cc-options: -std=c++11 -D__HAVE_SSE42=0 -D__HAVE_ARM64_CRC32C=0-  default-language: Haskell2010+    extra-libraries:+      stdc+++  if (arch(x86_64) && !os(windows))+    cxx-options: -DHAVE_SSE42=1 -msse4.2+  if arch(arm)+    cxx-options: -DHAVE_ARM64_CRC32C=1  test-suite crc32c-test   type: exitcode-stdio-1.0   main-is: Spec.hs-  other-modules:-      Paths_crc32c   hs-source-dirs:       test   build-depends:       QuickCheck-    , base >=4.9 && <5-    , bytestring >=0.10.8.2 && <0.11+    , base+    , bytestring     , crc32c     , hspec     , hspec-core+  default-language: Haskell2010++benchmark crc32c-bench+  type: exitcode-stdio-1.0+  main-is: Bench.hs+  hs-source-dirs: bench+  build-depends:+      base+    , bytestring+    , crc32c+    , criterion   default-language: Haskell2010
include/crc32c.cc view
@@ -8,7 +8,7 @@ #include <cstdint>  #include "./crc32c_arm64.h"-#include "./crc32c_arm64_linux_check.h"+#include "./crc32c_arm64_check.h" #include "./crc32c_internal.h" #include "./crc32c_sse42.h" #include "./crc32c_sse42_check.h"@@ -20,8 +20,8 @@   static bool can_use_sse42 = CanUseSse42();   if (can_use_sse42) return ExtendSse42(crc, data, count); #elif HAVE_ARM64_CRC32C-  static bool can_use_arm_linux = CanUseArm64Linux();-  if (can_use_arm_linux) return ExtendArm64(crc, data, count);+  static bool can_use_arm64_crc32 = CanUseArm64Crc32();+  if (can_use_arm64_crc32) return ExtendArm64(crc, data, count); #endif  // HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))    return ExtendPortable(crc, data, count);
include/crc32c/crc32c_config.h view
@@ -12,7 +12,9 @@ #define HAVE_BUILTIN_PREFETCH 1  // Define to 1 if targeting X86 and the compiler has the _mm_prefetch intrinsic.+#if (defined(_M_X64) || defined(__x86_64__)) #define HAVE_MM_PREFETCH 1+#endif  // 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+.
include/crc32c_arm64.cc view
@@ -62,7 +62,7 @@  namespace crc32c { -uint32_t ExtendArm64(uint32_t crc, const uint8_t *buf, size_t size) {+uint32_t ExtendArm64(uint32_t crc, const uint8_t *data, size_t size) {   int64_t length = size;   uint32_t crc0, crc1, crc2, crc3;   uint64_t t0, t1, t2;@@ -72,7 +72,6 @@   const poly64_t k0 = 0x8d96551c, k1 = 0xbd6f81f8, k2 = 0xdcb17aa4;    crc = crc ^ kCRC32Xor;-  const uint8_t *p = reinterpret_cast<const uint8_t *>(buf);    while (length >= KBYTES) {     crc0 = crc;@@ -81,14 +80,14 @@     crc3 = 0;      // Process 1024 bytes in parallel.-    CRC32C1024BYTES(p);+    CRC32C1024BYTES(data);      // Merge the 4 partial CRC32C values.     t2 = (uint64_t)vmull_p64(crc2, k2);     t1 = (uint64_t)vmull_p64(crc1, k1);     t0 = (uint64_t)vmull_p64(crc0, k0);-    crc = __crc32cd(crc3, *(uint64_t *)p);-    p += sizeof(uint64_t);+    crc = __crc32cd(crc3, *(uint64_t *)data);+    data += sizeof(uint64_t);     crc ^= __crc32cd(0, t2);     crc ^= __crc32cd(0, t1);     crc ^= __crc32cd(0, t0);@@ -97,23 +96,23 @@   }    while (length >= 8) {-    crc = __crc32cd(crc, *(uint64_t *)p);-    p += 8;+    crc = __crc32cd(crc, *(uint64_t *)data);+    data += 8;     length -= 8;   }    if (length & 4) {-    crc = __crc32cw(crc, *(uint32_t *)p);-    p += 4;+    crc = __crc32cw(crc, *(uint32_t *)data);+    data += 4;   }    if (length & 2) {-    crc = __crc32ch(crc, *(uint16_t *)p);-    p += 2;+    crc = __crc32ch(crc, *(uint16_t *)data);+    data += 2;   }    if (length & 1) {-    crc = __crc32cb(crc, *p);+    crc = __crc32cb(crc, *data);   }    return crc ^ kCRC32Xor;
include/crc32c_arm64.h view
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. -// Linux-specific code checking the availability for ARM CRC32C instructions.+// ARM-specific code -#ifndef CRC32C_CRC32C_ARM_LINUX_H_-#define CRC32C_CRC32C_ARM_LINUX_H_+#ifndef CRC32C_CRC32C_ARM_H_+#define CRC32C_CRC32C_ARM_H_  #include <cstddef> #include <cstdint>@@ -22,4 +22,4 @@  #endif  // HAVE_ARM64_CRC32C -#endif  // CRC32C_CRC32C_ARM_LINUX_H_+#endif  // CRC32C_CRC32C_ARM_H_
+ include/crc32c_arm64_check.h view
@@ -0,0 +1,66 @@+// Copyright 2017 The CRC32C Authors. All rights reserved.+// Use of this source code is governed by a BSD-style license that can be+// found in the LICENSE file. See the AUTHORS file for names of contributors.++// ARM-specific code checking for the availability of CRC32C instructions.++#ifndef CRC32C_CRC32C_ARM_CHECK_H_+#define CRC32C_CRC32C_ARM_CHECK_H_++#include <cstddef>+#include <cstdint>++#include "crc32c/crc32c_config.h"++#if HAVE_ARM64_CRC32C++#ifdef __linux__+#if HAVE_STRONG_GETAUXVAL+#include <sys/auxv.h>+#elif HAVE_WEAK_GETAUXVAL+// getauxval() is not available on Android until API level 20. Link it as a weak+// symbol.+extern "C" unsigned long getauxval(unsigned long type) __attribute__((weak));++#define AT_HWCAP 16+#endif  // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL+#endif  // defined (__linux__)++#ifdef __APPLE__+#include <sys/types.h>+#include <sys/sysctl.h>+#endif  // defined (__APPLE__)++namespace crc32c {++inline bool CanUseArm64Crc32() {+#if defined (__linux__) && (HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL)+  // From 'arch/arm64/include/uapi/asm/hwcap.h' in Linux kernel source code.+  constexpr unsigned long kHWCAP_PMULL = 1 << 4;+  constexpr unsigned long kHWCAP_CRC32 = 1 << 7;+  unsigned long hwcap =+#if HAVE_STRONG_GETAUXVAL+      // Some compilers warn on (&getauxval != nullptr) in the block below.+      getauxval(AT_HWCAP);+#elif HAVE_WEAK_GETAUXVAL+      (&getauxval != nullptr) ? getauxval(AT_HWCAP) : 0;+#else+#error This is supposed to be nested inside a check for HAVE_*_GETAUXVAL.+#endif  // HAVE_STRONG_GETAUXVAL+  return (hwcap & (kHWCAP_PMULL | kHWCAP_CRC32)) ==+         (kHWCAP_PMULL | kHWCAP_CRC32);+#elif defined(__APPLE__)+  int val = 0;+  size_t len = sizeof(val);+  return sysctlbyname("hw.optional.armv8_crc32", &val, &len, nullptr, 0) == 0+             && val != 0;+#else+  return false;+#endif  // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL+}++}  // namespace crc32c++#endif  // HAVE_ARM64_CRC32C++#endif  // CRC32C_CRC32C_ARM_CHECK_H_
− include/crc32c_arm64_linux_check.h
@@ -1,48 +0,0 @@-// Copyright 2017 The CRC32C Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--// ARM Linux-specific code checking for the availability of CRC32C instructions.--#ifndef CRC32C_CRC32C_ARM_LINUX_CHECK_H_-#define CRC32C_CRC32C_ARM_LINUX_CHECK_H_--// X86-specific code checking for the availability of SSE4.2 instructions.--#include <cstddef>-#include <cstdint>--#include "crc32c/crc32c_config.h"--#if HAVE_ARM64_CRC32C--#if HAVE_STRONG_GETAUXVAL-#include <sys/auxv.h>-#elif HAVE_WEAK_GETAUXVAL-// getauxval() is not available on Android until API level 20. Link it as a weak-// symbol.-extern "C" unsigned long getauxval(unsigned long type) __attribute__((weak));--#define AT_HWCAP 16-#endif  // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL--namespace crc32c {--inline bool CanUseArm64Linux() {-#if HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL-  // From 'arch/arm64/include/uapi/asm/hwcap.h' in Linux kernel source code.-  constexpr unsigned long kHWCAP_PMULL = 1 << 4;-  constexpr unsigned long kHWCAP_CRC32 = 1 << 7;-  unsigned long hwcap = (&getauxval != nullptr) ? getauxval(AT_HWCAP) : 0;-  return (hwcap & (kHWCAP_PMULL | kHWCAP_CRC32)) ==-         (kHWCAP_PMULL | kHWCAP_CRC32);-#else-  return false;-#endif  // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL-}--}  // namespace crc32c--#endif  // HAVE_ARM64_CRC32C--#endif  // CRC32C_CRC32C_ARM_LINUX_CHECK_H_
include/crc32c_read_le.h view
@@ -30,14 +30,14 @@ // Reads a little-endian 64-bit integer from a 64-bit-aligned buffer. inline uint64_t ReadUint64LE(const uint8_t* buffer) { #if BYTE_ORDER_BIG_ENDIAN-  return ((static_cast<uint32_t>(static_cast<uint8_t>(buffer[0]))) |-          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[1])) << 8) |-          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[2])) << 16) |-          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[3])) << 24) |-          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[4])) << 32) |-          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[5])) << 40) |-          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[6])) << 48) |-          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[7])) << 56));+  return ((static_cast<uint64_t>(static_cast<uint8_t>(buffer[0]))) |+          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[1])) << 8) |+          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[2])) << 16) |+          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[3])) << 24) |+          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[4])) << 32) |+          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[5])) << 40) |+          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[6])) << 48) |+          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[7])) << 56)); #else   // !BYTE_ORDER_BIG_ENDIAN   uint64_t result;   // This should be optimized to a single instruction.
include/crc32c_sse42.cc view
@@ -174,7 +174,7 @@     }   } -  // Proccess the data in predetermined block sizes with tables for quickly+  // Process the data in predetermined block sizes with tables for quickly   // combining the checksum. Experimentally it's better to use larger block   // sizes where possible so use a hierarchy of decreasing block sizes.   uint64_t l64 = l;
src/Data/Digest/CRC32C.hs view
@@ -3,16 +3,56 @@   , crc32c_update   ) where -import           Data.ByteString.Internal    (ByteString (..))-import           Data.Digest.CRC32C.Internal+import           Data.ByteString (ByteString)+import           Data.ByteString.Unsafe (unsafeUseAsCStringLen) import           Data.Word-import           Foreign.C.Types-import           Foreign.ForeignPtr.Unsafe-import           Foreign.Ptr +import           Foreign+import           Foreign.C+import           Foreign.Marshal.Unsafe+ crc32c :: ByteString -> Word32-crc32c (PS p o l) = fromIntegral $ lib_crc32c_value (unsafeForeignPtrToPtr p `plusPtr` o) (fromIntegral l)+crc32c bs =+  fromIntegral $+    unsafeLocalState $+      unsafeUseAsCStringLen bs $ \(p, l) ->+        lib_crc32c_value (castPtr p) (fromIntegral l)  crc32c_update :: Word32 -> ByteString -> Word32-crc32c_update hash (PS p o l) = fromIntegral $ lib_crc32c_extend (CUInt hash) (unsafeForeignPtrToPtr p `plusPtr` o) (fromIntegral l)+crc32c_update hash bs =+  fromIntegral $+    unsafeLocalState $+      unsafeUseAsCStringLen bs $ \(p, l) ->+        lib_crc32c_extend (fromIntegral hash) (castPtr p) (fromIntegral l) +-- FFI: safe or unsafe?+-- All of the FFI here is not-reentrant so we don't have to use safe. However+-- for very large inputs, the calls will take a while and during that time+-- they will block GC and other Haskell threads on the same capability. So+-- for very large inputs we would prefer to use a safe FFI call. But for small+-- inputs, the overhead of a safe FFI call is quite substantial, e.g+-- ~5x for 256 bytes, dropping to only ~10% for 16kb.+--+-- The solution we use here is to use unsafe FFI calls for smaller buffers and+-- safe FFI calls for larger buffers. This bounds the time that these calls+-- can block other threads or GC.++lib_crc32c_extend :: CUInt -> Ptr CUChar -> CSize -> IO CUInt+lib_crc32c_extend hash p l | l > 0x10000 = lib_crc32c_extend_safe hash p l+                           | otherwise   = lib_crc32c_extend_unsafe hash p l++lib_crc32c_value :: Ptr CUChar -> CSize -> IO CUInt+lib_crc32c_value p l | l > 0x10000 = lib_crc32c_value_safe p l+                     | otherwise   = lib_crc32c_value_unsafe p l++foreign import ccall unsafe "crc32c/crc32c.h crc32c_extend"+  lib_crc32c_extend_unsafe :: CUInt -> Ptr CUChar -> CSize -> IO CUInt++foreign import ccall safe "crc32c/crc32c.h crc32c_extend"+  lib_crc32c_extend_safe :: CUInt -> Ptr CUChar -> CSize -> IO CUInt++foreign import ccall unsafe "crc32c/crc32c.h crc32c_value"+  lib_crc32c_value_unsafe :: Ptr CUChar -> CSize -> IO CUInt++foreign import ccall safe "crc32c/crc32c.h crc32c_value"+  lib_crc32c_value_safe :: Ptr CUChar -> CSize -> IO CUInt
− src/Data/Digest/CRC32C/Internal.chs
@@ -1,12 +0,0 @@-module Data.Digest.CRC32C.Internal where--#include <crc32c/crc32c.h>--import Foreign.C-import Foreign.Ptr--lib_crc32c_extend :: CUInt -> Ptr CUChar -> CULong -> CUInt-lib_crc32c_extend = {#call pure crc32c_extend #}--lib_crc32c_value :: Ptr CUChar -> CULong -> CUInt-lib_crc32c_value  = {#call pure crc32c_value  #}