{-# LANGUAGE CPP #-}
module Data.RangeMin.Vector (
	unsafeVecRangeMinBy,
	unsafeVecRangeMin,
	unsafeVecRangeMax,
	vecRangeMinBy,
	vecRangeMin,
	vecRangeMax) where

import Data.RangeMin.Common
import Data.RangeMin.Int
import Data.RangeMin.Cartesian.Spec

import qualified Data.Vector.Generic as G

#define vec ('PV.fromList' [0,7,-10,4,5,4])

#define cmp (\\ i j -> 'abs' i '>=' 'abs' j)
{-# INLINE [1] unsafeVecRangeMinBy #-}
-- | /O(n)/.  Returns a range-min function on the vector, under the specified ordering.
-- The returned function /does not/ do bounds checks; see 'unsafeIntRangeMin' for details.
-- 
-- Example:
-- 
-- @
-- -- Finding the element with the /largest absolute value/ in a subrange.
-- 'unsafeVecRangeMinBy' cmp vec 0 6 == 2
-- 'unsafeVecRangeMinBy' cmp vec 2 3 == 2
-- 'unsafeVecRangeMinBy' cmp vec 3 3 == 4
-- @
-- 
unsafeVecRangeMinBy :: G.Vector v a => 
	LEq a		-- ^ A total ordering on the type @a@.
	-> v a		-- ^ A vector of elements of type @a@.
	-> RangeMin	-- ^ A range-min function on the vector which runs in /O(1)/.

{-# INLINE unsafeVecRangeMin #-}
-- | /O(n)/.  Equivalent to @'unsafeVecRangeMinBy' ('<=')@.  Specialized for instances of 'Injective'.
-- The returned function /does not/ do bounds checks; see 'unsafeIntRangeMin' for details.
-- 
-- Example:
-- 
-- @
-- -- In reality, these would be rewritten into calls to 'unsafeIntRangeMin', since 'Char' is an
-- -- instance of 'Injective'.
-- 'unsafeVecRangeMin' ('PV.fromList' \"banana\") 0 6 == 1
-- 'unsafeVecRangeMin' ('PV.fromList' \"banana\") 1 1 == 1
-- 'unsafeVecRangeMin' ('PV.fromList' \"banana\") 3 3 == 3
-- @
unsafeVecRangeMin :: (G.Vector v a, Ord a) => 
	v a		-- ^ A vector of elements of type @a@.
	-> RangeMin	-- ^ A range-min function (under the natural ordering)
			-- on the vector which runs in /O(1)/.

{-# INLINE unsafeVecRangeMax #-}
-- | /O(n)/.  Equivalent to @'unsafeVecRangeMinBy' ('>=')@.  Specialized for instances of 'Injective'.
-- The returned function /does not/ do bounds checks; see 'unsafeIntRangeMin' for details.
-- 
-- Example:
-- 
-- @
-- -- In reality, these would be rewritten into calls to 'unsafeIntRangeMin', since 'Char'
-- -- is an instance of 'Injective'.
-- 'unsafeVecRangeMax' ('PV.fromList' \"banana\") 0 6 == 2
-- 'unsafeVecRangeMax' ('PV.fromList' \"banana\") 1 1 == 1
-- 'unsafeVecRangeMax' ('PV.fromList' \"banana\") 3 3 == 4
-- @
unsafeVecRangeMax :: (G.Vector v a, Ord a) => 
	v a		-- ^ A vector of elements of type @a@.
	-> RangeMin	-- ^ A range-max function (under the natural ordering)
			-- on the vector which runs in /O(1)/.

{-# INLINE [1] vecRangeMinBy #-}
-- | /O(n)/.  Returns a range-min function on the vector, under the specified ordering.
-- The returned function /does/ do bounds checks; see 'intRangeMin' for details.
vecRangeMinBy :: G.Vector v a =>
	LEq a		-- ^ A total ordering on the type @a@.
	-> v a		-- ^ A vector of elements of type @a@.
	-> RangeMin	-- ^ A range-min function on the vector which runs in /O(1)/.

{-# INLINE vecRangeMin #-}
-- | /O(n)/.  Equivalent to @'vecRangeMinBy' ('<=')@; a safer version of 'unsafeVecRangeMin'.
-- Specialized for instances of 'Injective'.  The returned function /does/ do bounds checks; see 'intRangeMin' for details.
vecRangeMin :: (G.Vector v a, Ord a) =>
	v a		-- ^ A vector of elements of type @a@.
	-> RangeMin	-- ^ A range-min function (under the natural ordering)
			-- on the vector which runs in /O(1)/.

{-# INLINE vecRangeMax #-}
-- | /O(n)/.  Equivalent to @'vecRangeMinBy' ('>=')@; a safer version of 'unsafeVecRangeMax'.
-- Specialized for instances of 'Injective'. The returned function /does/ do bounds checks; see 'intRangeMin' for details.
vecRangeMax :: (G.Vector v a, Ord a) =>
	v a		-- ^ A vector of elements of type @a@.
	-> RangeMin	-- ^ A range-max function (under the natural ordering)
			-- on the vector which runs in /O(1)/.

unsafeVecRangeMinBy (<=?) xs = unsafeIntRangeMin (equivVectorBy (<=?) xs)
unsafeVecRangeMin xs = unsafeIntRangeMin (equivVectorMin xs)
unsafeVecRangeMax xs = unsafeIntRangeMin (equivVectorMax xs)
vecRangeMinBy (<=?) xs = intRangeMin (equivVectorBy (<=?) xs)
vecRangeMin xs = intRangeMin (equivVectorMin xs)
vecRangeMax xs = intRangeMin (equivVectorMax xs)