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