module Squeeze.Data.FileCombination(
FileCombination(
getAggregateFileSize,
getFilePathList
),
nullFileCombination,
comparingAggregateFileSize,
prepend,
risingFilter,
risingMergeByAggregateFileSize,
mkFileCombination,
singleton,
hasSizeBy
) where
import qualified Data.List
import qualified Data.Ord
import qualified Squeeze.Data.File as Data.File
import qualified ToolShed.Data.Foldable
import qualified ToolShed.SelfValidate
data FileCombination = MkFileCombination {
getAggregateFileSize :: !Data.File.FileSize,
getFilePathList :: Data.File.FilePathList
} deriving Eq
instance Show FileCombination where
showsPrec _ fileCombination = shows (getAggregateFileSize fileCombination) . showChar '\t' . shows (Data.List.sort $ getFilePathList fileCombination)
instance ToolShed.SelfValidate.SelfValidator FileCombination where
getErrors fileCombination = ToolShed.SelfValidate.extractErrors [
(
getAggregateFileSize fileCombination < 0,
"aggregate size must be positive; " ++ show fileCombination
), (
getAggregateFileSize fileCombination /= 0 && null (getFilePathList fileCombination),
"when zero files are specified, the aggregate size must also be zero; " ++ show fileCombination
), let
duplicateFilePaths = map head . filter ((> 1) . length) . ToolShed.Data.Foldable.gather $ getFilePathList fileCombination
in (
not $ null duplicateFilePaths,
"duplicate file-paths have been specified; " ++ show duplicateFilePaths
)
]
nullFileCombination :: FileCombination
nullFileCombination = MkFileCombination 0 []
mkFileCombination :: Data.File.FileSize -> Data.File.FilePathList -> FileCombination
mkFileCombination fileSize filePathList
| ToolShed.SelfValidate.isValid fileCombination = fileCombination
| otherwise = error $ "Squeeze.Data.FileCombination.mkFileCombination:\t" ++ ToolShed.SelfValidate.getFirstError fileCombination
where
fileCombination = MkFileCombination fileSize filePathList
singleton :: Data.File.FileSizeAndPath -> FileCombination
singleton (fileSize, filePath) = mkFileCombination fileSize [filePath]
{-# INLINE prepend #-}
prepend
:: Data.File.FileSizeAndPath
-> FileCombination
-> FileCombination
prepend (fileSize, filePath) MkFileCombination {
getAggregateFileSize = aggregateFileSize,
getFilePathList = filePathList
} = MkFileCombination {
getAggregateFileSize = fileSize + aggregateFileSize,
getFilePathList = filePath : filePathList
}
{-# INLINE hasSizeBy #-}
hasSizeBy
:: (Data.File.FileSize -> Bool)
-> FileCombination
-> Bool
hasSizeBy predicate MkFileCombination { getAggregateFileSize = aggregateFileSize } = predicate aggregateFileSize
risingFilter
:: Data.File.FileSize
-> [FileCombination]
-> [FileCombination]
risingFilter _ [] = []
risingFilter minimumSize (fileCombination@MkFileCombination { getAggregateFileSize = aggregateFileSize } : fileCombinations)
| aggregateFileSize >= minimumSize = fileCombination : risingFilter aggregateFileSize fileCombinations
| otherwise = risingFilter minimumSize fileCombinations
risingMerge
:: (FileCombination -> FileCombination -> Ordering)
-> [FileCombination]
-> [FileCombination]
-> [FileCombination]
risingMerge cmp = slave nullFileCombination where
lessThan bar = (== LT) . (`cmp` bar)
slave bar [] r = dropWhile (lessThan bar) r
slave bar l [] = dropWhile (lessThan bar) l
slave _ (x : xs) (y : ys) = case x `cmp` y of
GT -> x : slave x xs ys
LT -> y : slave y xs ys
_ -> x : y : slave x xs ys
comparingAggregateFileSize :: FileCombination -> FileCombination -> Ordering
comparingAggregateFileSize = Data.Ord.comparing getAggregateFileSize
risingMergeByAggregateFileSize
:: [FileCombination]
-> [FileCombination]
-> [FileCombination]
risingMergeByAggregateFileSize = risingMerge comparingAggregateFileSize