module Monky.Utility
( readValue
, readValues
, fopen
, fclose
, File
, readLine
, readContent
, findLine
, splitAtEvery
, maybeOpenFile
, sdivBound
, sdivUBound
, listDirectory
)
where
import System.IO
import Data.List (isPrefixOf)
import Data.Maybe (fromMaybe)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS
#if MIN_VERSION_base(4,9,0)
import System.Directory (listDirectory)
#else
import System.Directory (getDirectoryContents)
listDirectory :: String -> IO [String]
listDirectory = fmap (filter (not . ("." `isPrefixOf`))) . getDirectoryContents
#endif
class LineReadable a where
hGetReadable :: Handle -> IO a
instance LineReadable String where
hGetReadable = hGetLine
instance LineReadable ByteString where
hGetReadable = BS.hGetLine
class FileReadable a where
hGetFile :: Handle -> IO [a]
instance FileReadable String where
hGetFile = readStringLines
instance FileReadable ByteString where
hGetFile = readBSLines
newtype File = File Handle deriving (Show, Eq)
findLine :: Eq a => [a] -> [[a]] -> Maybe [a]
findLine y (x:xs) = if y `isPrefixOf` x
then Just x
else findLine y xs
findLine _ [] = Nothing
readValue :: File -> IO Int
readValue (File h) = do
hSeek h AbsoluteSeek 0
line <- hGetReadable h
let value = fmap fst $ BS.readInt line
return . fromMaybe (error ("Failed to read value from file:" ++ show h)) $ value
readValues :: File -> IO [Int]
readValues (File h) = do
hSeek h AbsoluteSeek 0
line <- hGetReadable h
let value = mapM (fmap fst . BS.readInt) $ BS.words line
return . fromMaybe (error ("Failed to read values from file:" ++ show h)) $ value
readLine :: LineReadable a => File -> IO a
readLine (File h) = do
hSeek h AbsoluteSeek 0
hGetReadable h
readStringLines :: Handle -> IO [String]
readStringLines h = do
eof <- hIsEOF h
if eof
then return []
else do
l <- hGetReadable h
fmap (l:) $ readStringLines h
readBSLines :: Handle -> IO [ByteString]
readBSLines h = fmap (BS.lines . BS.concat) $ readLines' []
where
readLines' ls = do
ret <- BS.hGet h 512
if ret == BS.empty
then return $ reverse ls
else readLines' (ret:ls)
readContent :: FileReadable a => File -> IO [a]
readContent (File h) = do
hSeek h AbsoluteSeek 0
hGetFile h
fopen :: String -> IO File
fopen = fmap File . flip openFile ReadMode
fclose :: File -> IO ()
fclose (File h) = hClose h
splitAtEvery :: String -> String -> [String]
splitAtEvery s str = splitAtEvery' s str []
where splitAtEvery' _ [] zs = [zs]
splitAtEvery' xs (y:ys) zs = if xs `isPrefixOf` (y:ys)
then zs:splitAtEvery' xs (cut ys) []
else splitAtEvery' xs ys (zs ++ [y])
where cut = drop (length xs 1)
maybeOpenFile :: Maybe String -> IO (Maybe File)
maybeOpenFile Nothing = return Nothing
maybeOpenFile (Just x) = fmap Just . fopen $ x
sdivBound :: (Integral a, Bounded a) => a -> a -> a
sdivBound _ 0 = maxBound
sdivBound x y = x `div` y
sdivUBound :: Integral a => a -> a -> a -> a
sdivUBound _ 0 d = d
sdivUBound x y _ = x `div` y
infixl 7 `sdivBound`, `sdivUBound`