packages feed

radix-tree-1.0.0.0: src/Data/ByteArray/NonEmpty.hs

{-# LANGUAGE BangPatterns
           , RankNTypes
           , ScopedTypeVariables
           , UnboxedTuples #-}

module Data.ByteArray.NonEmpty
  ( Step (..)

  , fromStep
  , toNonEmpty
  , toList

  , dropByteArray

  , appendByteArray
  , dropAppendByteArray
  , fromStepAppend

  , splitByteArray
  ) where

import           Control.Monad.ST
import           Data.Primitive.ByteArray
import           Data.List.NonEmpty (NonEmpty (..))
import           Data.Word



-- | Single step of destroying a key.
data Step a b = More a b
              | Done

{-# INLINE fromStep #-}
fromStep :: (x -> Step Word8 x) -> Word8 -> x -> ByteArray
fromStep (more :: x -> Step Word8 x) = \w0 -> go 1 (\marr -> writeByteArray marr 0 w0)
  where
    go :: Int -> (forall s. MutableByteArray s -> ST s ()) -> x -> ByteArray
    go !n write s =
      case more s of
        More w s' ->
          let write' marr = do
                write marr
                writeByteArray marr n w

          in go (n + 1) write' s'

        Done      ->
          runST $ do
            marr <- newByteArray n
            write marr
            unsafeFreezeByteArray marr



{-# INLINE toNonEmpty #-}
toNonEmpty :: ByteArray -> NonEmpty Word8
toNonEmpty arr = indexByteArray arr 0 :| toListFrom 1 arr

{-# INLINE toList #-}
toList :: ByteArray -> [Word8]
toList = toListFrom 0

{-# INLINE toListFrom #-}
toListFrom :: Int -> ByteArray -> [Word8]
toListFrom n0 arr = go n0
  where
    go n
      | n >= sizeofByteArray arr = []
      | otherwise                = indexByteArray arr n : go (n + 1)



dropByteArray :: Int -> ByteArray -> ByteArray
dropByteArray n arr =
  runST $ do
    let len = sizeofByteArray arr - n
    mbrr <- newByteArray len
    copyByteArray mbrr 0 arr n len
    unsafeFreezeByteArray mbrr



appendByteArray :: ByteArray -> ByteArray -> ByteArray
appendByteArray arr brr =
  runST $ do
    let alen = sizeofByteArray arr
        blen = sizeofByteArray brr
    mcrr <- newByteArray (alen + blen)
    copyByteArray mcrr 0    arr 0 alen
    copyByteArray mcrr alen brr 0 blen
    unsafeFreezeByteArray mcrr



dropAppendByteArray :: Int -> ByteArray -> ByteArray -> ByteArray
dropAppendByteArray n arr brr =
  runST $ do
    let alen = sizeofByteArray arr - n
        blen = sizeofByteArray brr
    mcrr <- newByteArray (alen + blen)
    copyByteArray mcrr 0    arr n alen
    copyByteArray mcrr alen brr 0 blen
    unsafeFreezeByteArray mcrr



{-# INLINE fromStepAppend #-}
fromStepAppend :: (x -> Step Word8 x) -> Word8 -> x -> ByteArray -> ByteArray
fromStepAppend (more :: x -> Step Word8 x) = \w0 s0 arr ->
  let go :: Int -> (forall s. MutableByteArray s -> ST s ()) -> x -> ByteArray
      go !n write s =
        case more s of
          More w s' ->
            let write' mbrr = do
                  writeByteArray mbrr n w
                  write mbrr

            in go (n + 1) write' s'

          Done      ->
            runST $ do
              let alen = sizeofByteArray arr
              mbrr <- newByteArray (n + alen)
              write mbrr
              copyByteArray mbrr n arr 0 alen
              unsafeFreezeByteArray mbrr

  in go 1 (\mbrr -> writeByteArray mbrr 0 w0) s0



data Wrap = Wrap {-# UNPACK #-} !ByteArray {-# UNPACK #-} !ByteArray

splitByteArray :: Int -> Int -> ByteArray -> (# ByteArray, ByteArray #)
splitByteArray offset n arr =
  let f = runST $ do
            let alen = sizeofByteArray arr

            mbrr <- newByteArray n
            copyByteArray mbrr 0 arr offset n
            brr <- unsafeFreezeByteArray mbrr

            let clen = alen - n

            mcrr <- newByteArray clen
            copyByteArray mcrr 0 arr n clen
            crr <- unsafeFreezeByteArray mcrr

            pure $ Wrap brr crr

  in case f of
       Wrap brr crr -> (# brr, crr #)