{-# LANGUAGE CPP, BangPatterns, NoImplicitPrelude #-} {-# OPTIONS_HADDOCK show-extensions #-} {-# OPTIONS_GHC -funbox-strict-fields #-} -- | -- Module : Data.Foldable.Ix -- Copyright : (c) OleksandrZhabenko 2020-2023 -- License : MIT -- Stability : Experimental -- Maintainer : oleksandr.zhabenko@yahoo.com -- -- module Data.Foldable.Ix where import Data.Foldable import GHC.Base hiding (foldr, foldl') import GHC.Num import GHC.Real import GHC.List (take, drop, reverse) data OneInTwoBang a b = B12 !a !b deriving Eq data ThreeInFourBang a b = B34 b !b ![a] deriving Eq {-| Function to find out the \'index\' (as the reperesentative of the 'Integral' class) of the first element in the 'Foldable' structure (from the left with indices starting from 0), which equals to the first argument. Returns 'Nothing' if there are no such elements. -} findIdx1 :: (Eq a, Foldable t, Integral b) => a -> t a -> Maybe b findIdx1 x js = (\(B12 n1 _) -> if n1 == (-1) then Nothing else Just n1) . foldl' f v \$ js where v = B12 (-1) 0 f (B12 n m) !y | n >= 0 = B12 n (m + 1) | y == x = B12 m (m + 1) | otherwise = B12 n (m + 1) {-# SPECIALIZE findIdx1 :: (Eq a, Foldable t) => a -> t a -> Maybe Int #-} findIdx1' :: (Eq a, Foldable t) => a -> t a -> Maybe Int findIdx1' = findIdx1 {-| Function to find out the \'indices\' of the elements in the 'Foldable' structure (from the left with indices starting from 0) that equal to the first argument. Returns empty list if there are no such elements. Uses two passes through the structure. -} findIdxs :: (Eq a, Foldable t) => a -> t a -> [Int] findIdxs x js = (\(B12 ys _) -> ys) . foldr f v \$ js where v = B12 [] (length js - 1) f y (B12 xs m) | y == x = B12 (m:xs) (m - 1) | otherwise = B12 xs (m - 1) {-| Function to find out the \'indices\' of the elements in the 'Foldable' structure (from the left with indices starting from 0) that equal to the first argument. Returns empty list if there are no such elements. Uses just one pass through the structure and additional 'reverse' operation on the resulting list with 'foldl''. -} findIdxsL1 :: (Eq a, Foldable t) => a -> t a -> [Int] findIdxsL1 x js = (\(B12 ys _) -> reverse ys) . foldl' f v \$ js where v = B12 [] 0 f (B12 xs m) !y | y == x = B12 (m:xs) (m + 1) | otherwise = B12 xs (m + 1) {-| Inspired by the Data.Vector.slice function from the @vector@ package. Takes a \'slice\' for the 'Foldable' structure converting it to the list. The first argument is the \'index\' of the element in the structure starting from 0 from the left. The second one is the length of the slice. -} sliceToList :: (Eq a, Foldable t) => Int -> Int -> t a -> [a] sliceToList idx l js = (\(B34 _ _ ys) -> reverse ys) . foldl' f v \$ js where v = B34 l 0 [] f (B34 l i xs) x | i >= idx && i <= idx + l - 1 = B34 l (i+1) (x:xs) | otherwise = B34 l (i+1) xs {-# SPECIALIZE sliceToList :: (Eq a) => Int -> Int -> [a] -> [a] #-} {-# NOINLINE[2] sliceToList #-} {-# RULES "sliceToList/lists" sliceToList = s2L #-} s2L :: (Eq a) => Int -> Int -> [a] -> [a] s2L idx l = drop idx . take (idx + l) {-# INLINABLE s2L #-}