module Data.Repa.Scalar.Date32
( Date32
, year, month, day
, pack
, unpack
, next
, diffDays
, loadYYYYsMMsDD
, loadDDsMMsYYYY)
where
import Data.Word
import Data.Bits
import GHC.Exts
import GHC.Word
import Foreign.Storable
import Foreign.Ptr
import Control.Monad
import Data.Repa.Scalar.Int
import qualified Data.Time.Calendar as Time
import qualified Foreign.Ptr as F
import qualified Foreign.Storable as F
import Prelude as P
newtype Date32
= Date32 Word32
deriving (Eq, Ord, Show)
instance Storable Date32 where
sizeOf (Date32 w) = sizeOf w
alignment (Date32 w) = alignment w
peek ptr = liftM Date32 (peek (castPtr ptr))
poke ptr (Date32 w) = poke (castPtr ptr) w
{-# INLINE sizeOf #-}
{-# INLINE alignment #-}
{-# INLINE peek #-}
{-# INLINE poke #-}
pack :: (Int, Int, Int) -> Date32
pack (yy, mm, dd)
= Date32
$ ((fromIntegral yy .&. 0x0ffff) `shiftL` 16)
.|. ((fromIntegral mm .&. 0x0ff) `shiftL` 8)
.|. (fromIntegral dd .&. 0x0ff)
{-# INLINE pack #-}
unpack :: Date32 -> (Int, Int, Int)
unpack (Date32 date)
= ( fromIntegral $ (date `shiftR` 16) .&. 0x0ffff
, fromIntegral $ (date `shiftR` 8) .&. 0x0ff
, fromIntegral $ date .&. 0x0ff)
{-# INLINE unpack #-}
year :: Date32 -> Int
year date
= case unpack date of
(yy, _, _) -> yy
{-# INLINE year #-}
month :: Date32 -> Int
month date
= case unpack date of
(_, mm, _) -> mm
{-# INLINE month #-}
day :: Date32 -> Int
day date
= case unpack date of
(_, _, dd) -> dd
{-# INLINE day #-}
next :: Date32 -> Date32
next (Date32 (W32# date))
= Date32 (W32# (next' date))
{-# INLINE next #-}
next' :: Word# -> Word#
next' !date
| (yy, mm, dd) <- unpack (Date32 (W32# date))
, (yy', mm', dd')
<- case mm of
1 -> if dd >= 31 then (yy, 2, 1) else (yy, mm, dd + 1)
2 -> if yy `mod` 4 == 0
then if dd >= 29
then (yy, 3, 1)
else (yy, mm, dd + 1)
else if dd >= 28
then (yy, 3, 1)
else (yy, mm, dd + 1)
3 -> if dd >= 31 then (yy, 4, 1) else (yy, mm, dd + 1)
4 -> if dd >= 30 then (yy, 5, 1) else (yy, mm, dd + 1)
5 -> if dd >= 31 then (yy, 6, 1) else (yy, mm, dd + 1)
6 -> if dd >= 30 then (yy, 7, 1) else (yy, mm, dd + 1)
7 -> if dd >= 31 then (yy, 8, 1) else (yy, mm, dd + 1)
8 -> if dd >= 31 then (yy, 9, 1) else (yy, mm, dd + 1)
9 -> if dd >= 30 then (yy, 10, 1) else (yy, mm, dd + 1)
10 -> if dd >= 31 then (yy, 11, 1) else (yy, mm, dd + 1)
11 -> if dd >= 30 then (yy, 12, 1) else (yy, mm, dd + 1)
12 -> if dd >= 31 then (yy + 1, 1, 1) else (yy, mm, dd + 1)
_ -> (0, 0, 0)
= case pack (yy', mm', dd') of
Date32 (W32# w) -> w
{-# NOINLINE next' #-}
diffDays :: Date32 -> Date32 -> Integer
diffDays date1 date2
| (y1, m1, d1) <- unpack date1
, (y2, m2, d2) <- unpack date2
= Time.diffDays
(Time.fromGregorian (fromIntegral y1) m1 d1)
(Time.fromGregorian (fromIntegral y2) m2 d2)
loadYYYYsMMsDD
:: Word8
-> Ptr Word8
-> Int
-> IO (Maybe (Date32, Int))
loadYYYYsMMsDD !sep !buf (I# len_)
= loadYear
where loadYear
| 1# <- 4# <=# len_
, (# 1#, yy, ix' #) <- loadInt' buf 4#
= sep1 ix' yy
| otherwise = return Nothing
sep1 ix yy
| 1# <- (ix +# 1#) <=# len_
= F.peekByteOff buf (I# ix) >>= \(r :: Word8)
-> if r == sep
then loadMonth (ix +# 1#) yy
else return Nothing
| otherwise = return Nothing
loadMonth ix yy
| 1# <- (ix +# 2#) <=# len_
, (# 1#, mm, o #) <- loadInt' (buf `F.plusPtr` (I# ix)) 2#
= sep2 (ix +# o) yy mm
| otherwise = return Nothing
sep2 ix yy mm
| 1# <- (ix +# 1#) <=# len_
= F.peekByteOff buf (I# ix) >>= \(r :: Word8)
-> if r == sep
then loadDay (ix +# 1#) yy mm
else return Nothing
| otherwise = return Nothing
loadDay ix yy mm
| 1# <- (ix +# 2#) <=# len_
, (# 1#, dd, o #) <- loadInt' (buf `F.plusPtr` (I# ix)) 2#
= return
$ Just (pack ( fromIntegral (I# yy)
, fromIntegral (I# mm)
, fromIntegral (I# dd))
, I# (ix +# o))
| otherwise = return Nothing
{-# NOINLINE loadYYYYsMMsDD #-}
loadDDsMMsYYYY
:: Word8
-> Ptr Word8
-> Int
-> IO (Maybe (Date32, Int))
loadDDsMMsYYYY !sep !buf (I# len_)
= loadDay
where loadDay
| 1# <- 2# <=# len_
, (# 1#, dd, o #) <- loadInt' buf 2#
= sep1 o dd
| otherwise = return Nothing
sep1 ix dd
| 1# <- (ix +# 1#) <=# len_
= F.peekByteOff buf (I# ix) >>= \(r :: Word8)
-> if r == sep
then loadMonth (ix +# 1#) dd
else return Nothing
| otherwise = return Nothing
loadMonth ix dd
| 1# <- (ix +# 2#) <=# len_
, (# 1#, mm, o #) <- loadInt' (buf `F.plusPtr` (I# ix)) 2#
= sep2 (ix +# o) dd mm
| otherwise = return Nothing
sep2 ix dd mm
| 1# <- (ix +# 1#) <=# len_
= F.peekByteOff buf (I# ix) >>= \(r :: Word8)
-> if r == sep
then loadYear (ix +# 1#) dd mm
else return Nothing
| otherwise = return Nothing
loadYear ix dd mm
| 1# <- (ix +# 4#) <=# len_
, (# 1#, yy, o #) <- loadInt' (buf `F.plusPtr` (I# ix)) 4#
= return
$ Just (pack ( fromIntegral (I# yy)
, fromIntegral (I# mm)
, fromIntegral (I# dd))
, I# (ix +# o))
| otherwise = return Nothing
{-# NOINLINE loadDDsMMsYYYY #-}
loadInt' (Ptr addr) len
= loadInt# addr len
{-# INLINE loadInt' #-}