{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE MultiParamTypeClasses #-}
-- |
-- Module      : Data.Massiv.Array
-- Copyright   : (c) Alexey Kuleshevich 2018
-- License     : BSD3
-- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>
-- Stability   : experimental
-- Portability : non-portable
--
--
-- Massiv is a library, that allows creation and manipulation of arrays in parallel and
-- sequentially. Depending on the representation (@__r__@), an @__`Array` r ix e__@ will have
-- certain properties that are unique to that particular representation, but all of them will share
-- the same trait, that an array is simply a mapping from an index (@__ix__@) of an arbitrary
-- dimension to an element (@__e__@) of some value. Which means that some of the array types are
-- pretty classic and are represented by a contiguous chunk of memory reserved for the elements,
-- namely arrays with `Manifest` representations:
--
-- * `B` - The most basic type of array that can hold any type of element in a boxed form, i.e. each
--         element is a pointer to the actual value, therefore it is also the slowest
--         representation. Elements are kept in a Weak Head Normal Form (WHNF).
--
-- * `N` - Similar to `B`, is also a boxed type, except it's elements are always kept in a Normal
--         Form (NF). This property is very useful for parallel processing, i.e. when calling
--         `compute` you do want all of your elements to be fully evaluated.
--
-- * `S` - Is a type of array that is backed by pinned memory, therefore pointers to those arrays
--         can be passed to FFI calls, because Garbage Collector (GC) is guaranteed not to move
--         it. Elements must be an instance of `Storable` class. It is just as efficient as `P` and
--         `U` arrays, except it is subject to fragmentation.
--
-- * `U` - Unboxed representation. Elements must be an instance of `Unbox` class.
--
-- * `P` - Array that can hold Haskell primitives, such as `Int`, `Word`, `Double`, etc. Any element
--        must be an instance of `Prim` class.
--
-- * `M` - General manifest array type, that any of the above representations can be converted to in
--       constant time using `toManifest`.
--
-- While at the same time, there are arrays that only describe how values for it's elements can be
-- computed, and have no memory overhead on their own.
--
-- * `D` - delayed array that is a mere function from an index to an element. Crucial representation
--         for fusing computation. Use `computeAs` in order to load array into `Manifest`
--         representation.
--
-- * `DI` - delayed interleaved array. Same as `D`, but performced better with unbalanced
--         computation, when evaluation one element takes much longer than it's neighbor.
--
-- * `DW` - delayed windowed array. This peculiar representation allows for very fast `Stencil`
--        computation.
--
-- Other Array types:
--
-- * `L` and `LN` - those types aren't particularly useful on their own, but because of their unique
--       ability to be converted to and from nested lists in constant time, provide an amazing
--       intermediary for list/array conversion.
--
-- Most of the `Manifest` arrays are capable of in-place mutation. Check out
-- "Data.Massiv.Array.Mutable" module for available functionality.
--
-- Many of the function names exported by this package will clash with the ones
-- from "Prelude", hence it can be more convenient to import like this:
--
-- @
-- import Prelude as P
-- import Data.Massiv.Array as A
-- @
--
module Data.Massiv.Array
  ( -- * Construct
    module Data.Massiv.Array.Ops.Construct
  -- * Compute
  , getComp
  , setComp
  , compute
  , computeAs
  , computeProxy
  , computeSource
  , clone
  , convert
  , convertAs
  , convertProxy
  , fromRaggedArray
  , fromRaggedArray'
  -- * Size
  , size
  , Core.elemsCount
  , Core.isEmpty
  -- * Indexing
  , (!?)
  , (!)
  , (??)
  , index
  , index'
  , defaultIndex
  , borderIndex
  , evaluateAt
  -- * Mapping
  , module Data.Massiv.Array.Ops.Map
  -- * Folding

  -- $folding

  , module Data.Massiv.Array.Ops.Fold
  -- * Transforming
  , module Data.Massiv.Array.Ops.Transform
  -- * Slicing
  , module Data.Massiv.Array.Ops.Slice
  -- * Conversion
  , module Data.Massiv.Array.Manifest.List
  -- * Mutable
  , module Data.Massiv.Array.Mutable
  -- * Core
  , module Data.Massiv.Core
  -- * Representations
  , module Data.Massiv.Array.Delayed
  , module Data.Massiv.Array.Manifest
  -- * Stencil
  , module Data.Massiv.Array.Stencil
  , module Data.Massiv.Array.Numeric
  ) where

import           Data.Massiv.Array.Delayed
import           Data.Massiv.Array.Manifest
import           Data.Massiv.Array.Manifest.Internal
import           Data.Massiv.Array.Manifest.List
import           Data.Massiv.Array.Mutable
import           Data.Massiv.Array.Numeric
import           Data.Massiv.Array.Ops.Construct
import           Data.Massiv.Array.Ops.Fold
import           Data.Massiv.Array.Ops.Map
import           Data.Massiv.Array.Ops.Slice
import           Data.Massiv.Array.Ops.Transform
import           Data.Massiv.Array.Stencil
import           Data.Massiv.Core                    hiding (elemsCount,
                                                      isEmpty)
import qualified Data.Massiv.Core                    as Core (elemsCount,
                                                              isEmpty)
import           Data.Massiv.Core.Common
import           Prelude                             as P hiding (all, and, any,
                                                           foldl, foldr, mapM,
                                                           mapM_, maximum,
                                                           minimum, or, product,
                                                           splitAt, sum)
{- $folding

All folding is done in a row-major order.

-}