    module VectorBuilder.Core.Builder where

    import qualified Data.Vector.Generic as B
    import qualified VectorBuilder.Core.Update as A
    import VectorBuilder.Prelude hiding (concat, empty)

    -- |
    -- An abstraction over the size of a vector for the process of its construction.
    --
    -- It postpones the actual construction of a vector until the execution of the builder.
    data Builder element
      = Builder !Int !(A.Update element)

    -- |
    -- Gets the size of a Builder.
    {-# INLINE size #-}
    size :: Builder element -> Int
    size :: forall element. Builder element -> Int
    size (Builder Int
    s Update element
    _) = Int
    s

    -- * Initialisation

    -- |
    -- Empty builder.
    {-# INLINE empty #-}
    empty :: Builder element
    empty :: forall element. Builder element
    empty =
      Int -> Update element -> Builder element
    forall element. Int -> Update element -> Builder element
    Builder Int
    0 Update element
    forall element. Update element
    A.empty

    -- |
    -- Builder of a single element.
    {-# INLINE singleton #-}
    singleton :: element -> Builder element
    singleton :: forall element. element -> Builder element
    singleton element
    element =
      Int -> Update element -> Builder element
    forall element. Int -> Update element -> Builder element
    Builder Int
    1 (element -> Update element
    forall element. element -> Update element
    A.write element
    element)

    -- |
    -- Builder from an immutable vector of elements.
    --
    -- Supports all kinds of vectors: boxed, unboxed, primitive, storable.
    {-# INLINE vector #-}
    vector :: (B.Vector vector element) => vector element -> Builder element
    vector :: forall (vector :: * -> *) element.
    Vector vector element =>
    vector element -> Builder element
    vector vector element
    vector =
      Int -> Update element -> Builder element
    forall element. Int -> Update element -> Builder element
    Builder (vector element -> Int
    forall (v :: * -> *) a. Vector v a => v a -> Int
    B.length vector element
    vector) (vector element -> Update element
    forall (vector :: * -> *) element.
    Vector vector element =>
    vector element -> Update element
    A.writeMany vector element
    vector)

    {-# INLINE foldable #-}
    foldable :: (Foldable foldable) => foldable element -> Builder element
    foldable :: forall (foldable :: * -> *) element.
    Foldable foldable =>
    foldable element -> Builder element
    foldable foldable element
    foldable =
      Int -> Update element -> Builder element
    forall element. Int -> Update element -> Builder element
    Builder (foldable element -> Int
    forall a. foldable a -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length foldable element
    foldable) (foldable element -> Update element
    forall (foldable :: * -> *) element.
    Foldable foldable =>
    foldable element -> Update element
    A.writeFoldable foldable element
    foldable)

    -- * Updates

    {-# INLINE snoc #-}
    snoc :: element -> Builder element -> Builder element
    snoc :: forall element. element -> Builder element -> Builder element
    snoc element
    element (Builder Int
    size Update element
    update) =
      Int -> Update element -> Builder element
    forall element. Int -> Update element -> Builder element
    Builder (Int -> Int
    forall a. Enum a => a -> a
    succ Int
    size) (Int -> Update element -> Update element -> Update element
    forall element.
    Int -> Update element -> Update element -> Update element
    A.prepend Int
    size Update element
    update (element -> Update element
    forall element. element -> Update element
    A.write element
    element))

    {-# INLINE cons #-}
    cons :: element -> Builder element -> Builder element
    cons :: forall element. element -> Builder element -> Builder element
    cons element
    element (Builder Int
    size Update element
    update) =
      Int -> Update element -> Builder element
    forall element. Int -> Update element -> Builder element
    Builder (Int -> Int
    forall a. Enum a => a -> a
    succ Int
    size) (Int -> Update element -> Update element -> Update element
    forall element.
    Int -> Update element -> Update element -> Update element
    A.prepend Int
    1 (element -> Update element
    forall element. element -> Update element
    A.write element
    element) Update element
    update)

    {-# INLINE prepend #-}
    prepend :: Builder element -> Builder element -> Builder element
    prepend :: forall element.
    Builder element -> Builder element -> Builder element
    prepend (Builder Int
    leftSize Update element
    leftUpdate) (Builder Int
    rightSize Update element
    rightUpdate) =
      Int -> Update element -> Builder element
    forall element. Int -> Update element -> Builder element
    Builder (Int
    leftSize Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    rightSize) (Int -> Update element -> Update element -> Update element
    forall element.
    Int -> Update element -> Update element -> Update element
    A.prepend Int
    leftSize Update element
    leftUpdate Update element
    rightUpdate)

    {-# INLINE append #-}
    append :: Builder element -> Builder element -> Builder element
    append :: forall element.
    Builder element -> Builder element -> Builder element
    append =
      (Builder element -> Builder element -> Builder element)
    -> Builder element -> Builder element -> Builder element
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Builder element -> Builder element -> Builder element
    forall element.
    Builder element -> Builder element -> Builder element
    prepend

    {-# INLINE concat #-}
    concat :: (Foldable foldable) => foldable (Builder element) -> Builder element
    concat :: forall (foldable :: * -> *) element.
    Foldable foldable =>
    foldable (Builder element) -> Builder element
    concat foldable (Builder element)
    builders =
      Int -> Update element -> Builder element
    forall element. Int -> Update element -> Builder element
    Builder
        ( let step :: Int -> Builder element -> Int
    step Int
    size (Builder Int
    builderSize Update element
    _) = Int
    size Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    builderSize
           in (Int -> Builder element -> Int)
    -> Int -> foldable (Builder element) -> Int
    forall b a. (b -> a -> b) -> b -> foldable a -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' Int -> Builder element -> Int
    forall {element}. Int -> Builder element -> Int
    step Int
    0 foldable (Builder element)
    builders
        )
        ( (forall s (vector :: * -> * -> *).
     MVector vector element =>
     vector s element -> Int -> ST s ())
    -> Update element
    forall element.
    (forall s (vector :: * -> * -> *).
     MVector vector element =>
     vector s element -> Int -> ST s ())
    -> Update element
    A.Update
            ( \vector s element
    mVector Int
    offset ->
                (Int -> Builder element -> ST s Int)
    -> Int -> foldable (Builder element) -> ST s ()
    forall (t :: * -> *) (m :: * -> *) b a.
    (Foldable t, Monad m) =>
    (b -> a -> m b) -> b -> t a -> m ()
    foldM_
                  ( \Int
    index (Builder Int
    size (A.Update forall s (vector :: * -> * -> *).
    MVector vector element =>
    vector s element -> Int -> ST s ()
    st)) ->
                      vector s element -> Int -> ST s ()
    forall s (vector :: * -> * -> *).
    MVector vector element =>
    vector s element -> Int -> ST s ()
    st vector s element
    mVector Int
    index ST s () -> Int -> ST s Int
    forall (f :: * -> *) a b. Functor f => f a -> b -> f b
    $> Int
    index Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    size
                  )
                  Int
    offset
                  foldable (Builder element)
    builders
            )
        )

    -- * Instances

    -- |
    -- Provides support for /O(1)/ concatenation.
    instance Semigroup (Builder element) where
      {-# INLINE (<>) #-}
      <> :: Builder element -> Builder element -> Builder element
    (<>) =
        Builder element -> Builder element -> Builder element
    forall element.
    Builder element -> Builder element -> Builder element
    prepend
      sconcat :: NonEmpty (Builder element) -> Builder element
    sconcat =
        NonEmpty (Builder element) -> Builder element
    forall (foldable :: * -> *) element.
    Foldable foldable =>
    foldable (Builder element) -> Builder element
    concat

    -- |
    -- Provides support for /O(1)/ concatenation.
    instance Monoid (Builder element) where
      {-# INLINE mempty #-}
      mempty :: Builder element
    mempty =
        Builder element
    forall element. Builder element
    empty
      {-# INLINE mappend #-}
      mappend :: Builder element -> Builder element -> Builder element
    mappend =
        Builder element -> Builder element -> Builder element
    forall a. Semigroup a => a -> a -> a
    (<>)
      {-# INLINE mconcat #-}
      mconcat :: [Builder element] -> Builder element
    mconcat =
        [Builder element] -> Builder element
    forall (foldable :: * -> *) element.
    Foldable foldable =>
    foldable (Builder element) -> Builder element
    concat