darcswatch-0.3: src/ByteStringUtils.hs
{-# LANGUAGE BangPatterns, ForeignFunctionInterface, CPP, ScopedTypeVariables #-}
-----------------------------------------------------------------------------
-- |
-- Module : ByteStringUtils
-- Copyright : (c) The University of Glasgow 2001,
-- David Roundy 2003-2005
-- License : GPL (I'm happy to also license this file BSD style but don't
-- want to bother distributing two license files with darcs.
--
-- Maintainer : droundy@abridgegame.org
-- Stability : experimental
-- Portability : portable
--
-- GZIp and MMap IO for ByteStrings, and miscellaneous functions for Data.ByteString
--
module ByteStringUtils (
unsafeWithInternals,
linesPS
) where
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString.Internal as BI
import Data.Word ( Word8 )
import Foreign.Ptr ( plusPtr, Ptr )
import Foreign.ForeignPtr ( withForeignPtr )
-- -----------------------------------------------------------------------------
-- unsafeWithInternals
-- | Do something with the internals of a PackedString. Beware of
-- altering the contents!
unsafeWithInternals :: B.ByteString -> (Ptr Word8 -> Int -> IO a) -> IO a
unsafeWithInternals ps f
= case BI.toForeignPtr ps of
(fp,s,l) -> withForeignPtr fp $ \p -> f (p `plusPtr` s) l
-- TODO: rename
{-# INLINE linesPS #-}
linesPS :: B.ByteString -> [B.ByteString]
linesPS ps
| B.null ps = [B.empty]
| otherwise = BC.split '\n' ps
{- QuickCheck property:
import Test.QuickCheck
import qualified Data.ByteString.Char8 as BC
import Data.Char
instance Arbitrary BC.ByteString where
arbitrary = fmap BC.pack arbitrary
instance Arbitrary Char where
arbitrary = chr `fmap` choose (32,127)
deepCheck = check (defaultConfig { configMaxTest = 10000})
testLines = deepCheck (\x -> (linesPS x == linesPSOld x))
linesPSOld ps = case BC.elemIndex '\n' ps of
Nothing -> [ps]
Just n -> B.take n ps : linesPS (B.drop (n+1) ps) -}
{-| This function acts exactly like the "Prelude" unlines function, or like
"Data.ByteString.Char8" 'unlines', but with one important difference: it will
produce a string which may not end with a newline! That is:
> unlinesPS ["foo", "bar"]
evaluates to \"foo\\nbar\", not \"foo\\nbar\\n\"! This point should hold true for
'linesPS' as well.
TODO: rename this function. -}
unlinesPS :: [B.ByteString] -> B.ByteString
unlinesPS [] = BC.empty
unlinesPS x = BC.init $ BC.unlines x
{-# INLINE unlinesPS #-}
{- QuickCheck property:
testUnlines = deepCheck (\x -> (unlinesPS x == unlinesPSOld x))
unlinesPSOld ss = BC.concat $ intersperse_newlines ss
where intersperse_newlines (a:b:s) = a : newline : intersperse_newlines (b:s)
intersperse_newlines s = s
newline = BC.pack "\n" -}