Safe Haskell | None |
---|---|

Language | Haskell2010 |

Double-buffered storage

This module provides a safer alternative to the methods of the classes
`Manifestable`

and `Manifestable2`

:

`store`

instead of`manifest`

`store2`

instead of`manifest2`

`setStore`

instead of`manifestStore`

`setStore2`

instead of`manifestStore2`

Consider the following example:

bad = do arr <- newArr 20 vec1 <- manifest arr (1...20) vec2 <- manifest arr $ map (*10) $ reverse vec1 printf "%d\n" $ sum vec2

First the vector `(1...20)`

is stored into `arr`

. Then the result is used to
compute a new vector which is also stored into `arr`

. So the storage is
updated while it is being read from, leading to unexpected results.

Using this module, we can make a small change to the program:

good = do st <- newStore 20 vec1 <- store st (1...20) vec2 <- store st $ map (*10) $ reverse vec1 printf "%d\n" $ sum vec2

Now the program works as expected; i.e. gives the same result as the normal Haskell expression

sum $ map (*10) $ reverse [1..20]

The price we have to pay for safe storage is that

allocates
twice as much memory as `newStore`

l

. However, none of the other functions in
this module allocate any memory.`newArr`

l

Note that this module does not protect against improper use of
`unsafeFreezeStore`

. A vector from a frozen `Store`

is only valid as long as
the `Store`

is not updated.

## Synopsis

- data Store a
- newStore :: (Syntax a, MonadComp m) => Data Length -> m (Store a)
- unsafeInplaceStore :: (Syntax a, MonadComp m) => Data Length -> m (Store a)
- unsafeFreezeStore :: (Syntax a, MonadComp m) => Data Length -> Store a -> m (Manifest a)
- unsafeFreezeStore2 :: (Syntax a, MonadComp m) => Data Length -> Data Length -> Store a -> m (Manifest2 a)
- setStore :: (Manifestable Run vec a, Finite vec, Syntax a) => Store a -> vec -> Run ()
- setStore2 :: (Manifestable2 Run vec a, Finite2 vec, Syntax a) => Store a -> vec -> Run ()
- store :: (Manifestable Run vec a, Finite vec, Syntax a) => Store a -> vec -> Run (Manifest a)
- store2 :: (Manifestable2 Run vec a, Finite2 vec, Syntax a) => Store a -> vec -> Run (Manifest2 a)
- loopStore :: (Integral i, PrimType i, Syntax a, Manifestable Run vec1 a, Finite vec1, Manifestable Run vec2 a, Finite vec2) => Store a -> IxRange (Data i) -> (Data i -> Manifest a -> Run vec1) -> vec2 -> Run (Manifest a)
- loopStore2 :: (Integral i, PrimType i, Syntax a, Manifestable2 Run vec1 a, Finite2 vec1, Manifestable2 Run vec2 a, Finite2 vec2) => Store a -> IxRange (Data i) -> (Data i -> Manifest2 a -> Run vec1) -> vec2 -> Run (Manifest2 a)

# Documentation

newStore :: (Syntax a, MonadComp m) => Data Length -> m (Store a) Source #

Create a new double-buffered `Store`

This operation allocates two arrays of the given length.

unsafeInplaceStore :: (Syntax a, MonadComp m) => Data Length -> m (Store a) Source #

Create a new single-buffered `Store`

Using `unsafeInplaceStore`

instead of `newStore`

allows double-buffered
algorithms to run inplace.

store :: (Manifestable Run vec a, Finite vec, Syntax a) => Store a -> vec -> Run (Manifest a) Source #

store2 :: (Manifestable2 Run vec a, Finite2 vec, Syntax a) => Store a -> vec -> Run (Manifest2 a) Source #