packages feed

primdata-0.1.2.2: Data/Array/LI.hs

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

{-| Lifted immutable arrays. -}

module Data.Array.LI where

import GHC.Exts
import Data.Foldable
import Data.Unlifted
import Data.Internal.Errors

type role Array representational
data Array a = Array (Array# a)

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

instance Functor Array where
  fmap = Data.Array.LI.map
  {-# inline fmap #-}

instance Foldable Array where
  foldr  = Data.Array.LI.foldr
  foldr' = foldr'
  foldl' = Data.Array.LI.foldl'
  null arr = size arr == 0
  length = size
  {-# inline foldr  #-}
  {-# inline foldr' #-}
  {-# inline foldl' #-}
  {-# inline null   #-}
  {-# inline length #-}

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

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

new# :: Int# -> a -> Array# a
new# n a = runRW# \s -> case newArray# n a s of
    (# s, marr #) -> case unsafeFreezeArray# marr s of
      (# _, arr #) -> arr
{-# inline new# #-}

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

empty :: Array a
empty = new 0 undefElem
{-# noinline empty #-}

infixl 7 !#
(!#) :: Array# a -> Int# -> (# a #)
(!#) = indexArray#
{-# inline (!#) #-}

infixl 7 !##
(!##) :: Array a -> Int -> (# a #)
(!##) (Array arr) (I# i) = arr !# i
{-# inline (!##) #-}

infixl 7 !
(!) :: Array a -> Int -> a
(!) arr i = case arr !## i of (# a #) -> a
{-# inline (!) #-}

size# :: Array# a -> Int#
size# = sizeofArray#
{-# inline size# #-}

size :: Array a -> Int
size (Array arr) = I# (size# arr)
{-# inline size #-}

clone# :: Array# a -> Int# -> Int# -> Array# a
clone# = cloneArray#
{-# inline clone# #-}

-- | Create a new array from a slice of the input array.
--   `Int` arguments are: offset, slice length.
clone :: Array a -> Int -> Int -> Array a
clone (Array arr) (I# i) (I# s) = Array (clone# arr i s)
{-# inline clone #-}

sizedUpdate# :: Int# -> Array# a -> Int# -> a -> Array# a
sizedUpdate# size arr i a = runRW# \s ->
    case thawArray# arr 0# size s of
        (# s, marr #) -> case writeArray# marr i a s of
            s -> case unsafeFreezeArray# marr s of
              (# s , arr #) -> arr
{-# inline sizedUpdate# #-}

-- | Create a new array where the element at an index is replaced by a given value.
--   The first parameter is the size of the array. If the size is statically known,
--   GHC is often able to generate more efficient copying code.
sizedUpdate :: Int -> Array a -> Int -> a -> Array a
sizedUpdate (I# size) (Array arr) (I# i) a = Array (sizedUpdate# size arr i a)
{-# inline sizedUpdate #-}

-- | Create a new array where the element at an index is replaced by a given value.
--   The first parameter is the size of the array.
update :: Array a -> Int -> a -> Array a
update arr i a = sizedUpdate (size arr) arr i a
{-# inline update #-}

sizedModify# :: Int# -> Array# a -> Int# -> (a -> a) -> Array# a
sizedModify# size arr i f =
  case indexArray# arr i of
    (# a #) -> sizedUpdate# size arr i (f a)
{-# inline sizedModify# #-}

-- | Create a new array where a function is lazily applied to a given element.
--   The first parameter is the size of the array. If the size is
--   statically known, GHC is often able to generate more efficient copying
--   code.
sizedModify :: Int -> Array a -> Int -> (a -> a) -> Array a
sizedModify (I# size) (Array arr) (I# i) f = Array (sizedModify# size arr i f)
{-# inline sizedModify #-}

-- | Create a new array where a function is lazily applied to a given element.
modify :: Array a -> Int -> (a -> a) -> Array a
modify arr i f = sizedModify (size arr) arr i f
{-# inline modify #-}

sizedModify'# :: Int# -> Array# a -> Int# -> (a -> a) -> Array# a
sizedModify'# size arr i f =
  case indexArray# arr i of
    (# a #) -> let !val = f a in sizedUpdate# size arr i val
{-# inline sizedModify'# #-}

-- | Create a new array where a function is strictly applied to a given element.
--   The first parameter is the size of the array. If the size is
--   statically known, GHC is often able to generate more efficient copying
--   code.
sizedModify' :: Int -> Array a -> Int -> (a -> a) -> Array a
sizedModify' (I# size) (Array arr) (I# i) f = Array (sizedModify'# size arr i f)

-- | Create a new array where a function is strictly applied to a given element.
modify' :: Array a -> Int -> (a -> a) -> Array a
modify' arr i f = sizedModify' (size arr) arr i f
{-# inline modify' #-}

sizedMap# :: forall a b. Int# -> (a -> b) ->  Array# a -> Array# b
sizedMap# size f = \arr ->
    let go :: Int# -> MutableArray# s b -> Int# -> State# s -> State# s
        go i marr size s = case i <# size of
            1# -> case indexArray# arr i of
              (# a #) -> case writeArray# marr i (f a) s of
                s -> go (i +# 1#) marr size s
            _  -> s
    in runRW# \s ->
        case newArray# size undefElem s of
            (# s, marr #) -> case go 0# marr size s of
                s -> case unsafeFreezeArray# marr s of
                  (# _ , arr #) -> arr
{-# inline sizedMap# #-}

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

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

sizedMap'# :: forall a b. Int# -> (a -> b) -> Array# a -> Array# b
sizedMap'# size f = \arr ->
    let go :: Int# -> MutableArray# s b -> Int# -> State# s -> State# s
        go i marr size s = case i <# size of
            1# -> case indexArray# arr i of
              (# a #) -> let !b = f a in case writeArray# marr i b s of
                s -> go (i +# 1#) marr size s
            _  -> s
    in runRW# \s ->
        case newArray# size undefElem s of
            (# s, marr #) -> case go 0# marr size s of
                s -> case unsafeFreezeArray# marr s of
                  (# _ , arr #) -> arr
{-# inline sizedMap'# #-}

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

map' :: forall a b. (a -> b) -> Array a -> Array b
map' f = \arr -> sizedMap' (size arr) f arr
{-# inline map' #-}

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

rfoldr :: (a -> b -> b) -> b -> Array a -> b
rfoldr f z = \(Array arr) -> go (sizeofArray# arr -# 1#) z arr where
    go i z arr = case i >=# 0# of
        1# -> case arr !# i of (# a #) -> f a (go (i -# 1#) z arr)
        _  -> z
{-# inline rfoldr #-}

foldl' :: (b -> a -> b) -> b -> Array a -> b
foldl' f z = \(Array arr) -> go 0# (sizeofArray# arr) z arr  where
    go i s z arr = case i <# s of
        1# -> case arr !# i of
                (# a #) -> let !b = f z a in go (i +# 1#) s b arr
        _  -> z
{-# inline foldl' #-}

rfoldl' :: (b -> a -> b) -> b -> Array a -> b
rfoldl' f z = \(Array arr) -> go (sizeofArray# arr -# 1#) z arr where
    go i z arr = case i >=# 0# of
        1# -> case arr!# i of
               (# a #) -> let !b = f z a in go (i -# 1#) b arr
        _  -> z
{-# inline rfoldl' #-}

fromList :: [a] -> Array a
fromList xs = case length xs of
  I# size -> Array (runRW# \s ->
     case newArray# size undefElem s of
        (# s, marr #) -> go xs 0# s where
            go (x:xs) i s = case writeArray# marr i x s of s -> go xs (i +# 1#) s
            go _      _ s = case unsafeFreezeArray# marr s of
                              (# _, arr #) -> arr)
{-# inline fromList #-}