module Bio.PDB.EventParser.FastParse(strtof, trim, trimFront)
where
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Internal as BSI
import qualified Data.ByteString.Unsafe as BSU
import GHC.Base(Char(..), Int(..))
import GHC.Prim
ord :: Char -> Int
ord (C# c#) = I# (ord# c#)
strtof :: BS.ByteString -> Maybe Double
strtof bs | BS.null bs = Nothing
strtof bs = case chr of
'-' -> strtof0 True 0 rest
_ | dv >= 0 && dv <= 9 -> strtof0 False dv rest
' ' -> strtof rest
_ -> Nothing
where chr = BSI.w2c $ BSU.unsafeHead bs
dv = digitValue chr
rest = BSU.unsafeTail bs
digitValue :: Char -> Int
digitValue !c = ord c ord '0'
final :: Bool -> Double -> Maybe Double
final !sign !f = if sign then Just (f) else Just f
strtof0 :: Bool -> Int -> BS.ByteString -> Maybe Double
strtof0 !sign !f !bs | BS.null bs = final sign (fromIntegral f :: Double)
strtof0 sign f bs = case chr of _ | dv >= 0 && dv <= 9 -> strtof0 sign (10 * f + dv) rest
'.' -> strtof1 sign 0 f rest
_ -> Nothing
where chr = BSI.w2c $ BSU.unsafeHead bs
rest = BSU.unsafeTail bs
dv = digitValue chr
strtof1 :: Bool -> Int -> Int -> BS.ByteString -> Maybe Double
strtof1 !sign !e !f !bs | BS.null bs = makeDouble sign e f
strtof1 sign e f bs = case chr of
_ | dv >= 0 && dv <= 9 -> strtof1 sign (e+1) (f*10 + dv) rest
' ' -> fs `seq` checkSpaces fs rest
_ -> Nothing
where chr = BSI.w2c $ BSU.unsafeHead bs
dv = digitValue chr
fs = makeDouble sign e f
rest = BSU.unsafeTail bs
makeDouble !sign !e !f = final sign (fromIntegral f * 0.1 ** fromIntegral e)
checkSpaces :: Maybe a -> BS.ByteString -> Maybe a
checkSpaces !result !blanks = if BS.all (==' ') blanks then result else Nothing
trimFront !s | BS.null s = s
trimFront !s = if BSU.unsafeHead s == 32
then trimFront $ BSU.unsafeTail s
else s
trimRear !s | BS.null s = s
trimRear !s = if BSU.unsafeIndex s (BS.length s 1) == 32
then trimRear $ butlast s
else s
butlast (BSI.PS fp o l) = BSI.PS fp o (l1)
trim !s = trimRear $ trimFront s