base16

Fast Haskell base16 encoding/decoding (docs.ppad.tech/base16).
git clone git://git.ppad.tech/base16.git
Log | Files | Refs | README | LICENSE

Arm.hs (2277B)


      1 {-# OPTIONS_HADDOCK hide #-}
      2 {-# LANGUAGE BangPatterns #-}
      3 
      4 -- |
      5 -- Module: Data.ByteString.Base16.Arm
      6 -- Copyright: (c) 2025 Jared Tobin
      7 -- License: MIT
      8 -- Maintainer: Jared Tobin <jared@ppad.tech>
      9 --
     10 -- ARM NEON support for base16 encoding and decoding.
     11 
     12 module Data.ByteString.Base16.Arm (
     13     base16_arm_available
     14   , encode
     15   , decode
     16   ) where
     17 
     18 import qualified Data.Bits as B
     19 import qualified Data.ByteString as BS
     20 import qualified Data.ByteString.Internal as BI
     21 import Data.Word (Word8)
     22 import Foreign.C.Types (CInt(..), CSize(..))
     23 import Foreign.ForeignPtr (withForeignPtr)
     24 import Foreign.Ptr (Ptr, plusPtr)
     25 import System.IO.Unsafe (unsafeDupablePerformIO)
     26 
     27 -- ffi ------------------------------------------------------------------------
     28 
     29 foreign import ccall unsafe "base16_encode_arm"
     30   c_base16_encode :: Ptr Word8 -> Ptr Word8 -> CSize -> IO ()
     31 
     32 foreign import ccall unsafe "base16_decode_arm"
     33   c_base16_decode :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
     34 
     35 foreign import ccall unsafe "base16_arm_available"
     36   c_base16_arm_available :: IO CInt
     37 
     38 -- utilities ------------------------------------------------------------------
     39 
     40 fi :: (Integral a, Num b) => a -> b
     41 fi = fromIntegral
     42 {-# INLINE fi #-}
     43 
     44 -- api ------------------------------------------------------------------------
     45 
     46 -- | Are ARM NEON extensions available?
     47 base16_arm_available :: Bool
     48 base16_arm_available =
     49   unsafeDupablePerformIO c_base16_arm_available /= 0
     50 {-# NOINLINE base16_arm_available #-}
     51 
     52 -- | Encode a base256 'ByteString' as base16 using NEON.
     53 encode :: BS.ByteString -> BS.ByteString
     54 encode (BI.PS sfp soff l) =
     55   BI.unsafeCreate (l `B.shiftL` 1) $ \dst ->
     56     withForeignPtr sfp $ \sp0 ->
     57       c_base16_encode (sp0 `plusPtr` soff) dst (fi l)
     58 
     59 -- | Decode a base16 'ByteString' to base256 using NEON.  Returns
     60 --   'Nothing' on odd-length or otherwise invalid input.
     61 decode :: BS.ByteString -> Maybe BS.ByteString
     62 decode (BI.PS sfp soff l)
     63   | B.testBit l 0 = Nothing
     64   | otherwise = unsafeDupablePerformIO $ do
     65       let !n = l `B.shiftR` 1
     66       fp <- BI.mallocByteString n
     67       ok <- withForeignPtr fp  $ \dst ->
     68             withForeignPtr sfp $ \sp0 ->
     69               c_base16_decode (sp0 `plusPtr` soff) dst (fi n)
     70       pure $! if ok /= 0 then Just (BI.PS fp 0 n) else Nothing