histogram-fill-0.8.2.0: Data/Histogram/ST.hs
{-# LANGUAGE BangPatterns #-}
-- |
-- Module : Data.Histogram.ST
-- Copyright : Copyright (c) 2009, Alexey Khudyakov <alexey.skladnoy@gmail.com>
-- License : BSD3
-- Maintainer : Alexey Khudyakov <alexey.skladnoy@gmail.com>
-- Stability : experimental
--
-- Mutable histograms.
module Data.Histogram.ST ( -- * Mutable histograms
MHistogram
, newMHistogram
, fill
-- , fillMonoidAccum
, unsafeFreezeHist
, freezeHist
) where
import Control.Monad
import Control.Monad.Primitive
import qualified Data.Vector.Generic as G
import qualified Data.Vector.Generic.Mutable as M
import Data.Histogram.Generic
----------------------------------------------------------------
-- Mutable histograms
----------------------------------------------------------------
-- | Mutable histogram.
data MHistogram s v bin a =
MHistogram
{-# UNPACK #-} !Int -- Number of bins
!bin -- Binning
!(v s a) -- Bin contents. Underflows are stored at the
-- n'th index and overflow are in the n+1
-- | Create new mutable histogram. All bins are set to zero element as
-- passed to function.
newMHistogram :: (PrimMonad m, Bin bin, M.MVector v a) => a -> bin -> m (MHistogram (PrimState m) v bin a)
newMHistogram zero bin = do
let n = nBins bin
-- NOTE: replicate will create vector of zero length requested
-- length is negative. Thus if number of bins is negative buffer
-- will be shorter than 2. And it's assumed that there's always at
-- least 2 bin. Consequently it could lead to memory corruption.
when (n < 0) $
error "Data.Histogram.ST.newMHistogram: negative number of bins"
a <- M.replicate (n + 2) zero
return $ MHistogram n bin a
{-# INLINE newMHistogram #-}
-- | Generic fill. It could be seen as left fold with multiple
-- accumulators where accumulator is chosen by @BinValue bin@.
fill :: (PrimMonad m, M.MVector v a, Bin bin)
=> MHistogram (PrimState m) v bin a -- ^ Mutable histogram to put value to
-> BinValue bin -- ^ Value being binned
-> (a -> b -> a) -- ^ Fold function
-> b -- ^ Value being put into histogram
-> m ()
fill (MHistogram n bin arr) !x f val = do
a <- M.unsafeRead arr ix
M.unsafeWrite arr ix $! f a val
where
i = toIndex bin x
ix | i < 0 = n
| i >= n = n+1
| otherwise = i
{-# INLINE fill #-}
-- | Create immutable histogram from mutable one. This operation is
-- unsafe! Accumulator mustn't be used after that
unsafeFreezeHist :: (PrimMonad m, G.Vector v a, Bin bin)
=> MHistogram (PrimState m) (G.Mutable v) bin a
-> m (Histogram v bin a)
unsafeFreezeHist (MHistogram n bin arr) = do
u <- M.unsafeRead arr n
o <- M.unsafeRead arr (n+1)
a <- G.unsafeFreeze $ M.slice 0 n arr
return $ histogramUO bin (Just (u,o)) a
{-# INLINE unsafeFreezeHist #-}
-- | Create immutable histogram from mutable one.
freezeHist :: (PrimMonad m, G.Vector v a, Bin bin)
=> MHistogram (PrimState m) (G.Mutable v) bin a
-> m (Histogram v bin a)
freezeHist (MHistogram n bin arr) = do
u <- M.unsafeRead arr n
o <- M.unsafeRead arr (n+1)
a <- G.freeze $ M.slice 0 n arr
return $ histogramUO bin (Just (u,o)) a
{-# INLINE freezeHist #-}