packages feed

primdata-0.1.2.2: Data/Array/FI.hs

{-# language
  UnboxedTuples, TypeOperators, MagicHash, RankNTypes,
  TypeApplications, ScopedTypeVariables, BangPatterns, BlockArguments,
  RoleAnnotations, TypeFamilies, AllowAmbiguousTypes #-}

{-|
Flat immutable arrays.
-}

module Data.Array.FI where

import GHC.Exts
import Data.Flat
import Data.Unlifted

type role Array representational
data Array a = Array ByteArray#

elemType :: Array a -> Proxy# a
elemType _ = proxy#
{-# inline elemType #-}

instance Unlifted (Array a) where
  type Rep (Array a) = ByteArray#
  to# (Array arr) = arr
  from#           = Array
  {-# inline to# #-}
  {-# inline from# #-}
  defaultElem = empty
  {-# inline defaultElem #-}

instance Semigroup (Array a) where
  (<>) = append; {-# inline (<>) #-}

instance Monoid (Array a) where
  mempty = empty; {-# inline mempty #-}

instance (Flat a, Show a) => Show (Array a) where
  show = show . Data.Array.FI.foldr (:) []
  {-# inline show #-}

new# :: forall a. Flat a => Int# -> ByteArray#
new# n = runRW# \s -> case newByteArray# (toByteOffset# @a proxy# n) s of
    (# s, marr #) -> case unsafeFreezeByteArray# marr s of
      (# _, arr #) -> arr
{-# inline new# #-}

new :: forall a. Flat a => Int -> Array a
new (I# n) = Array (new# @a n)
{-# inline new #-}

empty :: Array a
empty = Array (runRW# \s -> case newByteArray# 0# s of
    (# s, marr #) -> case unsafeFreezeByteArray# marr s of
      (# _, arr #) -> arr)
{-# noinline empty #-}

cons :: forall a. Flat a => a -> Array a -> Array a
cons a (Array as) = runRW# \s ->
  let as_size = sizeofByteArray# as
      a_size  = Data.Flat.size# @a proxy#
  in case newByteArray# (as_size +# a_size) s of
    (# s, marr #) -> case writeByteArray# marr 0# a s of
      s -> case copyByteArray# as 0# marr a_size as_size s of
        s -> case unsafeFreezeByteArray# marr s of
          (# _, arr #) -> Array arr
{-# inline cons #-}

append :: Array a -> Array a -> Array a
append (Array a) (Array a') = runRW# \s ->
    let size_a  = sizeofByteArray# a in
    let size_a' = sizeofByteArray# a' in
    case newByteArray# (size_a +# sizeofByteArray# a') s of
      (# s, dst #) -> case copyByteArray# a 0# dst 0# size_a s of
        s -> case copyByteArray# a' 0# dst size_a size_a' s of
          s -> case unsafeFreezeByteArray# dst s of
            (# _, arr #) -> Array arr

infixl 7 !#
(!#) :: forall a. Flat a => ByteArray# -> Int# -> a
(!#) arr i = indexByteArray# @a arr i
{-# inline (!#) #-}

infixl 7 !
(!) :: forall a. Flat a => Array a -> Int -> a
(!) (Array arr) (I# i) = indexByteArray# @a arr i
{-# inline (!) #-}

indexByBytes :: forall a. Flat a => Array a -> Int -> a
indexByBytes (Array arr) (I# i) = indexWord8ArrayAs# @a arr i
{-# inline indexByBytes #-}

size# :: forall a. Flat a => ByteArray# -> Int#
size# arr = fromByteOffset# @a proxy# (sizeofByteArray# arr)
{-# inline size# #-}

size :: forall a. Flat a => Array a -> Int
size (Array arr) = I# (Data.Array.FI.size# @a arr)
{-# inline size #-}

sizeInBytes :: forall a. Flat a => Array a -> Int
sizeInBytes (Array arr) = I# (sizeofByteArray# arr)

sizedMap# :: forall a b. (Flat a, Flat b) => Int# -> (a -> b) -> ByteArray# -> ByteArray#
sizedMap# size f = \arr ->
    let go :: Int# -> MutableByteArray# s -> Int# -> State# s -> State# s
        go i marr size s = case i <# size of
            1# -> case writeByteArray# marr i (f ((!#) @a arr i)) s of
                s -> go (i +# 1#) marr size s
            _  -> s
    in runRW# \s ->
        case newByteArray# (toByteOffset# @b proxy# size) s of
            (# s, marr #) -> case go 0# marr size s of
                s -> case unsafeFreezeByteArray# marr s of
                  (# _, arr #) -> arr
{-# inline sizedMap# #-}

sizedMap :: forall a b. (Flat a, Flat b) => Int -> (a -> b) -> Array a -> Array b
sizedMap (I# s) f = \(Array arr) -> Array (sizedMap# s f arr)
{-# inline sizedMap #-}

map :: forall a b. (Flat a, Flat b) => (a -> b) -> Array a -> Array b
map f = \arr -> sizedMap @a @b (Data.Array.FI.size arr) f arr
{-# inline map #-}

foldr :: forall a b. Flat a => (a -> b -> b) -> b -> Array a -> b
foldr f = \z (Array arr) -> go 0# (Data.Array.FI.size# @a arr) z arr where
    go i s z arr = case i <# s of
        1# -> f (arr !# i :: a) (go (i +# 1#) s z arr)
        _  -> z
{-# inline foldr #-}

foldr' :: forall a b. Flat a => (a -> b -> b) -> b -> Array a -> b
foldr' f = \z (Array arr) -> go 0# (Data.Array.FI.size# @a arr) z arr where
    go i s z arr = case i <# s of
        1# -> let !a = arr !# i :: a; !b = go (i +# 1#) s z arr in f a b
        _  -> z
{-# inline foldr' #-}

rfoldr :: forall a b. Flat a => (a -> b -> b) -> b -> Array a -> b
rfoldr f = \z (Array arr) -> go (Data.Array.FI.size# @a arr -# 1#) z arr where
    go i z arr = case i >=# 0# of
        1# -> f (arr !# i :: a) (go (i -# 1#) z arr)
        _  -> z
{-# inline rfoldr #-}

rfoldr' :: forall a b. Flat a => (a -> b -> b) -> b -> Array a -> b
rfoldr' f = \z (Array arr) -> go (Data.Array.FI.size# @a arr -# 1#) z arr where
    go i z arr = case i >=# 0# of
        1# -> let !a = arr !# i :: a; !b = go (i -# 1#) z arr in f a b
        _  -> z
{-# inline rfoldr' #-}

foldl' :: forall a b. Flat a => (b -> a -> b) -> b -> Array a -> b
foldl' f = \z (Array arr) -> go 0# (Data.Array.FI.size# @a arr) z arr  where
    go i s !z arr = case i <# s of
        1# -> go (i +# 1#) s (f z (arr !# i :: a)) arr
        _  -> z
{-# inline foldl' #-}

rfoldl' :: forall a b. Flat a => (b -> a -> b) -> b -> Array a -> b
rfoldl' f = \z (Array arr) -> go (Data.Array.FI.size# @a arr -# 1#) z arr where
    go i !z arr = case i >=# 0# of
        1# -> go (i -# 1#) (f z (arr !# i :: a)) arr
        _  -> z
{-# inline rfoldl' #-}

fromList :: forall a. Flat a => [a] -> Array a
fromList xs = case length xs of
  I# len -> Array (runRW# \s ->
    case newByteArray# (toByteOffset# @a proxy# len) s of
      (# s, marr #) -> go xs 0# s where
        go (x:xs) i s = case Data.Flat.writeByteArray# marr i x s of
                          s -> go xs (i +# 1#) s
        go _      _ s = case unsafeFreezeByteArray# marr s of (# _, arr #) -> arr)
{-# inline fromList #-}