module HaskellWorks.Data.Simd.Internal.ByteString
  ( toByteString
  , rechunkAlignedAt
  , rechunkPaddedAlignedAt
  ) where

import Data.Monoid ((<>))
import Data.Word

import qualified Data.ByteString          as BS
import qualified Data.ByteString.Internal as BS
import qualified Data.Vector.Storable     as DVS

toByteString :: DVS.Vector Word64 -> BS.ByteString
toByteString v = case DVS.unsafeToForeignPtr (DVS.unsafeCast v) of
  (fptr, vOffset, vLength) -> BS.fromForeignPtr fptr vOffset vLength
{-# INLINE toByteString #-}

rechunkAlignedAt :: Int -> [BS.ByteString] -> [BS.ByteString]
rechunkAlignedAt alignment = go
  where go (bs:bss) = case BS.length bs of
              bsLen -> if bsLen < alignment
                then case alignment - bsLen of
                  bsNeed -> case bss of
                    (cs:css) -> case BS.length cs of
                      csLen | csLen >  bsNeed -> (bs <> BS.take bsNeed cs ):go (BS.drop bsNeed cs:css)
                      csLen | csLen == bsNeed -> (bs <> cs                ):go                    css
                      _     | otherwise       ->                            go ((bs <> cs)       :css)
                    [] -> [bs]
                else case (bsLen `div` alignment) * alignment of
                  bsCroppedLen -> if bsCroppedLen == bsLen
                    then bs:go bss
                    else BS.take bsCroppedLen bs:go (BS.drop bsCroppedLen bs:bss)
        go [] = []
{-# INLINE rechunkAlignedAt #-}

rechunkPaddedAlignedAt :: Int -> [BS.ByteString] -> [BS.ByteString]
rechunkPaddedAlignedAt alignment = go
  where go (bs:bss) = case BS.length bs of
              bsLen -> if bsLen < alignment
                then case alignment - bsLen of
                  bsNeed -> case bss of
                    (cs:css) -> case BS.length cs of
                      csLen | csLen >  bsNeed -> (bs <> BS.take bsNeed cs ):go (BS.drop bsNeed cs:css)
                      csLen | csLen == bsNeed -> (bs <> cs                ):go                    css
                      _     | otherwise       ->                            go ((bs <> cs)       :css)
                    [] -> [bs <> BS.replicate bsNeed 0]
                else case (bsLen `div` alignment) * alignment of
                  bsCroppedLen -> if bsCroppedLen == bsLen
                    then bs:go bss
                    else BS.take bsCroppedLen bs:go (BS.drop bsCroppedLen bs:bss)
        go [] = []
{-# INLINE rechunkPaddedAlignedAt #-}