content: module Control.Concurrent.Chan.Unagi.Constants 
      where
  
  -- Constants for boxed and unboxed unagi.
  
  import Data.Bits
  import Control.Exception(assert)
  
  divMod_sEGMENT_LENGTH :: Int -> (Int,Int)
  {-# INLINE divMod_sEGMENT_LENGTH #-}
  divMod_sEGMENT_LENGTH n = let d = n `unsafeShiftR` lOG_SEGMENT_LENGTH
                                m = n .&. sEGMENT_LENGTH_MN_1
                             in d `seq` m `seq` (d,m)
  
  -- Nexttant for now: back-of-envelope considerations:
  --   - making most of constant factor for cloning array of *any* size
  --   - make most of overheads of moving to the next segment, etc.
  --   - provide enough runway for creating next segment when 32 simultaneous writers 
  --   - the larger this the larger one-time cost for the lucky writer
  --   - as arrays collect in heap, performance might suffer, so bigger arrays
  --     give us a constant factor edge there. see:
  --       http://stackoverflow.com/q/23462004/176841
  --
  sEGMENT_LENGTH :: Int
  {-# INLINE sEGMENT_LENGTH #-}
  sEGMENT_LENGTH = 1024 -- NOTE: THIS MUST REMAIN A POWER OF 2!
  
  -- Number of reads on which to spin for new segment creation.
  -- Back-of-envelope (time_to_create_new_segment / time_for_read_IOref) + margin.
  -- See usage site.
  --
  -- NOTE: this was calculated for boxed Unagi, but it probably doesn't make a
  -- measurable difference that we use it for Unagi.Unboxed too.
  nEW_SEGMENT_WAIT :: Int
  nEW_SEGMENT_WAIT = round (((14.6::Float) + 0.3*fromIntegral sEGMENT_LENGTH) / 3.7) + 10
  
  lOG_SEGMENT_LENGTH :: Int
  lOG_SEGMENT_LENGTH = 
      let x = 10  -- ...pre-computed from...
       in assert (x == (round $ logBase (2::Float) $ fromIntegral sEGMENT_LENGTH))
           x
  
  sEGMENT_LENGTH_MN_1 :: Int
  sEGMENT_LENGTH_MN_1 = sEGMENT_LENGTH - 1
  