{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UnliftedNewtypes #-}

-- | References to 'Int#'.
module Mikan.Utils.IntVar
  ( IntVar#(..)
  , newIntVar#
  , readIntVar#
  , writeIntVar#
  ) where

#include "MachDeps.h"

import GHC.Base

-- | An (unlifted) reference to an 'Int#'.
--
-- An @'IntVar#' s@ is morally a @'MutVar#' s 'Int#'@.
-- However, the value stored in a #'MutVar#'@ must have a boxed
-- runtime representation, which adds an extra pointer indirection.
--
-- @'IntVar#'@ avoids this by storing the 'Int#' inside of a 'MutableByteArray#'
-- containing @SIZEOF_HSINT@ bytes.
newtype IntVar# s = IntVar# (MutableByteArray# s)

{-# INLINE newIntVar# #-}
-- | Create a new 'IntVar#' containing an initial value.
newIntVar# :: Int# -> State# s -> (# State# s, IntVar# s #)
newIntVar# :: forall s. Int# -> State# s -> (# State# s, IntVar# s #)
newIntVar# Int#
n State# s
s0 =
  let
    !(# State# s
s1, MutableByteArray# s
bytes #) = Int# -> State# s -> (# State# s, MutableByteArray# s #)
forall d. Int# -> State# d -> (# State# d, MutableByteArray# d #)
newByteArray# SIZEOF_HSINT# s0
    !s2 :: State# s
s2 = MutableByteArray# s -> Int# -> Int# -> State# s -> State# s
forall d.
MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
writeIntArray# MutableByteArray# s
bytes Int#
0# Int#
n State# s
s1
  in (# State# s
s2, MutableByteArray# s -> IntVar# s
forall s. MutableByteArray# s -> IntVar# s
IntVar# MutableByteArray# s
bytes #)

{-# INLINE readIntVar# #-}
-- | Read the contents of an 'IntVar#'.
readIntVar# :: IntVar# s -> State# s -> (# State# s, Int# #)
readIntVar# :: forall s. IntVar# s -> State# s -> (# State# s, Int# #)
readIntVar# (IntVar# MutableByteArray# s
bytes) = MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
forall d.
MutableByteArray# d -> Int# -> State# d -> (# State# d, Int# #)
readIntArray# MutableByteArray# s
bytes Int#
0#

{-# INLINE writeIntVar# #-}
-- | Read the contents of an 'IntVar#'.
writeIntVar# :: IntVar# s -> Int# -> State# s -> State# s
writeIntVar# :: forall s. IntVar# s -> Int# -> State# s -> State# s
writeIntVar# (IntVar# MutableByteArray# s
bytes) Int#
n = MutableByteArray# s -> Int# -> Int# -> State# s -> State# s
forall d.
MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
writeIntArray# MutableByteArray# s
bytes Int#
0# Int#
n