packages feed

packed-0.1.0: src/Packed/Bytes.hs

{-# LANGUAGE BangPatterns #-}

{-# OPTIONS_GHC
 -Weverything
 -fno-warn-unsafe
 -fno-warn-implicit-prelude
 -fno-warn-missing-import-lists
 -O2
#-}

module Packed.Bytes
  ( Bytes(..)
  , pack
  , unpack
  , drop
  , dropEnd
  , replicate
  , length
  , foldl'
  , take
  , empty
  , findByte
    -- * Characters
  , isAscii
  ) where

import Prelude hiding (take,length,replicate,drop)

import Packed.Bytes.Small (ByteArray(..))
import Data.Word (Word8)
import qualified Packed.Bytes.Window as BAW
import qualified Packed.Bytes.Small as BA

data Bytes = Bytes
  {-# UNPACK #-} !ByteArray -- payload
  {-# UNPACK #-} !Int -- offset
  {-# UNPACK #-} !Int -- length

instance Eq Bytes where
  Bytes arrA offA lenA == Bytes arrB offB lenB =
    if lenA == lenB
      then BAW.equality offA offB lenA arrA arrB
      else False

pack :: [Word8] -> Bytes
pack bs = let arr = BA.pack bs in Bytes arr 0 (BA.length arr)

unpack :: Bytes -> [Word8]
unpack (Bytes arr off len) = go off
  where
  go :: Int -> [Word8]
  go !ix = if ix < len + off
    then BA.unsafeIndex arr ix : go (ix + 1)
    else []

drop :: Int -> Bytes -> Bytes
drop n (Bytes arr off len) = if len > n
  then Bytes arr (off + n) (len - n)
  else empty

dropEnd :: Int -> Bytes -> Bytes
dropEnd n (Bytes arr off len) = if len > n
  then Bytes arr off (len - n)
  else empty

replicate :: Int -> Word8 -> Bytes
replicate len w = fromByteArray (BA.replicate len w)

fromByteArray :: ByteArray -> Bytes
fromByteArray ba = Bytes ba 0 (BA.length ba)

length :: Bytes -> Int
length (Bytes _ _ len) = len

findByte :: Word8 -> Bytes -> Maybe Int
findByte !w (Bytes arr off len) = case BAW.findByte off len w arr of
  Just ix -> Just (ix - off)
  Nothing -> Nothing

foldl' :: (a -> Word8 -> a) -> a -> Bytes -> a
foldl' f !acc0 (Bytes arr off len) = BAW.foldl' off len f acc0 arr

take :: Int -> Bytes -> Bytes
take !n (Bytes arr off len) = if n < len
  then Bytes arr off (len - n)
  else empty

empty :: Bytes
empty = Bytes BA.empty 0 0

isAscii :: Bytes -> Bool
isAscii (Bytes arr off len) = BAW.isAscii off len arr

-- In this implementation, we overallocate on each side to
-- make things line up with machine word boundaries. This
-- make the reversal eight times faster.
-- reverse :: Bytes -> Bytes
-- reverse (Bytes arr off len) =
--   let !leftWordIx = quot off (PM.sizeOf (undefined :: Word))
--       !rightWordIx = quot (off + len) (PM.sizeOf (undefined :: Word))