packages feed

vext-0.1.8.0: src-imp/Word128.hs

{-# language BangPatterns #-}
{-# language CPP #-}
{-# language DataKinds #-}
{-# language MagicHash #-}
{-# language PolyKinds #-}
{-# language RankNTypes #-}
{-# language StandaloneKindSignatures #-}
{-# language TypeApplications #-}
{-# language TypeFamilies #-}
{-# language UnboxedTuples #-}

module Word128
  ( R
  , A#
  , M#
  , empty#
  , index#
  , write#
  , read#
  , unsafeFreeze#
  , initialized#
  , set#
  , unsafeShrinkFreeze#
  , thaw#
  , freeze#
  , copy#
  ) where

import GHC.Exts
import Data.Kind (Type)
import Data.Unlifted (PrimArray#(..),MutablePrimArray#(..))
import EmptyPrimArray (emptyPrimArray#)

import qualified GHC.Exts as Exts

type A# = PrimArray# @( 'TupleRep '[ 'Word64Rep, 'Word64Rep ] )
type M# = MutablePrimArray# @( 'TupleRep '[ 'Word64Rep, 'Word64Rep ] )
type R = ( 'TupleRep '[ 'Word64Rep, 'Word64Rep ] )

unsafeFromW128 :: forall (a :: TYPE ( 'TupleRep '[ 'Word64Rep, 'Word64Rep ] )). (# Word64#, Word64# #) -> a
{-# inline unsafeFromW128 #-}
unsafeFromW128 (# x, y #) = unsafeCoerce# (# x, y #)

unsafeToW128 :: forall (a :: TYPE ( 'TupleRep '[ 'Word64Rep, 'Word64Rep ] )). a -> (# Word64#, Word64# #)
{-# inline unsafeToW128 #-}
unsafeToW128 x = unsafeCoerce# x

empty# :: forall (a :: TYPE R). (# #) -> A# a
empty# = emptyPrimArray#

thaw# :: forall (s :: Type) (a :: TYPE R).
     A# a
  -> Int#
  -> Int#
  -> State# s
  -> (# State# s, M# s a #)
thaw# (PrimArray# v) off len s0 = case Exts.newByteArray# (len *# 16# ) s0 of
  (# s1, m #) -> case Exts.copyByteArray# v (off *# 16# ) m 0# (len *# 16# ) s1 of
    s2 -> (# s2, MutablePrimArray# m #)

freeze# :: forall (s :: Type) (a :: TYPE R).
     M# s a
  -> Int#
  -> Int#
  -> State# s
  -> (# State# s, A# a #)
freeze# (MutablePrimArray# v) off len s0 = case Exts.newByteArray# (len *# 16# ) s0 of
  (# s1, m #) -> case Exts.copyMutableByteArray# v (off *# 16# ) m 0# (len *# 16# ) s1 of
    s2 -> case Exts.unsafeFreezeByteArray# m s2 of
      (# s3, x #) -> (# s3, PrimArray# x #)

-- shrink and freeze, all at once
unsafeShrinkFreeze# ::
     M# s a
  -> Int# -- number of elements to preserve
  -> State# s
  -> (# State# s, A# a #)
unsafeShrinkFreeze# (MutablePrimArray# m) elemCount s0Alpha =
  let !byteCount = elemCount *# 16#
   in case getSizeofMutableByteArray# m s0Alpha of
        (# s0, sz #) -> case sz ==# byteCount of
          1# -> case Exts.unsafeFreezeByteArray# m s0 of
            (# s1, v #) -> (# s1, PrimArray# v #)
          _ -> case Exts.shrinkMutableByteArray# m byteCount s0 of
            s1 -> case Exts.unsafeFreezeByteArray# m s1 of
              (# s2, v #) -> (# s2, PrimArray# v #)

unsafeFreeze# :: forall (s :: Type) (a :: TYPE R).
     M# s a
  -> State# s
  -> (# State# s, A# a #)
unsafeFreeze# (MutablePrimArray# m) s0 = case unsafeFreezeByteArray# m s0 of
  (# s1, v #) -> (# s1, PrimArray# v #)

copy# :: M# s a -> Int# -> A# a -> Int# -> Int# -> State# s -> State# s
{-# inline copy# #-}
copy# (MutablePrimArray# dst) doff (PrimArray# src) soff len =
  Exts.copyByteArray# src (soff *# 16#) dst (doff *# 16#) (len *# 16#)

-- Not exported. Offset and length are counts of elements, not bytes
setLoop# :: forall (s :: Type) (a :: TYPE R). M# s a -> Int# -> Int# -> a -> State# s -> State# s
setLoop# marr off len x s = case len of                                    
  0# -> s
  _ -> setLoop# marr (off +# 1# ) (len -# 1# ) x (write# marr off x s)                         

set# :: forall (s :: Type) (a :: TYPE R).
     M# s a
  -> Int#
  -> Int#
  -> a
  -> State# s
  -> State# s
set# m@(MutablePrimArray# b) off0 len0 a s0 = case unsafeToW128 a of
  (# x, y #) | 0## <- Exts.word64ToWord# x, 0## <- Exts.word64ToWord# y -> Exts.setByteArray# b (off0 *# 16# ) (len0 *# 16# ) 0# s0
  _ -> setLoop# m off0 len0 a s0


initialized# :: forall (s :: Type) (a :: TYPE R).
     Int#
  -> a
  -> State# s
  -> (# State# s, M# s a #)
initialized# n a s0 = case newByteArray# (n *# 16# ) s0 of
  (# s1, b #) -> case unsafeToW128 a of
    (# x, y #) | 0## <- Exts.word64ToWord# x, 0## <- Exts.word64ToWord# y -> case Exts.setByteArray# b 0# (n *# 16#) 0# s1 of
      s2 -> (# s2, MutablePrimArray# b #)
    _ -> case setLoop# (MutablePrimArray# b) 0# n a s1 of
      s2 -> (# s2, MutablePrimArray# b #)

#if WORDS_BIGENDIAN

-- TODO: Handle big-endian arch if I ever need to.

#else
index# :: forall (a :: TYPE R). A# a -> Int# -> a
{-# inline index# #-}
index# (PrimArray# arr#) i# = unsafeFromW128
  (# Exts.indexWord64Array# arr# ((2# *# i#) +# 1#)
  ,  Exts.indexWord64Array# arr# (2# *# i#) #)

read# :: forall (s :: Type) (a :: TYPE R). M# s a -> Int# -> State# s -> (# State# s, a #)
{-# inline read# #-}
read# (MutablePrimArray# arr#) i# s0 = case Exts.readWord64Array# arr# ((2# *# i#) +# 1#) s0 of
  (# s1, i0 #) -> case Exts.readWord64Array# arr# (2# *# i#) s1 of
    (# s2, i1 #) -> (# s2, unsafeFromW128 (# i0, i1 #) #)

write# :: forall (s :: Type) (a :: TYPE R). M# s a -> Int# -> a -> State# s -> State# s
{-# inline write# #-}
write# (MutablePrimArray# arr#) i# x s0 = case unsafeToW128 x of
  (# a, b #) -> case Exts.writeWord64Array# arr# ((2# *# i#) +# 1#) a s0 of
    s1 -> case Exts.writeWord64Array# arr# (2# *# i#) b s1 of
      s2 -> s2
#endif