{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DerivingVia #-}
{-# OPTIONS_HADDOCK hide #-}
-- |
-- Module      : Data.Vector.Unboxed.Base
-- Copyright   : (c) Roman Leshchinskiy 2009-2010
--                   Alexey Kuleshevich 2020-2022
--                   Aleksey Khudyakov 2020-2022
--                   Andrew Lelechenko 2020-2022
-- License     : BSD-style
--
-- Maintainer  : Haskell Libraries Team <libraries@haskell.org>
-- Stability   : experimental
-- Portability : non-portable
--
-- Adaptive unboxed vectors: basic implementation.

module Data.Vector.Unboxed.Base (
  MVector(..), IOVector, STVector, Vector(..), Unbox,
  UnboxViaPrim(..), UnboxViaStorable(..), As(..), IsoUnbox(..),
  DoNotUnboxLazy(..), DoNotUnboxNormalForm(..), DoNotUnboxStrict(..)
) where

import qualified Data.Vector.Generic         as G
import qualified Data.Vector.Generic.Mutable as M
import qualified Data.Vector                 as B
import qualified Data.Vector.Strict          as S
import qualified Data.Vector.Storable        as St

import qualified Data.Vector.Primitive as P

import Control.Applicative (Const(..))

import Control.DeepSeq ( NFData(rnf), NFData1(liftRnf), force)

import Control.Monad.Primitive
import Control.Monad ( liftM )

import Data.Functor.Identity
import Data.Functor.Compose
import Data.Word ( Word8, Word16, Word32, Word64 )
import Data.Int  ( Int8, Int16, Int32, Int64 )
import Data.Complex
import Data.Monoid (Dual(..),Sum(..),Product(..),All(..),Any(..))
import Data.Monoid (Alt(..))
import Data.Semigroup (Min(..),Max(..),First(..),Last(..),WrappedMonoid(..),Arg(..))
import Data.Data     ( Data(..) )
import GHC.Exts      ( Down(..) )
import GHC.Generics
import Data.Coerce
import Data.Kind     (Type)

#include "vector.h"

data family MVector s a
data family Vector    a

type IOVector = MVector RealWorld
type STVector s = MVector s

type instance G.Mutable Vector = MVector

class (G.Vector Vector a, M.MVector MVector a) => Unbox a

instance NFData (Vector a) where rnf !_ = ()
instance NFData (MVector s a) where rnf !_ = ()

-- | @since 0.12.1.0
instance NFData1 Vector where
  liftRnf _ !_ = ()
-- | @since 0.12.1.0
instance NFData1 (MVector s) where
  liftRnf _ !_ = ()


instance (Data a, Unbox a) => Data (Vector a) where
  gfoldl       = G.gfoldl
  toConstr _   = G.mkVecConstr "Data.Vector.Unboxed.Vector"
  gunfold      = G.gunfold
  dataTypeOf _ = G.mkVecType "Data.Vector.Unboxed.Vector"
  dataCast1    = G.dataCast

-- ----
-- Unit
-- ----

newtype instance MVector s () = MV_Unit Int
newtype instance Vector    () = V_Unit Int

instance Unbox ()

instance M.MVector MVector () where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}

  basicLength (MV_Unit n) = n

  basicUnsafeSlice _ m (MV_Unit _) = MV_Unit m

  basicOverlaps _ _ = False

  basicUnsafeNew n = return (MV_Unit n)

  -- Nothing to initialize
  basicInitialize _ = return ()

  basicUnsafeRead (MV_Unit _) _ = return ()

  basicUnsafeWrite (MV_Unit _) _ () = return ()

  basicClear _ = return ()

  basicSet (MV_Unit _) () = return ()

  basicUnsafeCopy (MV_Unit _) (MV_Unit _) = return ()

  basicUnsafeGrow (MV_Unit n) m = return $ MV_Unit (n+m)

instance G.Vector Vector () where
  {-# INLINE basicUnsafeFreeze #-}
  basicUnsafeFreeze (MV_Unit n) = return $ V_Unit n

  {-# INLINE basicUnsafeThaw #-}
  basicUnsafeThaw (V_Unit n) = return $ MV_Unit n

  {-# INLINE basicLength #-}
  basicLength (V_Unit n) = n

  {-# INLINE basicUnsafeSlice #-}
  basicUnsafeSlice _ m (V_Unit _) = V_Unit m

  {-# INLINE basicUnsafeIndexM #-}
  basicUnsafeIndexM (V_Unit _) _ = return ()

  {-# INLINE basicUnsafeCopy #-}
  basicUnsafeCopy (MV_Unit _) (V_Unit _) = return ()

  {-# INLINE elemseq #-}
  elemseq _ = seq


-- ---------------
-- Primitive types
-- ---------------

-- | Newtype wrapper which allows to derive unboxed vector in term of
-- primitive vectors using @DerivingVia@ mechanism. This is mostly
-- used as illustration of use of @DerivingVia@ for vector, see examples below.
--
-- First is rather straightforward: we define newtype and use GND to
-- derive 'P.Prim' instance. Newtype instances should be defined
-- manually. Then we use deriving via to define necessary instances.
--
-- >>> :set -XTypeFamilies -XStandaloneDeriving -XDerivingVia -XMultiParamTypeClasses
-- >>> -- Needed to derive Prim
-- >>> :set -XGeneralizedNewtypeDeriving -XDataKinds -XUnboxedTuples -XPolyKinds
-- >>>
-- >>> import qualified Data.Vector.Generic         as VG
-- >>> import qualified Data.Vector.Generic.Mutable as VGM
-- >>> import qualified Data.Vector.Primitive       as VP
-- >>> import qualified Data.Vector.Unboxed         as VU
-- >>>
-- >>> newtype Foo = Foo Int deriving VP.Prim
-- >>>
-- >>> newtype instance VU.MVector s Foo = MV_Foo (VP.MVector s Foo)
-- >>> newtype instance VU.Vector    Foo = V_Foo  (VP.Vector    Foo)
-- >>> deriving via (VU.UnboxViaPrim Foo) instance VGM.MVector VU.MVector Foo
-- >>> deriving via (VU.UnboxViaPrim Foo) instance VG.Vector   VU.Vector  Foo
-- >>> instance VU.Unbox Foo
--
-- Second example is essentially same but with a twist. Instead of
-- using 'P.Prim' instance of data type, we use underlying instance of 'Int':
--
-- >>> :set -XTypeFamilies -XStandaloneDeriving -XDerivingVia -XMultiParamTypeClasses
-- >>>
-- >>> import qualified Data.Vector.Generic         as VG
-- >>> import qualified Data.Vector.Generic.Mutable as VGM
-- >>> import qualified Data.Vector.Primitive       as VP
-- >>> import qualified Data.Vector.Unboxed         as VU
-- >>>
-- >>> newtype Foo = Foo Int
-- >>>
-- >>> newtype instance VU.MVector s Foo = MV_Foo (VP.MVector s Int)
-- >>> newtype instance VU.Vector    Foo = V_Foo  (VP.Vector    Int)
-- >>> deriving via (VU.UnboxViaPrim Int) instance VGM.MVector VU.MVector Foo
-- >>> deriving via (VU.UnboxViaPrim Int) instance VG.Vector   VU.Vector  Foo
-- >>> instance VU.Unbox Foo
--
-- @since 0.13.0.0
newtype UnboxViaPrim a = UnboxViaPrim a

newtype instance MVector s (UnboxViaPrim a) = MV_UnboxViaPrim (P.MVector s a)
newtype instance Vector    (UnboxViaPrim a) = V_UnboxViaPrim (P.Vector a)

instance P.Prim a => M.MVector MVector (UnboxViaPrim a) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}
  basicLength          = coerce $ M.basicLength          @P.MVector @a
  basicUnsafeSlice     = coerce $ M.basicUnsafeSlice     @P.MVector @a
  basicOverlaps        = coerce $ M.basicOverlaps        @P.MVector @a
  basicUnsafeNew       = coerce $ M.basicUnsafeNew       @P.MVector @a
  basicInitialize      = coerce $ M.basicInitialize      @P.MVector @a
  basicUnsafeReplicate = coerce $ M.basicUnsafeReplicate @P.MVector @a
  basicUnsafeRead      = coerce $ M.basicUnsafeRead      @P.MVector @a
  basicUnsafeWrite     = coerce $ M.basicUnsafeWrite     @P.MVector @a
  basicClear           = coerce $ M.basicClear           @P.MVector @a
  basicSet             = coerce $ M.basicSet             @P.MVector @a
  basicUnsafeCopy      = coerce $ M.basicUnsafeCopy      @P.MVector @a
  basicUnsafeMove      = coerce $ M.basicUnsafeMove      @P.MVector @a
  basicUnsafeGrow      = coerce $ M.basicUnsafeGrow      @P.MVector @a

instance P.Prim a => G.Vector Vector (UnboxViaPrim a) where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeFreeze = coerce $ G.basicUnsafeFreeze @P.Vector @a
  basicUnsafeThaw   = coerce $ G.basicUnsafeThaw   @P.Vector @a
  basicLength       = coerce $ G.basicLength       @P.Vector @a
  basicUnsafeSlice  = coerce $ G.basicUnsafeSlice  @P.Vector @a
  basicUnsafeIndexM = coerce $ G.basicUnsafeIndexM @P.Vector @a
  basicUnsafeCopy   = coerce $ G.basicUnsafeCopy   @P.Vector @a
  elemseq _ = seq

-- | Isomorphism between type @a@ and its representation in unboxed
-- vector @b@. Default instance coerces between generic
-- representations of @a@ and @b@ which means they have same shape and
-- corresponding fields could be coerced to each other. Note that this
-- means it's possible to have fields that have different types:
--
-- >>> :set -XMultiParamTypeClasses -XDeriveGeneric -XFlexibleInstances
-- >>> import GHC.Generics (Generic)
-- >>> import Data.Monoid
-- >>> import qualified Data.Vector.Unboxed as VU
-- >>> :{
-- data Foo a = Foo Int a
--   deriving (Show,Generic)
-- instance VU.IsoUnbox (Foo a) (Int, a)
-- instance VU.IsoUnbox (Foo a) (Sum Int, Product a)
-- :}
--
-- @since 0.13.0.0
class IsoUnbox a b where
  -- | Convert value into it representation in unboxed vector.
  toURepr   :: a -> b
  default toURepr :: (Generic a, Generic b, Coercible (Rep a ()) (Rep b ())) => a -> b
  toURepr = to . idU . coerce . idU . from
  -- | Convert value representation in unboxed vector back to value.
  fromURepr :: b -> a
  default fromURepr :: (Generic a, Generic b, Coercible (Rep b ()) (Rep a ())) => b -> a
  fromURepr = to . idU . coerce . idU . from

idU :: f () -> f ()
idU = id


-- | Newtype which allows to derive unbox instances for type @a@ which
-- uses @b@ as underlying representation (usually tuple). Type @a@ and
-- its representation @b@ are connected by type class
-- 'IsoUnbox'. Here's example which uses explicit 'IsoUnbox' instance:
--
--
-- >>> :set -XTypeFamilies -XStandaloneDeriving -XDerivingVia
-- >>> :set -XMultiParamTypeClasses -XTypeOperators -XFlexibleInstances
-- >>> import qualified Data.Vector.Unboxed         as VU
-- >>> import qualified Data.Vector.Unboxed.Mutable as MVU
-- >>> import qualified Data.Vector.Generic         as VG
-- >>> import qualified Data.Vector.Generic.Mutable as VGM
-- >>> :{
-- data Foo a = Foo Int a
--   deriving Show
-- instance VU.IsoUnbox (Foo a) (Int,a) where
--   toURepr (Foo i a) = (i,a)
--   fromURepr (i,a) = Foo i a
--   {-# INLINE toURepr #-}
--   {-# INLINE fromURepr #-}
-- newtype instance VU.MVector s (Foo a) = MV_Foo (VU.MVector s (Int, a))
-- newtype instance VU.Vector    (Foo a) = V_Foo  (VU.Vector    (Int, a))
-- deriving via (Foo a `VU.As` (Int, a)) instance VU.Unbox a => VGM.MVector MVU.MVector (Foo a)
-- deriving via (Foo a `VU.As` (Int, a)) instance VU.Unbox a => VG.Vector   VU.Vector   (Foo a)
-- instance VU.Unbox a => VU.Unbox (Foo a)
-- :}
--
--
-- It's also possible to use generic-based instance for 'IsoUnbox'
-- which should work for all product types.
--
-- >>> :set -XMultiParamTypeClasses -XTypeOperators -XFlexibleInstances -XDeriveGeneric
-- >>> :set -XDerivingVia
-- >>> import qualified Data.Vector.Unboxed         as VU
-- >>> import qualified Data.Vector.Generic         as VG
-- >>> import qualified Data.Vector.Generic.Mutable as VGM
-- >>> :{
-- data Bar a = Bar Int a
--   deriving (Show,Generic)
-- instance VU.IsoUnbox (Bar a) (Int,a) where
-- newtype instance VU.MVector s (Bar a) = MV_Bar (VU.MVector s (Int, a))
-- newtype instance VU.Vector    (Bar a) = V_Bar  (VU.Vector    (Int, a))
-- deriving via (Bar a `VU.As` (Int, a)) instance VU.Unbox a => VGM.MVector VU.MVector (Bar a)
-- deriving via (Bar a `VU.As` (Int, a)) instance VU.Unbox a => VG.Vector  VU.Vector  (Bar a)
-- instance VU.Unbox a => VU.Unbox (Bar a)
-- :}
--
-- @since 0.13.0.0
newtype As (a :: Type) (b :: Type) = As a

newtype instance MVector s (As a b) = MV_UnboxAs (MVector s b)
newtype instance Vector    (As a b) = V_UnboxAs  (Vector b)

instance (IsoUnbox a b, Unbox b) => M.MVector MVector (As a b) where
  -- Methods that just use underlying vector
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeMove #-}
  {-# INLINE basicUnsafeGrow #-}
  {-# INLINE basicClear #-}
  basicLength      = coerce $ M.basicLength      @MVector @b
  basicUnsafeSlice = coerce $ M.basicUnsafeSlice @MVector @b
  basicOverlaps    = coerce $ M.basicOverlaps    @MVector @b
  basicUnsafeNew   = coerce $ M.basicUnsafeNew   @MVector @b
  basicInitialize  = coerce $ M.basicInitialize  @MVector @b
  basicUnsafeCopy  = coerce $ M.basicUnsafeCopy  @MVector @b
  basicUnsafeMove  = coerce $ M.basicUnsafeMove  @MVector @b
  basicUnsafeGrow  = coerce $ M.basicUnsafeGrow  @MVector @b
  basicClear       = coerce $ M.basicClear       @MVector @b
  -- Conversion to/from underlying representation
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicSet #-}
  basicUnsafeReplicate n (As x) = MV_UnboxAs <$> M.basicUnsafeReplicate n (toURepr x)
  basicUnsafeRead (MV_UnboxAs v) i = As . fromURepr <$> M.basicUnsafeRead v i
  basicUnsafeWrite (MV_UnboxAs v) i (As x) = M.basicUnsafeWrite v i (toURepr x)
  basicSet (MV_UnboxAs v) (As x) = M.basicSet v (toURepr x)

instance (IsoUnbox a b, Unbox b) => G.Vector Vector (As a b) where
  -- Method that just use underlying vector
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE elemseq #-}
  basicUnsafeFreeze = coerce $ G.basicUnsafeFreeze @Vector @b
  basicUnsafeThaw   = coerce $ G.basicUnsafeThaw   @Vector @b
  basicLength       = coerce $ G.basicLength       @Vector @b
  basicUnsafeSlice  = coerce $ G.basicUnsafeSlice  @Vector @b
  basicUnsafeCopy   = coerce $ G.basicUnsafeCopy   @Vector @b
  elemseq _         = seq
  -- Conversion to/from underlying representation
  {-# INLINE basicUnsafeIndexM #-}
  basicUnsafeIndexM (V_UnboxAs v) i = As . fromURepr <$> G.basicUnsafeIndexM v i


newtype instance MVector s Int = MV_Int (P.MVector s Int)
newtype instance Vector    Int = V_Int  (P.Vector    Int)
deriving via (UnboxViaPrim Int) instance M.MVector MVector Int
deriving via (UnboxViaPrim Int) instance G.Vector  Vector  Int
instance Unbox Int

newtype instance MVector s Int8 = MV_Int8 (P.MVector s Int8)
newtype instance Vector    Int8 = V_Int8  (P.Vector    Int8)
deriving via (UnboxViaPrim Int8) instance M.MVector MVector Int8
deriving via (UnboxViaPrim Int8) instance G.Vector  Vector  Int8
instance Unbox Int8

newtype instance MVector s Int16 = MV_Int16 (P.MVector s Int16)
newtype instance Vector    Int16 = V_Int16  (P.Vector    Int16)
deriving via (UnboxViaPrim Int16) instance M.MVector MVector Int16
deriving via (UnboxViaPrim Int16) instance G.Vector  Vector  Int16
instance Unbox Int16

newtype instance MVector s Int32 = MV_Int32 (P.MVector s Int32)
newtype instance Vector    Int32 = V_Int32  (P.Vector    Int32)
deriving via (UnboxViaPrim Int32) instance M.MVector MVector Int32
deriving via (UnboxViaPrim Int32) instance G.Vector  Vector  Int32
instance Unbox Int32

newtype instance MVector s Int64 = MV_Int64 (P.MVector s Int64)
newtype instance Vector    Int64 = V_Int64  (P.Vector    Int64)
deriving via (UnboxViaPrim Int64) instance M.MVector MVector Int64
deriving via (UnboxViaPrim Int64) instance G.Vector  Vector  Int64
instance Unbox Int64


newtype instance MVector s Word = MV_Word (P.MVector s Word)
newtype instance Vector    Word = V_Word  (P.Vector    Word)
deriving via (UnboxViaPrim Word) instance M.MVector MVector Word
deriving via (UnboxViaPrim Word) instance G.Vector  Vector  Word
instance Unbox Word

newtype instance MVector s Word8 = MV_Word8 (P.MVector s Word8)
newtype instance Vector    Word8 = V_Word8  (P.Vector    Word8)
deriving via (UnboxViaPrim Word8) instance M.MVector MVector Word8
deriving via (UnboxViaPrim Word8) instance G.Vector  Vector  Word8
instance Unbox Word8

newtype instance MVector s Word16 = MV_Word16 (P.MVector s Word16)
newtype instance Vector    Word16 = V_Word16  (P.Vector    Word16)
deriving via (UnboxViaPrim Word16) instance M.MVector MVector Word16
deriving via (UnboxViaPrim Word16) instance G.Vector  Vector  Word16
instance Unbox Word16

newtype instance MVector s Word32 = MV_Word32 (P.MVector s Word32)
newtype instance Vector    Word32 = V_Word32  (P.Vector    Word32)
deriving via (UnboxViaPrim Word32) instance M.MVector MVector Word32
deriving via (UnboxViaPrim Word32) instance G.Vector  Vector  Word32
instance Unbox Word32

newtype instance MVector s Word64 = MV_Word64 (P.MVector s Word64)
newtype instance Vector    Word64 = V_Word64  (P.Vector    Word64)
deriving via (UnboxViaPrim Word64) instance M.MVector MVector Word64
deriving via (UnboxViaPrim Word64) instance G.Vector  Vector  Word64
instance Unbox Word64


newtype instance MVector s Float = MV_Float (P.MVector s Float)
newtype instance Vector    Float = V_Float  (P.Vector    Float)
deriving via (UnboxViaPrim Float) instance M.MVector MVector Float
deriving via (UnboxViaPrim Float) instance G.Vector  Vector  Float
instance Unbox Float

newtype instance MVector s Double = MV_Double (P.MVector s Double)
newtype instance Vector    Double = V_Double  (P.Vector    Double)
deriving via (UnboxViaPrim Double) instance M.MVector MVector Double
deriving via (UnboxViaPrim Double) instance G.Vector  Vector  Double
instance Unbox Double

newtype instance MVector s Char = MV_Char (P.MVector s Char)
newtype instance Vector    Char = V_Char  (P.Vector    Char)
deriving via (UnboxViaPrim Char) instance M.MVector MVector Char
deriving via (UnboxViaPrim Char) instance G.Vector  Vector  Char
instance Unbox Char

-- ----
-- Bool
-- ----

fromBool :: Bool -> Word8
{-# INLINE fromBool #-}
fromBool True = 1
fromBool False = 0

toBool :: Word8 -> Bool
{-# INLINE toBool #-}
toBool 0 = False
toBool _ = True

newtype instance MVector s Bool = MV_Bool (P.MVector s Word8)
newtype instance Vector    Bool = V_Bool  (P.Vector    Word8)

instance Unbox Bool

instance M.MVector MVector Bool where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}
  basicLength (MV_Bool v) = M.basicLength v
  basicUnsafeSlice i n (MV_Bool v) = MV_Bool $ M.basicUnsafeSlice i n v
  basicOverlaps (MV_Bool v1) (MV_Bool v2) = M.basicOverlaps v1 v2
  basicUnsafeNew n = MV_Bool `liftM` M.basicUnsafeNew n
  basicInitialize (MV_Bool v) = M.basicInitialize v
  basicUnsafeReplicate n x = MV_Bool `liftM` M.basicUnsafeReplicate n (fromBool x)
  basicUnsafeRead (MV_Bool v) i = toBool `liftM` M.basicUnsafeRead v i
  basicUnsafeWrite (MV_Bool v) i x = M.basicUnsafeWrite v i (fromBool x)
  basicClear (MV_Bool v) = M.basicClear v
  basicSet (MV_Bool v) x = M.basicSet v (fromBool x)
  basicUnsafeCopy (MV_Bool v1) (MV_Bool v2) = M.basicUnsafeCopy v1 v2
  basicUnsafeMove (MV_Bool v1) (MV_Bool v2) = M.basicUnsafeMove v1 v2
  basicUnsafeGrow (MV_Bool v) n = MV_Bool `liftM` M.basicUnsafeGrow v n

instance G.Vector Vector Bool where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeFreeze (MV_Bool v) = V_Bool `liftM` G.basicUnsafeFreeze v
  basicUnsafeThaw (V_Bool v) = MV_Bool `liftM` G.basicUnsafeThaw v
  basicLength (V_Bool v) = G.basicLength v
  basicUnsafeSlice i n (V_Bool v) = V_Bool $ G.basicUnsafeSlice i n v
  basicUnsafeIndexM (V_Bool v) i = toBool `liftM` G.basicUnsafeIndexM v i
  basicUnsafeCopy (MV_Bool mv) (V_Bool v) = G.basicUnsafeCopy mv v
  elemseq _ = seq

-- -------
-- Complex
-- -------

newtype instance MVector s (Complex a) = MV_Complex (MVector s (a,a))
newtype instance Vector    (Complex a) = V_Complex  (Vector    (a,a))

instance (Unbox a) => Unbox (Complex a)

instance (Unbox a) => M.MVector MVector (Complex a) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeMove #-}
  {-# INLINE basicUnsafeGrow #-}
  basicLength      = coerce $ M.basicLength      @MVector @(a,a)
  basicUnsafeSlice = coerce $ M.basicUnsafeSlice @MVector @(a,a)
  basicOverlaps    = coerce $ M.basicOverlaps    @MVector @(a,a)
  basicUnsafeNew   = coerce $ M.basicUnsafeNew   @MVector @(a,a)
  basicInitialize  = coerce $ M.basicInitialize  @MVector @(a,a)
  basicUnsafeCopy  = coerce $ M.basicUnsafeCopy  @MVector @(a,a)
  basicUnsafeMove  = coerce $ M.basicUnsafeMove  @MVector @(a,a)
  basicUnsafeGrow  = coerce $ M.basicUnsafeGrow  @MVector @(a,a)
  basicClear       = coerce $ M.basicClear       @MVector @(a,a)
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicSet #-}
  basicUnsafeReplicate n (x :+ y) = MV_Complex <$> M.basicUnsafeReplicate n (x,y)
  basicUnsafeRead (MV_Complex v) i = uncurry (:+) <$> M.basicUnsafeRead v i
  basicUnsafeWrite (MV_Complex v) i (x :+ y) = M.basicUnsafeWrite v i (x,y)
  basicSet (MV_Complex v) (x :+ y) = M.basicSet v (x,y)

instance (Unbox a) => G.Vector Vector (Complex a) where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeCopy #-}
  basicUnsafeFreeze = coerce $ G.basicUnsafeFreeze @Vector @(a,a)
  basicUnsafeThaw   = coerce $ G.basicUnsafeThaw   @Vector @(a,a)
  basicLength       = coerce $ G.basicLength       @Vector @(a,a)
  basicUnsafeSlice  = coerce $ G.basicUnsafeSlice  @Vector @(a,a)
  basicUnsafeCopy   = coerce $ G.basicUnsafeCopy   @Vector @(a,a)
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeIndexM (V_Complex v) i
                = uncurry (:+) <$> G.basicUnsafeIndexM v i
  elemseq _ (x :+ y) z = G.elemseq (undefined :: Vector a) x
                       $ G.elemseq (undefined :: Vector a) y z

-- -------
-- Identity
-- -------

newtype instance MVector s (Identity a) = MV_Identity (MVector s a)
newtype instance Vector    (Identity a) = V_Identity  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (Identity a)
deriving instance Unbox a => M.MVector MVector (Identity a)
instance Unbox a => Unbox (Identity a)

newtype instance MVector s (Down a) = MV_Down (MVector s a)
newtype instance Vector    (Down a) = V_Down  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (Down a)
deriving instance Unbox a => M.MVector MVector (Down a)
instance Unbox a => Unbox (Down a)

newtype instance MVector s (Dual a) = MV_Dual (MVector s a)
newtype instance Vector    (Dual a) = V_Dual  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (Dual a)
deriving instance Unbox a => M.MVector MVector (Dual a)
instance Unbox a => Unbox (Dual a)

newtype instance MVector s (Sum a) = MV_Sum (MVector s a)
newtype instance Vector    (Sum a) = V_Sum  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (Sum a)
deriving instance Unbox a => M.MVector MVector (Sum a)
instance Unbox a => Unbox (Sum a)

newtype instance MVector s (Product a) = MV_Product (MVector s a)
newtype instance Vector    (Product a) = V_Product  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (Product a)
deriving instance Unbox a => M.MVector MVector (Product a)
instance Unbox a => Unbox (Product a)

-- --------------
-- Data.Semigroup
-- --------------


newtype instance MVector s (Min a) = MV_Min (MVector s a)
newtype instance Vector    (Min a) = V_Min  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (Min a)
deriving instance Unbox a => M.MVector MVector (Min a)
instance Unbox a => Unbox (Min a)

newtype instance MVector s (Max a) = MV_Max (MVector s a)
newtype instance Vector    (Max a) = V_Max  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (Max a)
deriving instance Unbox a => M.MVector MVector (Max a)
instance Unbox a => Unbox (Max a)

newtype instance MVector s (First a) = MV_First (MVector s a)
newtype instance Vector    (First a) = V_First  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (First a)
deriving instance Unbox a => M.MVector MVector (First a)
instance Unbox a => Unbox (First a)

newtype instance MVector s (Last a) = MV_Last (MVector s a)
newtype instance Vector    (Last a) = V_Last  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (Last a)
deriving instance Unbox a => M.MVector MVector (Last a)
instance Unbox a => Unbox (Last a)

newtype instance MVector s (WrappedMonoid a) = MV_WrappedMonoid (MVector s a)
newtype instance Vector    (WrappedMonoid a) = V_WrappedMonoid  (Vector a)
deriving instance Unbox a => G.Vector  Vector  (WrappedMonoid a)
deriving instance Unbox a => M.MVector MVector (WrappedMonoid a)
instance Unbox a => Unbox (WrappedMonoid a)

-- ------------------
-- Data.Semigroup.Arg
-- ------------------

newtype instance MVector s (Arg a b) = MV_Arg (MVector s (a,b))
newtype instance Vector    (Arg a b) = V_Arg  (Vector    (a,b))

instance (Unbox a, Unbox b) => Unbox (Arg a b)

instance (Unbox a, Unbox b) => M.MVector MVector (Arg a b) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeMove #-}
  {-# INLINE basicUnsafeGrow #-}
  basicLength      = coerce $ M.basicLength      @MVector @(a,b)
  basicUnsafeSlice = coerce $ M.basicUnsafeSlice @MVector @(a,b)
  basicOverlaps    = coerce $ M.basicOverlaps    @MVector @(a,b)
  basicUnsafeNew   = coerce $ M.basicUnsafeNew   @MVector @(a,b)
  basicInitialize  = coerce $ M.basicInitialize  @MVector @(a,b)
  basicUnsafeCopy  = coerce $ M.basicUnsafeCopy  @MVector @(a,b)
  basicUnsafeMove  = coerce $ M.basicUnsafeMove  @MVector @(a,b)
  basicUnsafeGrow  = coerce $ M.basicUnsafeGrow  @MVector @(a,b)
  basicClear       = coerce $ M.basicClear       @MVector @(a,b)
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicSet #-}
  basicUnsafeReplicate n (Arg x y)        = MV_Arg <$> M.basicUnsafeReplicate n (x,y)
  basicUnsafeRead (MV_Arg v) i            = uncurry Arg <$> M.basicUnsafeRead v i
  basicUnsafeWrite (MV_Arg v) i (Arg x y) = M.basicUnsafeWrite v i (x,y)
  basicSet (MV_Arg v) (Arg x y)           = M.basicSet v (x,y)


instance (Unbox a, Unbox b) => G.Vector Vector (Arg a b) where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeCopy #-}
  basicUnsafeFreeze = coerce $ G.basicUnsafeFreeze @Vector @(a,b)
  basicUnsafeThaw   = coerce $ G.basicUnsafeThaw   @Vector @(a,b)
  basicLength       = coerce $ G.basicLength       @Vector @(a,b)
  basicUnsafeSlice  = coerce $ G.basicUnsafeSlice  @Vector @(a,b)
  basicUnsafeCopy   = coerce $ G.basicUnsafeCopy   @Vector @(a,b)
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeIndexM (V_Arg v) i  = uncurry Arg `liftM` G.basicUnsafeIndexM v i
  elemseq _ (Arg x y) z          = G.elemseq (undefined :: Vector a) x
                                 $ G.elemseq (undefined :: Vector b) y z

-- -------
-- Unboxing the Storable values
-- -------

-- | Newtype wrapper which allows to derive unboxed vector in term of
-- storable vectors using @DerivingVia@ mechanism. This is mostly
-- used as illustration of use of @DerivingVia@ for vector, see examples below.
--
-- First is rather straightforward: we define newtype and use GND to
-- derive 'St.Storable' instance. Newtype instances should be defined
-- manually. Then we use deriving via to define necessary instances.
--
-- >>> :set -XTypeFamilies -XStandaloneDeriving -XDerivingVia -XMultiParamTypeClasses
-- >>> :set -XGeneralizedNewtypeDeriving
-- >>>
-- >>> import qualified Data.Vector.Generic         as VG
-- >>> import qualified Data.Vector.Generic.Mutable as VGM
-- >>> import qualified Data.Vector.Storable        as VS
-- >>> import qualified Data.Vector.Unboxed         as VU
-- >>>
-- >>> newtype Foo = Foo Int deriving VS.Storable
-- >>>
-- >>> newtype instance VU.MVector s Foo = MV_Foo (VS.MVector s Foo)
-- >>> newtype instance VU.Vector    Foo = V_Foo  (VS.Vector    Foo)
-- >>> deriving via (VU.UnboxViaStorable Foo) instance VGM.MVector VU.MVector Foo
-- >>> deriving via (VU.UnboxViaStorable Foo) instance VG.Vector   VU.Vector  Foo
-- >>> instance VU.Unbox Foo
--
-- Second example is essentially same but with a twist. Instead of
-- using 'St.Storable' instance of data type, we use underlying instance of 'Int':
--
-- >>> :set -XTypeFamilies -XStandaloneDeriving -XDerivingVia -XMultiParamTypeClasses
-- >>>
-- >>> import qualified Data.Vector.Generic         as VG
-- >>> import qualified Data.Vector.Generic.Mutable as VGM
-- >>> import qualified Data.Vector.Storable        as VS
-- >>> import qualified Data.Vector.Unboxed         as VU
-- >>>
-- >>> newtype Foo = Foo Int
-- >>>
-- >>> newtype instance VU.MVector s Foo = MV_Foo (VS.MVector s Int)
-- >>> newtype instance VU.Vector    Foo = V_Foo  (VS.Vector    Int)
-- >>> deriving via (VU.UnboxViaStorable Int) instance VGM.MVector VU.MVector Foo
-- >>> deriving via (VU.UnboxViaStorable Int) instance VG.Vector   VU.Vector  Foo
-- >>> instance VU.Unbox Foo
--
-- @since 0.13.3.0
newtype UnboxViaStorable a = UnboxViaStorable a

newtype instance MVector s (UnboxViaStorable a) = MV_UnboxViaStorable (St.MVector s a)
newtype instance Vector    (UnboxViaStorable a) = V_UnboxViaStorable  (St.Vector    a)

instance St.Storable a => M.MVector MVector (UnboxViaStorable a) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}
  basicLength          = coerce $ M.basicLength          @St.MVector @a
  basicUnsafeSlice     = coerce $ M.basicUnsafeSlice     @St.MVector @a
  basicOverlaps        = coerce $ M.basicOverlaps        @St.MVector @a
  basicUnsafeNew       = coerce $ M.basicUnsafeNew       @St.MVector @a
  basicInitialize      = coerce $ M.basicInitialize      @St.MVector @a
  basicUnsafeReplicate = coerce $ M.basicUnsafeReplicate @St.MVector @a
  basicUnsafeRead      = coerce $ M.basicUnsafeRead      @St.MVector @a
  basicUnsafeWrite     = coerce $ M.basicUnsafeWrite     @St.MVector @a
  basicClear           = coerce $ M.basicClear           @St.MVector @a
  basicSet             = coerce $ M.basicSet             @St.MVector @a
  basicUnsafeCopy      = coerce $ M.basicUnsafeCopy      @St.MVector @a
  basicUnsafeMove      = coerce $ M.basicUnsafeMove      @St.MVector @a
  basicUnsafeGrow      = coerce $ M.basicUnsafeGrow      @St.MVector @a

instance St.Storable a => G.Vector Vector (UnboxViaStorable a) where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeFreeze = coerce $ G.basicUnsafeFreeze @St.Vector @a
  basicUnsafeThaw   = coerce $ G.basicUnsafeThaw   @St.Vector @a
  basicLength       = coerce $ G.basicLength       @St.Vector @a
  basicUnsafeSlice  = coerce $ G.basicUnsafeSlice  @St.Vector @a
  basicUnsafeIndexM = coerce $ G.basicUnsafeIndexM @St.Vector @a
  basicUnsafeCopy   = coerce $ G.basicUnsafeCopy   @St.Vector @a
  elemseq _ = seq

instance St.Storable a => Unbox (UnboxViaStorable a)

-- -------
-- Unboxing the boxed values
-- -------

-- | Newtype which allows to derive unbox instances for type @a@ which
-- is normally a "boxed" type. The newtype does not alter the strictness
-- semantics of the underlying type and inherits the laizness of said type.
-- For a strict newtype wrapper, see 'DoNotUnboxStrict'.
--
-- 'DoNotUnboxLazy' is intended to be unsed in conjunction with the newtype 'As'
-- and the type class 'IsoUnbox'. Here's an example which uses the following
-- explicit 'IsoUnbox' instance:
--
--
-- >>> :set -XTypeFamilies -XStandaloneDeriving -XDerivingVia
-- >>> :set -XMultiParamTypeClasses -XTypeOperators -XFlexibleInstances
-- >>> import qualified Data.Vector.Unboxed         as VU
-- >>> import qualified Data.Vector.Generic         as VG
-- >>> import qualified Data.Vector.Generic.Mutable as VGM
-- >>> :{
-- >>> data Foo a = Foo Int a
-- >>>   deriving (Eq, Ord, Show)
-- >>> instance VU.IsoUnbox (Foo a) (Int, VU.DoNotUnboxLazy a) where
-- >>>   toURepr (Foo i a) = (i, VU.DoNotUnboxLazy a)
-- >>>   fromURepr (i, VU.DoNotUnboxLazy a) = Foo i a
-- >>>   {-# INLINE toURepr #-}
-- >>>   {-# INLINE fromURepr #-}
-- >>> newtype instance VU.MVector s (Foo a) = MV_Foo (VU.MVector s (Int, VU.DoNotUnboxLazy a))
-- >>> newtype instance VU.Vector    (Foo a) = V_Foo  (VU.Vector    (Int, VU.DoNotUnboxLazy a))
-- >>> deriving via (Foo a `VU.As` (Int, VU.DoNotUnboxLazy a)) instance VGM.MVector VU.MVector (Foo a)
-- >>> deriving via (Foo a `VU.As` (Int, VU.DoNotUnboxLazy a)) instance VG.Vector   VU.Vector   (Foo a)
-- >>> instance VU.Unbox (Foo a)
-- >>> :}
--
-- >>> VU.fromListN 3 [ Foo 4 "Haskell's", Foo 8 "strong", Foo 16 "types" ]
-- [Foo 4 "Haskell's",Foo 8 "strong",Foo 16 "types"]
--
-- @since 0.13.2.0
newtype DoNotUnboxLazy a = DoNotUnboxLazy a

newtype instance MVector s (DoNotUnboxLazy a) = MV_DoNotUnboxLazy (B.MVector s a)
newtype instance Vector    (DoNotUnboxLazy a) = V_DoNotUnboxLazy  (B.Vector    a)

instance M.MVector MVector (DoNotUnboxLazy a) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}
  basicLength          = coerce $ M.basicLength          @B.MVector @a
  basicUnsafeSlice     = coerce $ M.basicUnsafeSlice     @B.MVector @a
  basicOverlaps        = coerce $ M.basicOverlaps        @B.MVector @a
  basicUnsafeNew       = coerce $ M.basicUnsafeNew       @B.MVector @a
  basicInitialize      = coerce $ M.basicInitialize      @B.MVector @a
  basicUnsafeReplicate = coerce $ M.basicUnsafeReplicate @B.MVector @a
  basicUnsafeRead      = coerce $ M.basicUnsafeRead      @B.MVector @a
  basicUnsafeWrite     = coerce $ M.basicUnsafeWrite     @B.MVector @a
  basicClear           = coerce $ M.basicClear           @B.MVector @a
  basicSet             = coerce $ M.basicSet             @B.MVector @a
  basicUnsafeCopy      = coerce $ M.basicUnsafeCopy      @B.MVector @a
  basicUnsafeMove      = coerce $ M.basicUnsafeMove      @B.MVector @a
  basicUnsafeGrow      = coerce $ M.basicUnsafeGrow      @B.MVector @a

instance G.Vector Vector (DoNotUnboxLazy a) where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeFreeze = coerce $ G.basicUnsafeFreeze @B.Vector @a
  basicUnsafeThaw   = coerce $ G.basicUnsafeThaw   @B.Vector @a
  basicLength       = coerce $ G.basicLength       @B.Vector @a
  basicUnsafeSlice  = coerce $ G.basicUnsafeSlice  @B.Vector @a
  basicUnsafeIndexM = coerce $ G.basicUnsafeIndexM @B.Vector @a
  basicUnsafeCopy   = coerce $ G.basicUnsafeCopy   @B.Vector @a
  elemseq _ = seq

instance Unbox (DoNotUnboxLazy a)

-- | Newtype which allows to derive unbox instances for type @a@ which
-- is normally a "boxed" type. The newtype stictly evaluates the wrapped values
-- ensuring that the unboxed vector contains no (direct) thunks.
-- For a less strict newtype wrapper, see 'DoNotUnboxLazy'.
-- For a more strict newtype wrapper, see 'DoNotUnboxNormalForm'.
--
-- 'DoNotUnboxStrict' is intended to be unsed in conjunction with the newtype 'As'
-- and the type class 'IsoUnbox'. Here's an example which uses the following
-- explicit 'IsoUnbox' instance:
--
--
-- >>> :set -XBangPatterns -XTypeFamilies -XStandaloneDeriving -XDerivingVia
-- >>> :set -XMultiParamTypeClasses -XTypeOperators -XFlexibleInstances
-- >>> import qualified Data.Vector.Unboxed         as VU
-- >>> import qualified Data.Vector.Generic         as VG
-- >>> import qualified Data.Vector.Generic.Mutable as VGM
-- >>> :{
-- >>> data Bar a = Bar Int a
-- >>>   deriving Show
-- >>> instance VU.IsoUnbox (Bar a) (Int, VU.DoNotUnboxStrict a) where
-- >>>   toURepr (Bar i !a) = (i, VU.DoNotUnboxStrict a)
-- >>>   fromURepr (i, VU.DoNotUnboxStrict a) = Bar i a
-- >>>   {-# INLINE toURepr #-}
-- >>>   {-# INLINE fromURepr #-}
-- >>> newtype instance VU.MVector s (Bar a) = MV_Bar (VU.MVector s (Int, VU.DoNotUnboxStrict a))
-- >>> newtype instance VU.Vector    (Bar a) = V_Bar  (VU.Vector    (Int, VU.DoNotUnboxStrict a))
-- >>> deriving via (Bar a `VU.As` (Int, VU.DoNotUnboxStrict a)) instance VGM.MVector VU.MVector (Bar a)
-- >>> deriving via (Bar a `VU.As` (Int, VU.DoNotUnboxStrict a)) instance VG.Vector   VU.Vector   (Bar a)
-- >>> instance VU.Unbox (Bar a)
-- >>> :}
--
-- >>> VU.fromListN 3 [ Bar 3 "Bye", Bar 2 "for", Bar 1 "now" ]
-- [Bar 3 "Bye",Bar 2 "for",Bar 1 "now"]
--
-- @since 0.13.2.0
newtype DoNotUnboxStrict a = DoNotUnboxStrict a

newtype instance MVector s (DoNotUnboxStrict a) = MV_DoNotUnboxStrict (S.MVector s a)
newtype instance Vector    (DoNotUnboxStrict a) = V_DoNotUnboxStrict  (S.Vector a)

instance M.MVector MVector (DoNotUnboxStrict a) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}
  basicLength          = coerce $ M.basicLength          @S.MVector @a
  basicUnsafeSlice     = coerce $ M.basicUnsafeSlice     @S.MVector @a
  basicOverlaps        = coerce $ M.basicOverlaps        @S.MVector @a
  basicUnsafeNew       = coerce $ M.basicUnsafeNew       @S.MVector @a
  basicInitialize      = coerce $ M.basicInitialize      @S.MVector @a
  basicUnsafeReplicate = coerce $ M.basicUnsafeReplicate @S.MVector @a
  basicUnsafeRead      = coerce $ M.basicUnsafeRead      @S.MVector @a
  basicUnsafeWrite     = coerce $ M.basicUnsafeWrite     @S.MVector @a
  basicClear           = coerce $ M.basicClear           @S.MVector @a
  basicSet             = coerce $ M.basicSet             @S.MVector @a
  basicUnsafeCopy      = coerce $ M.basicUnsafeCopy      @S.MVector @a
  basicUnsafeMove      = coerce $ M.basicUnsafeMove      @S.MVector @a
  basicUnsafeGrow      = coerce $ M.basicUnsafeGrow      @S.MVector @a

instance G.Vector Vector (DoNotUnboxStrict a) where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeFreeze = coerce $ G.basicUnsafeFreeze @S.Vector @a
  basicUnsafeThaw   = coerce $ G.basicUnsafeThaw   @S.Vector @a
  basicLength       = coerce $ G.basicLength       @S.Vector @a
  basicUnsafeSlice  = coerce $ G.basicUnsafeSlice  @S.Vector @a
  basicUnsafeIndexM = coerce $ G.basicUnsafeIndexM @S.Vector @a
  basicUnsafeCopy   = coerce $ G.basicUnsafeCopy   @S.Vector @a
  elemseq _ = seq

instance Unbox (DoNotUnboxStrict a)

-- | Newtype which allows to derive unbox instances for type @a@ which
-- is normally a "boxed" type. The newtype stictly evaluates the wrapped values
-- via thier requisite 'NFData' instance, ensuring that the unboxed vector
-- contains only values reduced to normal form.
-- For a less strict newtype wrappers, see 'DoNotUnboxLazy' and 'DoNotUnboxStrict'.
--
-- 'DoNotUnboxNormalForm' is intended to be unsed in conjunction with the newtype 'As'
-- and the type class 'IsoUnbox'. Here's an example which uses the following
-- explicit 'IsoUnbox' instance:
--
--
-- >>> :set -XTypeFamilies -XStandaloneDeriving -XDerivingVia
-- >>> :set -XMultiParamTypeClasses -XTypeOperators -XFlexibleInstances
-- >>> import qualified Data.Vector.Unboxed         as VU
-- >>> import qualified Data.Vector.Generic         as VG
-- >>> import qualified Data.Vector.Generic.Mutable as VGM
-- >>> import qualified Control.DeepSeq             as NF
-- >>> :{
-- >>> data Baz a = Baz Int a
-- >>>   deriving Show
-- >>> instance NF.NFData a => VU.IsoUnbox (Baz a) (Int, VU.DoNotUnboxNormalForm a) where
-- >>>   toURepr (Baz i a) = (i, VU.DoNotUnboxNormalForm $ NF.force a)
-- >>>   fromURepr (i, VU.DoNotUnboxNormalForm a) = Baz i a
-- >>>   {-# INLINE toURepr #-}
-- >>>   {-# INLINE fromURepr #-}
-- >>> newtype instance VU.MVector s (Baz a) = MV_Baz (VU.MVector s (Int, VU.DoNotUnboxNormalForm a))
-- >>> newtype instance VU.Vector    (Baz a) = V_Baz  (VU.Vector    (Int, VU.DoNotUnboxNormalForm a))
-- >>> deriving via (Baz a `VU.As` (Int, VU.DoNotUnboxNormalForm a)) instance NF.NFData a => VGM.MVector VU.MVector (Baz a)
-- >>> deriving via (Baz a `VU.As` (Int, VU.DoNotUnboxNormalForm a)) instance NF.NFData a => VG.Vector   VU.Vector   (Baz a)
-- >>> instance NF.NFData a => VU.Unbox (Baz a)
-- >>> :}
--
-- >>> VU.fromListN 3 [ Baz 3 "Fully", Baz 9 "evaluated", Baz 27 "data" ]
-- [Baz 3 "Fully",Baz 9 "evaluated",Baz 27 "data"]
--
-- @since 0.13.2.0
newtype DoNotUnboxNormalForm a = DoNotUnboxNormalForm a

newtype instance MVector s (DoNotUnboxNormalForm a) = MV_DoNotUnboxNormalForm (S.MVector s a)
newtype instance Vector    (DoNotUnboxNormalForm a) = V_DoNotUnboxNormalForm  (S.Vector a)

instance NFData a => M.MVector MVector (DoNotUnboxNormalForm a) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicInitialize #-}
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}
  basicLength          = coerce $ M.basicLength          @S.MVector @a
  basicUnsafeSlice     = coerce $ M.basicUnsafeSlice     @S.MVector @a
  basicOverlaps        = coerce $ M.basicOverlaps        @S.MVector @a
  basicUnsafeNew       = coerce $ M.basicUnsafeNew       @S.MVector @a
  basicInitialize      = coerce $ M.basicInitialize      @S.MVector @a
  basicUnsafeReplicate = coerce (\i x -> M.basicUnsafeReplicate @S.MVector @a i (force x))
  basicUnsafeRead      = coerce $ M.basicUnsafeRead      @S.MVector @a
  basicUnsafeWrite     = coerce (\v i x -> M.basicUnsafeWrite @S.MVector @a v i (force x))
  basicClear           = coerce $ M.basicClear           @S.MVector @a
  basicSet             = coerce (\v x -> M.basicSet @S.MVector @a v (force x))
  basicUnsafeCopy      = coerce $ M.basicUnsafeCopy      @S.MVector @a
  basicUnsafeMove      = coerce $ M.basicUnsafeMove      @S.MVector @a
  basicUnsafeGrow      = coerce $ M.basicUnsafeGrow      @S.MVector @a

instance NFData a => G.Vector Vector (DoNotUnboxNormalForm a) where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeFreeze = coerce $ G.basicUnsafeFreeze @S.Vector @a
  basicUnsafeThaw   = coerce $ G.basicUnsafeThaw   @S.Vector @a
  basicLength       = coerce $ G.basicLength       @S.Vector @a
  basicUnsafeSlice  = coerce $ G.basicUnsafeSlice  @S.Vector @a
  basicUnsafeIndexM = coerce $ G.basicUnsafeIndexM @S.Vector @a
  basicUnsafeCopy   = coerce $ G.basicUnsafeCopy   @S.Vector @a
  elemseq _ x y = rnf (coerce x :: a) `seq` y

instance NFData a => Unbox (DoNotUnboxNormalForm a)


newtype instance MVector s Any = MV_Any (MVector s Bool)
newtype instance Vector    Any = V_Any  (Vector    Bool)
deriving instance G.Vector  Vector  Any
deriving instance M.MVector MVector Any
instance Unbox Any

newtype instance MVector s All = MV_All (MVector s Bool)
newtype instance Vector    All = V_All  (Vector    Bool)
deriving instance G.Vector  Vector  All
deriving instance M.MVector MVector All
instance Unbox All

-- -------
-- Const
-- -------

newtype instance MVector s (Const b a) = MV_Const (MVector s b)
newtype instance Vector    (Const b a) = V_Const  (Vector    b)
deriving instance Unbox b => G.Vector  Vector  (Const b a)
deriving instance Unbox b => M.MVector MVector (Const b a)
instance Unbox b => Unbox (Const b a)

-- ---
-- Alt
-- ---

newtype instance MVector s (Alt f a) = MV_Alt (MVector s (f a))
newtype instance Vector    (Alt f a) = V_Alt  (Vector    (f a))
deriving instance Unbox (f a) => G.Vector  Vector  (Alt f a)
deriving instance Unbox (f a) => M.MVector MVector (Alt f a)
instance Unbox (f a) => Unbox (Alt f a)

-- -------
-- Compose
-- -------

newtype instance MVector s (Compose f g a) = MV_Compose (MVector s (f (g a)))
newtype instance Vector    (Compose f g a) = V_Compose  (Vector    (f (g a)))
deriving instance Unbox (f (g a)) => G.Vector  Vector  (Compose f g a)
deriving instance Unbox (f (g a)) => M.MVector MVector (Compose f g a)
instance Unbox (f (g a)) => Unbox (Compose f g a)

-- ------
-- Tuples
-- ------

data instance MVector s (a, b)
    = MV_2 {-# UNPACK #-} !Int !(MVector s a)
                               !(MVector s b)
data instance Vector (a, b)
    = V_2 {-# UNPACK #-} !Int !(Vector a)
                              !(Vector b)
instance (Unbox a, Unbox b) => Unbox (a, b)
instance (Unbox a, Unbox b) => M.MVector MVector (a, b) where
  {-# INLINE basicLength  #-}
  basicLength (MV_2 n_ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (MV_2 _ as bs)
      = MV_2 m_ (M.basicUnsafeSlice i_ m_ as)
                (M.basicUnsafeSlice i_ m_ bs)
  {-# INLINE basicOverlaps  #-}
  basicOverlaps (MV_2 _ as1 bs1) (MV_2 _ as2 bs2)
      = M.basicOverlaps as1 as2
        || M.basicOverlaps bs1 bs2
  {-# INLINE basicUnsafeNew  #-}
  basicUnsafeNew n_
      = do
          as <- M.basicUnsafeNew n_
          bs <- M.basicUnsafeNew n_
          return $ MV_2 n_ as bs
  {-# INLINE basicInitialize  #-}
  basicInitialize (MV_2 _ as bs)
      = do
          M.basicInitialize as
          M.basicInitialize bs
  {-# INLINE basicUnsafeReplicate  #-}
  basicUnsafeReplicate n_ (a, b)
      = do
          as <- M.basicUnsafeReplicate n_ a
          bs <- M.basicUnsafeReplicate n_ b
          return $ MV_2 n_ as bs
  {-# INLINE basicUnsafeRead  #-}
  basicUnsafeRead (MV_2 _ as bs) i_
      = do
          a <- M.basicUnsafeRead as i_
          b <- M.basicUnsafeRead bs i_
          return (a, b)
  {-# INLINE basicUnsafeWrite  #-}
  basicUnsafeWrite (MV_2 _ as bs) i_ (a, b)
      = do
          M.basicUnsafeWrite as i_ a
          M.basicUnsafeWrite bs i_ b
  {-# INLINE basicClear  #-}
  basicClear (MV_2 _ as bs)
      = do
          M.basicClear as
          M.basicClear bs
  {-# INLINE basicSet  #-}
  basicSet (MV_2 _ as bs) (a, b)
      = do
          M.basicSet as a
          M.basicSet bs b
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_2 _ as1 bs1) (MV_2 _ as2 bs2)
      = do
          M.basicUnsafeCopy as1 as2
          M.basicUnsafeCopy bs1 bs2
  {-# INLINE basicUnsafeMove  #-}
  basicUnsafeMove (MV_2 _ as1 bs1) (MV_2 _ as2 bs2)
      = do
          M.basicUnsafeMove as1 as2
          M.basicUnsafeMove bs1 bs2
  {-# INLINE basicUnsafeGrow  #-}
  basicUnsafeGrow (MV_2 n_ as bs) m_
      = do
          as' <- M.basicUnsafeGrow as m_
          bs' <- M.basicUnsafeGrow bs m_
          return $ MV_2 (m_+n_) as' bs'
instance (Unbox a, Unbox b) => G.Vector Vector (a, b) where
  {-# INLINE basicUnsafeFreeze  #-}
  basicUnsafeFreeze (MV_2 n_ as bs)
      = do
          as' <- G.basicUnsafeFreeze as
          bs' <- G.basicUnsafeFreeze bs
          return $ V_2 n_ as' bs'
  {-# INLINE basicUnsafeThaw  #-}
  basicUnsafeThaw (V_2 n_ as bs)
      = do
          as' <- G.basicUnsafeThaw as
          bs' <- G.basicUnsafeThaw bs
          return $ MV_2 n_ as' bs'
  {-# INLINE basicLength  #-}
  basicLength (V_2 n_ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (V_2 _ as bs)
      = V_2 m_ (G.basicUnsafeSlice i_ m_ as)
               (G.basicUnsafeSlice i_ m_ bs)
  {-# INLINE basicUnsafeIndexM  #-}
  basicUnsafeIndexM (V_2 _ as bs) i_
      = do
          a <- G.basicUnsafeIndexM as i_
          b <- G.basicUnsafeIndexM bs i_
          return (a, b)
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_2 _ as1 bs1) (V_2 _ as2 bs2)
      = do
          G.basicUnsafeCopy as1 as2
          G.basicUnsafeCopy bs1 bs2
  {-# INLINE elemseq  #-}
  elemseq _ (a, b)
      = G.elemseq (undefined :: Vector a) a
        . G.elemseq (undefined :: Vector b) b

data instance MVector s (a, b, c)
    = MV_3 {-# UNPACK #-} !Int !(MVector s a)
                               !(MVector s b)
                               !(MVector s c)
data instance Vector (a, b, c)
    = V_3 {-# UNPACK #-} !Int !(Vector a)
                              !(Vector b)
                              !(Vector c)
instance (Unbox a, Unbox b, Unbox c) => Unbox (a, b, c)
instance (Unbox a,
          Unbox b,
          Unbox c) => M.MVector MVector (a, b, c) where
  {-# INLINE basicLength  #-}
  basicLength (MV_3 n_ _ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (MV_3 _ as bs cs)
      = MV_3 m_ (M.basicUnsafeSlice i_ m_ as)
                (M.basicUnsafeSlice i_ m_ bs)
                (M.basicUnsafeSlice i_ m_ cs)
  {-# INLINE basicOverlaps  #-}
  basicOverlaps (MV_3 _ as1 bs1 cs1) (MV_3 _ as2 bs2 cs2)
      = M.basicOverlaps as1 as2
        || M.basicOverlaps bs1 bs2
        || M.basicOverlaps cs1 cs2
  {-# INLINE basicUnsafeNew  #-}
  basicUnsafeNew n_
      = do
          as <- M.basicUnsafeNew n_
          bs <- M.basicUnsafeNew n_
          cs <- M.basicUnsafeNew n_
          return $ MV_3 n_ as bs cs
  {-# INLINE basicInitialize #-}
  basicInitialize (MV_3 _ as bs cs)
      = do
          M.basicInitialize as
          M.basicInitialize bs
          M.basicInitialize cs
  {-# INLINE basicUnsafeReplicate  #-}
  basicUnsafeReplicate n_ (a, b, c)
      = do
          as <- M.basicUnsafeReplicate n_ a
          bs <- M.basicUnsafeReplicate n_ b
          cs <- M.basicUnsafeReplicate n_ c
          return $ MV_3 n_ as bs cs
  {-# INLINE basicUnsafeRead  #-}
  basicUnsafeRead (MV_3 _ as bs cs) i_
      = do
          a <- M.basicUnsafeRead as i_
          b <- M.basicUnsafeRead bs i_
          c <- M.basicUnsafeRead cs i_
          return (a, b, c)
  {-# INLINE basicUnsafeWrite  #-}
  basicUnsafeWrite (MV_3 _ as bs cs) i_ (a, b, c)
      = do
          M.basicUnsafeWrite as i_ a
          M.basicUnsafeWrite bs i_ b
          M.basicUnsafeWrite cs i_ c
  {-# INLINE basicClear  #-}
  basicClear (MV_3 _ as bs cs)
      = do
          M.basicClear as
          M.basicClear bs
          M.basicClear cs
  {-# INLINE basicSet  #-}
  basicSet (MV_3 _ as bs cs) (a, b, c)
      = do
          M.basicSet as a
          M.basicSet bs b
          M.basicSet cs c
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_3 _ as1 bs1 cs1) (MV_3 _ as2 bs2 cs2)
      = do
          M.basicUnsafeCopy as1 as2
          M.basicUnsafeCopy bs1 bs2
          M.basicUnsafeCopy cs1 cs2
  {-# INLINE basicUnsafeMove  #-}
  basicUnsafeMove (MV_3 _ as1 bs1 cs1) (MV_3 _ as2 bs2 cs2)
      = do
          M.basicUnsafeMove as1 as2
          M.basicUnsafeMove bs1 bs2
          M.basicUnsafeMove cs1 cs2
  {-# INLINE basicUnsafeGrow  #-}
  basicUnsafeGrow (MV_3 n_ as bs cs) m_
      = do
          as' <- M.basicUnsafeGrow as m_
          bs' <- M.basicUnsafeGrow bs m_
          cs' <- M.basicUnsafeGrow cs m_
          return $ MV_3 (m_+n_) as' bs' cs'
instance (Unbox a,
          Unbox b,
          Unbox c) => G.Vector Vector (a, b, c) where
  {-# INLINE basicUnsafeFreeze  #-}
  basicUnsafeFreeze (MV_3 n_ as bs cs)
      = do
          as' <- G.basicUnsafeFreeze as
          bs' <- G.basicUnsafeFreeze bs
          cs' <- G.basicUnsafeFreeze cs
          return $ V_3 n_ as' bs' cs'
  {-# INLINE basicUnsafeThaw  #-}
  basicUnsafeThaw (V_3 n_ as bs cs)
      = do
          as' <- G.basicUnsafeThaw as
          bs' <- G.basicUnsafeThaw bs
          cs' <- G.basicUnsafeThaw cs
          return $ MV_3 n_ as' bs' cs'
  {-# INLINE basicLength  #-}
  basicLength (V_3 n_ _ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (V_3 _ as bs cs)
      = V_3 m_ (G.basicUnsafeSlice i_ m_ as)
               (G.basicUnsafeSlice i_ m_ bs)
               (G.basicUnsafeSlice i_ m_ cs)
  {-# INLINE basicUnsafeIndexM  #-}
  basicUnsafeIndexM (V_3 _ as bs cs) i_
      = do
          a <- G.basicUnsafeIndexM as i_
          b <- G.basicUnsafeIndexM bs i_
          c <- G.basicUnsafeIndexM cs i_
          return (a, b, c)
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_3 _ as1 bs1 cs1) (V_3 _ as2 bs2 cs2)
      = do
          G.basicUnsafeCopy as1 as2
          G.basicUnsafeCopy bs1 bs2
          G.basicUnsafeCopy cs1 cs2
  {-# INLINE elemseq  #-}
  elemseq _ (a, b, c)
      = G.elemseq (undefined :: Vector a) a
        . G.elemseq (undefined :: Vector b) b
        . G.elemseq (undefined :: Vector c) c

data instance MVector s (a, b, c, d)
    = MV_4 {-# UNPACK #-} !Int !(MVector s a)
                               !(MVector s b)
                               !(MVector s c)
                               !(MVector s d)
data instance Vector (a, b, c, d)
    = V_4 {-# UNPACK #-} !Int !(Vector a)
                              !(Vector b)
                              !(Vector c)
                              !(Vector d)
instance (Unbox a, Unbox b, Unbox c, Unbox d) => Unbox (a, b, c, d)
instance (Unbox a,
          Unbox b,
          Unbox c,
          Unbox d) => M.MVector MVector (a, b, c, d) where
  {-# INLINE basicLength  #-}
  basicLength (MV_4 n_ _ _ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (MV_4 _ as bs cs ds)
      = MV_4 m_ (M.basicUnsafeSlice i_ m_ as)
                (M.basicUnsafeSlice i_ m_ bs)
                (M.basicUnsafeSlice i_ m_ cs)
                (M.basicUnsafeSlice i_ m_ ds)
  {-# INLINE basicOverlaps  #-}
  basicOverlaps (MV_4 _ as1 bs1 cs1 ds1) (MV_4 _ as2 bs2 cs2 ds2)
      = M.basicOverlaps as1 as2
        || M.basicOverlaps bs1 bs2
        || M.basicOverlaps cs1 cs2
        || M.basicOverlaps ds1 ds2
  {-# INLINE basicUnsafeNew  #-}
  basicUnsafeNew n_
      = do
          as <- M.basicUnsafeNew n_
          bs <- M.basicUnsafeNew n_
          cs <- M.basicUnsafeNew n_
          ds <- M.basicUnsafeNew n_
          return $ MV_4 n_ as bs cs ds
  {-# INLINE basicInitialize #-}
  basicInitialize (MV_4 _ as bs cs ds)
      = do
          M.basicInitialize as
          M.basicInitialize bs
          M.basicInitialize cs
          M.basicInitialize ds
  {-# INLINE basicUnsafeReplicate  #-}
  basicUnsafeReplicate n_ (a, b, c, d)
      = do
          as <- M.basicUnsafeReplicate n_ a
          bs <- M.basicUnsafeReplicate n_ b
          cs <- M.basicUnsafeReplicate n_ c
          ds <- M.basicUnsafeReplicate n_ d
          return $ MV_4 n_ as bs cs ds
  {-# INLINE basicUnsafeRead  #-}
  basicUnsafeRead (MV_4 _ as bs cs ds) i_
      = do
          a <- M.basicUnsafeRead as i_
          b <- M.basicUnsafeRead bs i_
          c <- M.basicUnsafeRead cs i_
          d <- M.basicUnsafeRead ds i_
          return (a, b, c, d)
  {-# INLINE basicUnsafeWrite  #-}
  basicUnsafeWrite (MV_4 _ as bs cs ds) i_ (a, b, c, d)
      = do
          M.basicUnsafeWrite as i_ a
          M.basicUnsafeWrite bs i_ b
          M.basicUnsafeWrite cs i_ c
          M.basicUnsafeWrite ds i_ d
  {-# INLINE basicClear  #-}
  basicClear (MV_4 _ as bs cs ds)
      = do
          M.basicClear as
          M.basicClear bs
          M.basicClear cs
          M.basicClear ds
  {-# INLINE basicSet  #-}
  basicSet (MV_4 _ as bs cs ds) (a, b, c, d)
      = do
          M.basicSet as a
          M.basicSet bs b
          M.basicSet cs c
          M.basicSet ds d
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_4 _ as1 bs1 cs1 ds1) (MV_4 _ as2
                                                   bs2
                                                   cs2
                                                   ds2)
      = do
          M.basicUnsafeCopy as1 as2
          M.basicUnsafeCopy bs1 bs2
          M.basicUnsafeCopy cs1 cs2
          M.basicUnsafeCopy ds1 ds2
  {-# INLINE basicUnsafeMove  #-}
  basicUnsafeMove (MV_4 _ as1 bs1 cs1 ds1) (MV_4 _ as2
                                                   bs2
                                                   cs2
                                                   ds2)
      = do
          M.basicUnsafeMove as1 as2
          M.basicUnsafeMove bs1 bs2
          M.basicUnsafeMove cs1 cs2
          M.basicUnsafeMove ds1 ds2
  {-# INLINE basicUnsafeGrow  #-}
  basicUnsafeGrow (MV_4 n_ as bs cs ds) m_
      = do
          as' <- M.basicUnsafeGrow as m_
          bs' <- M.basicUnsafeGrow bs m_
          cs' <- M.basicUnsafeGrow cs m_
          ds' <- M.basicUnsafeGrow ds m_
          return $ MV_4 (m_+n_) as' bs' cs' ds'
instance (Unbox a,
          Unbox b,
          Unbox c,
          Unbox d) => G.Vector Vector (a, b, c, d) where
  {-# INLINE basicUnsafeFreeze  #-}
  basicUnsafeFreeze (MV_4 n_ as bs cs ds)
      = do
          as' <- G.basicUnsafeFreeze as
          bs' <- G.basicUnsafeFreeze bs
          cs' <- G.basicUnsafeFreeze cs
          ds' <- G.basicUnsafeFreeze ds
          return $ V_4 n_ as' bs' cs' ds'
  {-# INLINE basicUnsafeThaw  #-}
  basicUnsafeThaw (V_4 n_ as bs cs ds)
      = do
          as' <- G.basicUnsafeThaw as
          bs' <- G.basicUnsafeThaw bs
          cs' <- G.basicUnsafeThaw cs
          ds' <- G.basicUnsafeThaw ds
          return $ MV_4 n_ as' bs' cs' ds'
  {-# INLINE basicLength  #-}
  basicLength (V_4 n_ _ _ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (V_4 _ as bs cs ds)
      = V_4 m_ (G.basicUnsafeSlice i_ m_ as)
               (G.basicUnsafeSlice i_ m_ bs)
               (G.basicUnsafeSlice i_ m_ cs)
               (G.basicUnsafeSlice i_ m_ ds)
  {-# INLINE basicUnsafeIndexM  #-}
  basicUnsafeIndexM (V_4 _ as bs cs ds) i_
      = do
          a <- G.basicUnsafeIndexM as i_
          b <- G.basicUnsafeIndexM bs i_
          c <- G.basicUnsafeIndexM cs i_
          d <- G.basicUnsafeIndexM ds i_
          return (a, b, c, d)
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_4 _ as1 bs1 cs1 ds1) (V_4 _ as2
                                                  bs2
                                                  cs2
                                                  ds2)
      = do
          G.basicUnsafeCopy as1 as2
          G.basicUnsafeCopy bs1 bs2
          G.basicUnsafeCopy cs1 cs2
          G.basicUnsafeCopy ds1 ds2
  {-# INLINE elemseq  #-}
  elemseq _ (a, b, c, d)
      = G.elemseq (undefined :: Vector a) a
        . G.elemseq (undefined :: Vector b) b
        . G.elemseq (undefined :: Vector c) c
        . G.elemseq (undefined :: Vector d) d

data instance MVector s (a, b, c, d, e)
    = MV_5 {-# UNPACK #-} !Int !(MVector s a)
                               !(MVector s b)
                               !(MVector s c)
                               !(MVector s d)
                               !(MVector s e)
data instance Vector (a, b, c, d, e)
    = V_5 {-# UNPACK #-} !Int !(Vector a)
                              !(Vector b)
                              !(Vector c)
                              !(Vector d)
                              !(Vector e)
instance (Unbox a,
          Unbox b,
          Unbox c,
          Unbox d,
          Unbox e) => Unbox (a, b, c, d, e)
instance (Unbox a,
          Unbox b,
          Unbox c,
          Unbox d,
          Unbox e) => M.MVector MVector (a, b, c, d, e) where
  {-# INLINE basicLength  #-}
  basicLength (MV_5 n_ _ _ _ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (MV_5 _ as bs cs ds es)
      = MV_5 m_ (M.basicUnsafeSlice i_ m_ as)
                (M.basicUnsafeSlice i_ m_ bs)
                (M.basicUnsafeSlice i_ m_ cs)
                (M.basicUnsafeSlice i_ m_ ds)
                (M.basicUnsafeSlice i_ m_ es)
  {-# INLINE basicOverlaps  #-}
  basicOverlaps (MV_5 _ as1 bs1 cs1 ds1 es1) (MV_5 _ as2
                                                     bs2
                                                     cs2
                                                     ds2
                                                     es2)
      = M.basicOverlaps as1 as2
        || M.basicOverlaps bs1 bs2
        || M.basicOverlaps cs1 cs2
        || M.basicOverlaps ds1 ds2
        || M.basicOverlaps es1 es2
  {-# INLINE basicUnsafeNew  #-}
  basicUnsafeNew n_
      = do
          as <- M.basicUnsafeNew n_
          bs <- M.basicUnsafeNew n_
          cs <- M.basicUnsafeNew n_
          ds <- M.basicUnsafeNew n_
          es <- M.basicUnsafeNew n_
          return $ MV_5 n_ as bs cs ds es
  {-# INLINE basicInitialize #-}
  basicInitialize (MV_5 _ as bs cs ds es)
      = do
          M.basicInitialize as
          M.basicInitialize bs
          M.basicInitialize cs
          M.basicInitialize ds
          M.basicInitialize es
  {-# INLINE basicUnsafeReplicate  #-}
  basicUnsafeReplicate n_ (a, b, c, d, e)
      = do
          as <- M.basicUnsafeReplicate n_ a
          bs <- M.basicUnsafeReplicate n_ b
          cs <- M.basicUnsafeReplicate n_ c
          ds <- M.basicUnsafeReplicate n_ d
          es <- M.basicUnsafeReplicate n_ e
          return $ MV_5 n_ as bs cs ds es
  {-# INLINE basicUnsafeRead  #-}
  basicUnsafeRead (MV_5 _ as bs cs ds es) i_
      = do
          a <- M.basicUnsafeRead as i_
          b <- M.basicUnsafeRead bs i_
          c <- M.basicUnsafeRead cs i_
          d <- M.basicUnsafeRead ds i_
          e <- M.basicUnsafeRead es i_
          return (a, b, c, d, e)
  {-# INLINE basicUnsafeWrite  #-}
  basicUnsafeWrite (MV_5 _ as bs cs ds es) i_ (a, b, c, d, e)
      = do
          M.basicUnsafeWrite as i_ a
          M.basicUnsafeWrite bs i_ b
          M.basicUnsafeWrite cs i_ c
          M.basicUnsafeWrite ds i_ d
          M.basicUnsafeWrite es i_ e
  {-# INLINE basicClear  #-}
  basicClear (MV_5 _ as bs cs ds es)
      = do
          M.basicClear as
          M.basicClear bs
          M.basicClear cs
          M.basicClear ds
          M.basicClear es
  {-# INLINE basicSet  #-}
  basicSet (MV_5 _ as bs cs ds es) (a, b, c, d, e)
      = do
          M.basicSet as a
          M.basicSet bs b
          M.basicSet cs c
          M.basicSet ds d
          M.basicSet es e
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_5 _ as1 bs1 cs1 ds1 es1) (MV_5 _ as2
                                                       bs2
                                                       cs2
                                                       ds2
                                                       es2)
      = do
          M.basicUnsafeCopy as1 as2
          M.basicUnsafeCopy bs1 bs2
          M.basicUnsafeCopy cs1 cs2
          M.basicUnsafeCopy ds1 ds2
          M.basicUnsafeCopy es1 es2
  {-# INLINE basicUnsafeMove  #-}
  basicUnsafeMove (MV_5 _ as1 bs1 cs1 ds1 es1) (MV_5 _ as2
                                                       bs2
                                                       cs2
                                                       ds2
                                                       es2)
      = do
          M.basicUnsafeMove as1 as2
          M.basicUnsafeMove bs1 bs2
          M.basicUnsafeMove cs1 cs2
          M.basicUnsafeMove ds1 ds2
          M.basicUnsafeMove es1 es2
  {-# INLINE basicUnsafeGrow  #-}
  basicUnsafeGrow (MV_5 n_ as bs cs ds es) m_
      = do
          as' <- M.basicUnsafeGrow as m_
          bs' <- M.basicUnsafeGrow bs m_
          cs' <- M.basicUnsafeGrow cs m_
          ds' <- M.basicUnsafeGrow ds m_
          es' <- M.basicUnsafeGrow es m_
          return $ MV_5 (m_+n_) as' bs' cs' ds' es'
instance (Unbox a,
          Unbox b,
          Unbox c,
          Unbox d,
          Unbox e) => G.Vector Vector (a, b, c, d, e) where
  {-# INLINE basicUnsafeFreeze  #-}
  basicUnsafeFreeze (MV_5 n_ as bs cs ds es)
      = do
          as' <- G.basicUnsafeFreeze as
          bs' <- G.basicUnsafeFreeze bs
          cs' <- G.basicUnsafeFreeze cs
          ds' <- G.basicUnsafeFreeze ds
          es' <- G.basicUnsafeFreeze es
          return $ V_5 n_ as' bs' cs' ds' es'
  {-# INLINE basicUnsafeThaw  #-}
  basicUnsafeThaw (V_5 n_ as bs cs ds es)
      = do
          as' <- G.basicUnsafeThaw as
          bs' <- G.basicUnsafeThaw bs
          cs' <- G.basicUnsafeThaw cs
          ds' <- G.basicUnsafeThaw ds
          es' <- G.basicUnsafeThaw es
          return $ MV_5 n_ as' bs' cs' ds' es'
  {-# INLINE basicLength  #-}
  basicLength (V_5 n_ _ _ _ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (V_5 _ as bs cs ds es)
      = V_5 m_ (G.basicUnsafeSlice i_ m_ as)
               (G.basicUnsafeSlice i_ m_ bs)
               (G.basicUnsafeSlice i_ m_ cs)
               (G.basicUnsafeSlice i_ m_ ds)
               (G.basicUnsafeSlice i_ m_ es)
  {-# INLINE basicUnsafeIndexM  #-}
  basicUnsafeIndexM (V_5 _ as bs cs ds es) i_
      = do
          a <- G.basicUnsafeIndexM as i_
          b <- G.basicUnsafeIndexM bs i_
          c <- G.basicUnsafeIndexM cs i_
          d <- G.basicUnsafeIndexM ds i_
          e <- G.basicUnsafeIndexM es i_
          return (a, b, c, d, e)
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_5 _ as1 bs1 cs1 ds1 es1) (V_5 _ as2
                                                      bs2
                                                      cs2
                                                      ds2
                                                      es2)
      = do
          G.basicUnsafeCopy as1 as2
          G.basicUnsafeCopy bs1 bs2
          G.basicUnsafeCopy cs1 cs2
          G.basicUnsafeCopy ds1 ds2
          G.basicUnsafeCopy es1 es2
  {-# INLINE elemseq  #-}
  elemseq _ (a, b, c, d, e)
      = G.elemseq (undefined :: Vector a) a
        . G.elemseq (undefined :: Vector b) b
        . G.elemseq (undefined :: Vector c) c
        . G.elemseq (undefined :: Vector d) d
        . G.elemseq (undefined :: Vector e) e

data instance MVector s (a, b, c, d, e, f)
    = MV_6 {-# UNPACK #-} !Int !(MVector s a)
                               !(MVector s b)
                               !(MVector s c)
                               !(MVector s d)
                               !(MVector s e)
                               !(MVector s f)
data instance Vector (a, b, c, d, e, f)
    = V_6 {-# UNPACK #-} !Int !(Vector a)
                              !(Vector b)
                              !(Vector c)
                              !(Vector d)
                              !(Vector e)
                              !(Vector f)
instance (Unbox a,
          Unbox b,
          Unbox c,
          Unbox d,
          Unbox e,
          Unbox f) => Unbox (a, b, c, d, e, f)
instance (Unbox a,
          Unbox b,
          Unbox c,
          Unbox d,
          Unbox e,
          Unbox f) => M.MVector MVector (a, b, c, d, e, f) where
  {-# INLINE basicLength  #-}
  basicLength (MV_6 n_ _ _ _ _ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (MV_6 _ as bs cs ds es fs)
      = MV_6 m_ (M.basicUnsafeSlice i_ m_ as)
                (M.basicUnsafeSlice i_ m_ bs)
                (M.basicUnsafeSlice i_ m_ cs)
                (M.basicUnsafeSlice i_ m_ ds)
                (M.basicUnsafeSlice i_ m_ es)
                (M.basicUnsafeSlice i_ m_ fs)
  {-# INLINE basicOverlaps  #-}
  basicOverlaps (MV_6 _ as1 bs1 cs1 ds1 es1 fs1) (MV_6 _ as2
                                                         bs2
                                                         cs2
                                                         ds2
                                                         es2
                                                         fs2)
      = M.basicOverlaps as1 as2
        || M.basicOverlaps bs1 bs2
        || M.basicOverlaps cs1 cs2
        || M.basicOverlaps ds1 ds2
        || M.basicOverlaps es1 es2
        || M.basicOverlaps fs1 fs2
  {-# INLINE basicUnsafeNew  #-}
  basicUnsafeNew n_
      = do
          as <- M.basicUnsafeNew n_
          bs <- M.basicUnsafeNew n_
          cs <- M.basicUnsafeNew n_
          ds <- M.basicUnsafeNew n_
          es <- M.basicUnsafeNew n_
          fs <- M.basicUnsafeNew n_
          return $ MV_6 n_ as bs cs ds es fs
  {-# INLINE basicInitialize #-}
  basicInitialize (MV_6 _ as bs cs ds es fs)
      = do
          M.basicInitialize as
          M.basicInitialize bs
          M.basicInitialize cs
          M.basicInitialize ds
          M.basicInitialize es
          M.basicInitialize fs
  {-# INLINE basicUnsafeReplicate  #-}
  basicUnsafeReplicate n_ (a, b, c, d, e, f)
      = do
          as <- M.basicUnsafeReplicate n_ a
          bs <- M.basicUnsafeReplicate n_ b
          cs <- M.basicUnsafeReplicate n_ c
          ds <- M.basicUnsafeReplicate n_ d
          es <- M.basicUnsafeReplicate n_ e
          fs <- M.basicUnsafeReplicate n_ f
          return $ MV_6 n_ as bs cs ds es fs
  {-# INLINE basicUnsafeRead  #-}
  basicUnsafeRead (MV_6 _ as bs cs ds es fs) i_
      = do
          a <- M.basicUnsafeRead as i_
          b <- M.basicUnsafeRead bs i_
          c <- M.basicUnsafeRead cs i_
          d <- M.basicUnsafeRead ds i_
          e <- M.basicUnsafeRead es i_
          f <- M.basicUnsafeRead fs i_
          return (a, b, c, d, e, f)
  {-# INLINE basicUnsafeWrite  #-}
  basicUnsafeWrite (MV_6 _ as bs cs ds es fs) i_ (a, b, c, d, e, f)
      = do
          M.basicUnsafeWrite as i_ a
          M.basicUnsafeWrite bs i_ b
          M.basicUnsafeWrite cs i_ c
          M.basicUnsafeWrite ds i_ d
          M.basicUnsafeWrite es i_ e
          M.basicUnsafeWrite fs i_ f
  {-# INLINE basicClear  #-}
  basicClear (MV_6 _ as bs cs ds es fs)
      = do
          M.basicClear as
          M.basicClear bs
          M.basicClear cs
          M.basicClear ds
          M.basicClear es
          M.basicClear fs
  {-# INLINE basicSet  #-}
  basicSet (MV_6 _ as bs cs ds es fs) (a, b, c, d, e, f)
      = do
          M.basicSet as a
          M.basicSet bs b
          M.basicSet cs c
          M.basicSet ds d
          M.basicSet es e
          M.basicSet fs f
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_6 _ as1 bs1 cs1 ds1 es1 fs1) (MV_6 _ as2
                                                           bs2
                                                           cs2
                                                           ds2
                                                           es2
                                                           fs2)
      = do
          M.basicUnsafeCopy as1 as2
          M.basicUnsafeCopy bs1 bs2
          M.basicUnsafeCopy cs1 cs2
          M.basicUnsafeCopy ds1 ds2
          M.basicUnsafeCopy es1 es2
          M.basicUnsafeCopy fs1 fs2
  {-# INLINE basicUnsafeMove  #-}
  basicUnsafeMove (MV_6 _ as1 bs1 cs1 ds1 es1 fs1) (MV_6 _ as2
                                                           bs2
                                                           cs2
                                                           ds2
                                                           es2
                                                           fs2)
      = do
          M.basicUnsafeMove as1 as2
          M.basicUnsafeMove bs1 bs2
          M.basicUnsafeMove cs1 cs2
          M.basicUnsafeMove ds1 ds2
          M.basicUnsafeMove es1 es2
          M.basicUnsafeMove fs1 fs2
  {-# INLINE basicUnsafeGrow  #-}
  basicUnsafeGrow (MV_6 n_ as bs cs ds es fs) m_
      = do
          as' <- M.basicUnsafeGrow as m_
          bs' <- M.basicUnsafeGrow bs m_
          cs' <- M.basicUnsafeGrow cs m_
          ds' <- M.basicUnsafeGrow ds m_
          es' <- M.basicUnsafeGrow es m_
          fs' <- M.basicUnsafeGrow fs m_
          return $ MV_6 (m_+n_) as' bs' cs' ds' es' fs'
instance (Unbox a,
          Unbox b,
          Unbox c,
          Unbox d,
          Unbox e,
          Unbox f) => G.Vector Vector (a, b, c, d, e, f) where
  {-# INLINE basicUnsafeFreeze  #-}
  basicUnsafeFreeze (MV_6 n_ as bs cs ds es fs)
      = do
          as' <- G.basicUnsafeFreeze as
          bs' <- G.basicUnsafeFreeze bs
          cs' <- G.basicUnsafeFreeze cs
          ds' <- G.basicUnsafeFreeze ds
          es' <- G.basicUnsafeFreeze es
          fs' <- G.basicUnsafeFreeze fs
          return $ V_6 n_ as' bs' cs' ds' es' fs'
  {-# INLINE basicUnsafeThaw  #-}
  basicUnsafeThaw (V_6 n_ as bs cs ds es fs)
      = do
          as' <- G.basicUnsafeThaw as
          bs' <- G.basicUnsafeThaw bs
          cs' <- G.basicUnsafeThaw cs
          ds' <- G.basicUnsafeThaw ds
          es' <- G.basicUnsafeThaw es
          fs' <- G.basicUnsafeThaw fs
          return $ MV_6 n_ as' bs' cs' ds' es' fs'
  {-# INLINE basicLength  #-}
  basicLength (V_6 n_ _ _ _ _ _ _) = n_
  {-# INLINE basicUnsafeSlice  #-}
  basicUnsafeSlice i_ m_ (V_6 _ as bs cs ds es fs)
      = V_6 m_ (G.basicUnsafeSlice i_ m_ as)
               (G.basicUnsafeSlice i_ m_ bs)
               (G.basicUnsafeSlice i_ m_ cs)
               (G.basicUnsafeSlice i_ m_ ds)
               (G.basicUnsafeSlice i_ m_ es)
               (G.basicUnsafeSlice i_ m_ fs)
  {-# INLINE basicUnsafeIndexM  #-}
  basicUnsafeIndexM (V_6 _ as bs cs ds es fs) i_
      = do
          a <- G.basicUnsafeIndexM as i_
          b <- G.basicUnsafeIndexM bs i_
          c <- G.basicUnsafeIndexM cs i_
          d <- G.basicUnsafeIndexM ds i_
          e <- G.basicUnsafeIndexM es i_
          f <- G.basicUnsafeIndexM fs i_
          return (a, b, c, d, e, f)
  {-# INLINE basicUnsafeCopy  #-}
  basicUnsafeCopy (MV_6 _ as1 bs1 cs1 ds1 es1 fs1) (V_6 _ as2
                                                          bs2
                                                          cs2
                                                          ds2
                                                          es2
                                                          fs2)
      = do
          G.basicUnsafeCopy as1 as2
          G.basicUnsafeCopy bs1 bs2
          G.basicUnsafeCopy cs1 cs2
          G.basicUnsafeCopy ds1 ds2
          G.basicUnsafeCopy es1 es2
          G.basicUnsafeCopy fs1 fs2
  {-# INLINE elemseq  #-}
  elemseq _ (a, b, c, d, e, f)
      = G.elemseq (undefined :: Vector a) a
        . G.elemseq (undefined :: Vector b) b
        . G.elemseq (undefined :: Vector c) c
        . G.elemseq (undefined :: Vector d) d
        . G.elemseq (undefined :: Vector e) e
        . G.elemseq (undefined :: Vector f) f

