packages feed

pvector-0.1.0.0: src/Data/Vector/Persistent/Internal/Buffer.hs

module Data.Vector.Persistent.Internal.Buffer where

import Control.Monad.Primitive
import Data.Primitive.SmallArray
import Data.Vector.Persistent.Internal.Array (shrinkSmallMutableArray_)
import Prelude hiding (length)

data Buffer s a = Buffer
  { offset :: !Int,
    marr :: !(SmallMutableArray s a)
  }

new :: (PrimMonad m, s ~ PrimState m) => m (Buffer s a)
new = do
  marr <- newSmallArray 0 undefinedElem
  pure Buffer {offset = 0, marr}
{-# INLINE new #-}

newWithCapacity :: (PrimMonad m, s ~ PrimState m) => Int -> m (Buffer s a)
newWithCapacity cap = do
  marr <- newSmallArray cap undefinedElem
  pure Buffer {offset = 0, marr}
{-# INLINE newWithCapacity #-}

push :: (PrimMonad m, s ~ PrimState m) => a -> Buffer s a -> m (Buffer s a)
push a buffer = do
  buffer' <-
    if length buffer == capacity buffer
      then resize buffer
      else pure buffer
  writeSmallArray (marr buffer') (length buffer) a
  pure buffer' {offset = offset buffer' + 1}
{-# INLINE push #-}

read :: (PrimMonad m, s ~ PrimState m) => Int -> Buffer s a -> m a
read i Buffer {marr} = readSmallArray marr i
{-# INLINE read #-}

write :: (PrimMonad m, s ~ PrimState m) => Int -> a -> Buffer s a -> m ()
write i a Buffer {marr} = writeSmallArray marr i a
{-# INLINE write #-}

clear :: Buffer s a -> Buffer s a
clear = shrink 0
{-# INLINE clear #-}

shrink :: Int -> Buffer s a -> Buffer s a
shrink i buffer = buffer {offset = i}
{-# INLINE shrink #-}

unsafeShrink :: (PrimMonad m, s ~ PrimState m) => Int -> Buffer s a -> m (Buffer s a)
unsafeShrink i Buffer {marr} = do
  marr <- shrinkSmallMutableArray_ marr i
  pure Buffer {marr, offset = i}
{-# INLINE unsafeShrink #-}

capacity :: Buffer s a -> Int
capacity Buffer {marr} = sizeofSmallMutableArray marr
{-# INLINE capacity #-}

null :: Buffer s a -> Bool
null = (0 ==) . length

length :: Buffer s a -> Int
length = offset
{-# INLINE length #-}

undefinedElem :: forall a. a
undefinedElem = error "undefined element"
{-# NOINLINE undefinedElem #-}

resize :: (PrimMonad m, s ~ PrimState m) => Buffer s a -> m (Buffer s a)
resize buffer = do
  if capacity buffer == 0
    then grow 32 buffer
    else grow (capacity buffer) buffer
{-# INLINE resize #-}

grow :: (PrimMonad m, s ~ PrimState m) => Int -> Buffer s a -> m (Buffer s a)
grow more buffer@Buffer {marr, offset} = do
  marr' <- newSmallArray (sizeofSmallMutableArray marr + more) undefinedElem
  copySmallMutableArray marr' 0 marr 0 offset
  pure buffer {marr = marr'}
{-# INLINE grow #-}

freeze :: (PrimMonad m, s ~ PrimState m) => Buffer s a -> m (SmallArray a)
freeze Buffer {marr, offset} = freezeSmallArray marr 0 offset
{-# INLINE freeze #-}

unsafeFreeze :: (PrimMonad m, s ~ PrimState m) => Buffer s a -> m (SmallArray a)
unsafeFreeze Buffer {marr, offset} = do
  marr <- shrinkSmallMutableArray_ marr offset
  unsafeFreezeSmallArray marr
{-# INLINE unsafeFreeze #-}