packages feed

opc-xml-da-client-0.1: base/OpcXmlDaClient/Base/Vector.hs

-- |
-- General utilities for immutable vectors.
module OpcXmlDaClient.Base.Vector where

import Data.Vector.Generic
import qualified Data.Vector.Generic.Mutable as M
import qualified OpcXmlDaClient.Base.MVector as M
import OpcXmlDaClient.Base.Prelude hiding (Vector)

-- |
-- >>> fromReverseListN 3 [1,2,3] :: Data.Vector.Vector Int
-- [3,2,1]
{-# INLINE fromReverseListN #-}
fromReverseListN :: Vector v a => Int -> [a] -> v a
fromReverseListN size list =
  initialized size $ \mv -> M.writeListInReverseOrderStartingFrom mv (pred size) list

{-# INLINE initialized #-}
initialized :: Vector v a => Int -> (forall s. Mutable v s a -> ST s ()) -> v a
initialized size initialize = runST $ do
  mv <- M.unsafeNew size
  initialize mv
  unsafeFreeze mv

-- |
-- Efficiently build a vector with the @many@ pattern.
many :: (MonadPlus m, Vector v a) => m a -> m (v a)
many produce =
  manyWithIndex (const produce)

manyWithIndex :: (MonadPlus m, Vector v a) => (Int -> m a) -> m (v a)
manyWithIndex produce =
  build [] 0
  where
    build list !size =
      step <|> finish
      where
        step =
          produce size >>= \a -> build (a : list) (succ size)
        finish =
          pure (fromReverseListN size list)

manyWithIndexTerminating :: (MonadPlus m, Vector v a) => (Int -> m (Either e a)) -> m (Either e (v a))
manyWithIndexTerminating produce =
  build [] 0
  where
    build list !size =
      step <|> finish
      where
        step =
          produce size >>= \case
            Right a -> build (a : list) (succ size)
            Left a -> return (Left a)
        finish =
          pure (Right (fromReverseListN size list))