on c3dcabc help sign in
150 lines 5.1 kB history raw
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE ScopedTypeVariables #-}
4{-# OPTIONS_GHC -Wno-identities #-}
6#ifndef __GHCJS__
7#include "config.h"
8#endif
10#include "Streamly/Internal/Data/Time/config-clock.h"
12-- |
13-- Module : Streamly.Internal.Data.Time.TimeSpec
14-- Copyright : (c) 2019 Composewell Technologies
15-- License : BSD3
16-- Maintainer : streamly@composewell.com
17-- Stability : experimental
18-- Portability : GHC
20module Streamly.Internal.Data.Time.TimeSpec
21 (
22 TimeSpec(..)
23 )
24where
26import Data.Int (Int64)
27import Foreign.Storable (Storable(..), peek)
29#ifdef HS_CLOCK_GHCJS
30import Foreign.C (CTime(..), CLong(..))
31#endif
33-------------------------------------------------------------------------------
34-- Some constants
35-------------------------------------------------------------------------------
37{-# INLINE tenPower9 #-}
38tenPower9 :: Int64
39tenPower9 = 1000000000
41-------------------------------------------------------------------------------
42-- TimeSpec representation
43-------------------------------------------------------------------------------
45-- A structure storing seconds and nanoseconds as 'Int64' is the simplest and
46-- fastest way to store practically large quantities of time with efficient
47-- arithmetic operations. If we store nanoseconds using 'Integer' it can store
48-- practically unbounded quantities but it may not be as efficient to
49-- manipulate in performance critical applications. XXX need to measure the
50-- performance.
51--
52-- | Data type to represent practically large quantities of time efficiently.
53-- It can represent time up to ~292 billion years at nanosecond resolution.
54data TimeSpec = TimeSpec
55 { sec :: {-# UNPACK #-} !Int64 -- ^ seconds
56 , nsec :: {-# UNPACK #-} !Int64 -- ^ nanoseconds
57 } deriving (Eq, Read, Show)
59-- We assume that nsec is always less than 10^9. When TimeSpec is negative then
60-- both sec and nsec are negative.
61instance Ord TimeSpec where
62 compare (TimeSpec s1 ns1) (TimeSpec s2 ns2) =
63 if s1 == s2
64 then compare ns1 ns2
65 else compare s1 s2
67-- make sure nsec is less than 10^9
68{-# INLINE addWithOverflow #-}
69addWithOverflow :: TimeSpec -> TimeSpec -> TimeSpec
70addWithOverflow (TimeSpec s1 ns1) (TimeSpec s2 ns2) =
71 let nsum = ns1 + ns2
72 (s', ns) = if nsum > tenPower9 || nsum < negate tenPower9
73 then nsum `divMod` tenPower9
74 else (0, nsum)
75 in TimeSpec (s1 + s2 + s') ns
77-- make sure both sec and nsec have the same sign
78{-# INLINE adjustSign #-}
79adjustSign :: TimeSpec -> TimeSpec
80adjustSign t@(TimeSpec s ns)
81 | s > 0 && ns < 0 = TimeSpec (s - 1) (ns + tenPower9)
82 | s < 0 && ns > 0 = TimeSpec (s + 1) (ns - tenPower9)
83 | otherwise = t
85{-# INLINE timeSpecToInteger #-}
86timeSpecToInteger :: TimeSpec -> Integer
87timeSpecToInteger (TimeSpec s ns) = toInteger $ s * tenPower9 + ns
89instance Num TimeSpec where
90 {-# INLINE (+) #-}
91 t1 + t2 = adjustSign (addWithOverflow t1 t2)
93 -- XXX will this be more optimal if imlemented without "negate"?
94 {-# INLINE (-) #-}
95 t1 - t2 = t1 + negate t2
96 t1 * t2 = fromInteger $ timeSpecToInteger t1 * timeSpecToInteger t2
98 {-# INLINE negate #-}
99 negate (TimeSpec s ns) = TimeSpec (negate s) (negate ns)
100 {-# INLINE abs #-}
101 abs (TimeSpec s ns) = TimeSpec (abs s) (abs ns)
102 {-# INLINE signum #-}
103 signum (TimeSpec s ns) | s == 0 = TimeSpec (signum ns) 0
104 | otherwise = TimeSpec (signum s) 0
105 -- This is fromNanoSecond64 Integer
106 {-# INLINE fromInteger #-}
107 fromInteger nanosec = TimeSpec (fromInteger s) (fromInteger ns)
108 where (s, ns) = nanosec `divMod` toInteger tenPower9
110#if HS_CLOCK_POSIX
111#include <time.h>
112#endif
114#ifdef HS_CLOCK_GHCJS
115instance Storable TimeSpec where
116 sizeOf _ = 8
117 alignment _ = 4
118 peek p = do
119 CTime s <- peekByteOff p 0
120 CLong ns <- peekByteOff p 4
121 return (TimeSpec (fromIntegral s) (fromIntegral ns))
122 poke p (TimeSpec s ns) = do
123 pokeByteOff p 0 ((fromIntegral s) :: CTime)
124 pokeByteOff p 4 ((fromIntegral ns) :: CLong)
126#elif HS_CLOCK_WINDOWS
127instance Storable TimeSpec where
128 sizeOf _ = sizeOf (undefined :: Int64) * 2
129 alignment _ = alignment (undefined :: Int64)
130 peek ptr = do
131 s <- peekByteOff ptr 0
132 ns <- peekByteOff ptr (sizeOf (undefined :: Int64))
133 return (TimeSpec s ns)
134 poke ptr ts = do
135 pokeByteOff ptr 0 (sec ts)
136 pokeByteOff ptr (sizeOf (undefined :: Int64)) (nsec ts)
137#else
138instance Storable TimeSpec where
139 sizeOf _ = #{size struct timespec}
140 alignment _ = #{alignment struct timespec}
141 peek ptr = do
142 s :: #{type time_t} <- #{peek struct timespec, tv_sec} ptr
143 ns :: #{type long} <- #{peek struct timespec, tv_nsec} ptr
144 return $ TimeSpec (fromIntegral s) (fromIntegral ns)
145 poke ptr ts = do
146 let s :: #{type time_t} = fromIntegral $ sec ts
147 ns :: #{type long} = fromIntegral $ nsec ts
148 #{poke struct timespec, tv_sec} ptr (s)
149 #{poke struct timespec, tv_nsec} ptr (ns)
150#endif