{-| Splittable containers abstraction. -} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} module Data.Splittable ( Split(..) , Combine(..) ) where import Prelude hiding (splitAt) import qualified Prelude as P import qualified Data.ByteString as BS import qualified Data.Vector.Generic as VG -- | Class of tasks (containers which hold input data) which may be -- splitted into subtasks. -- -- 'splitAt' and 'splitIn' must preserve linear ordering on elements -- of task, if there's any. class Split source where -- | Split the source in two subsources given the size of the first source. splitAt :: Int -> source -> (source, source) -- | Calculate the overall size of the source size :: source -> Int splitIn :: Int -- ^ Split the source into that many subsources of equal -- size. This number is capped to the size of source if it -- exceeds it. -> source -> [source] splitIn n l | n < 1 = error "Can't split in less than one chunk!" | n > (size l) = splitIn (size l) l | otherwise = let partSize = (size l) `div` n splitIn1 acc 1 rest = acc ++ [rest] splitIn1 acc m rest = splitIn1 (acc ++ [v1]) (m - 1) v2 where (v1, v2) = splitAt partSize rest in splitIn1 [] n l {-# INLINE splitIn #-} -- | A counterpart for 'Split'. Class of containers which may be -- combined into single container (which holds output data). class Combine result where -- | Combine list of results, preserving linear ordering. combine :: [result] -> result instance Split [s] where splitAt = P.splitAt size = P.length instance Combine [s] where combine = concat instance (VG.Vector v e) => Split (v e) where splitAt = VG.splitAt size = VG.length instance (VG.Vector v e) => Combine (v e) where combine = VG.concat instance Split BS.ByteString where splitAt = BS.splitAt size = BS.length