File: Time.sml

package info (click to toggle)
polyml 5.2.1-1.1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 19,692 kB
  • ctags: 17,567
  • sloc: cpp: 37,221; sh: 9,591; asm: 4,120; ansic: 428; makefile: 203; ml: 191; awk: 91; sed: 10
file content (208 lines) | stat: -rw-r--r-- 7,305 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
(*
    Title:      Standard Basis Library: Time Signature and structure.
    Author:     David Matthews
    Copyright   David Matthews 2000, 2005

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.
	
	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*)

(* G&R 2004 status: updated. *)

signature TIME =
sig
	 eqtype time
     exception Time
     val zeroTime : time
     val fromReal : LargeReal.real -> time
     val toReal : time -> LargeReal.real
     val toSeconds      : time -> LargeInt.int
     val toMilliseconds : time -> LargeInt.int
     val toMicroseconds : time -> LargeInt.int
	 val toNanoseconds  : time -> LargeInt.int
     val fromSeconds      : LargeInt.int -> time
     val fromMilliseconds : LargeInt.int -> time
     val fromMicroseconds : LargeInt.int -> time
     val fromNanoseconds  : LargeInt.int -> time
     val + : time * time -> time
     val - : time * time -> time
     val compare : time * time -> General.order
     val <  : time * time -> bool
     val <= : time * time -> bool
     val >  : time * time -> bool
     val >= : time * time -> bool
     val now : unit -> time
     val fmt : int -> time -> string
     val toString : time -> string
     val fromString : string -> time option
     val scan       : (char, 'a) StringCvt.reader -> (time, 'a) StringCvt.reader
end;

structure Time :> TIME =
struct
	(* Unix and Windows both use 64 bit quantities for times.  Windows
	   uses a 64-bit number of 100ns ticks, Unix uses one word of seconds
	   and another of microseconds.  To handle both easily we use a single
	   arbitrary precision number for times with the actual resolution
	   returned as an RTS call.  The intention is retain as much precision
	   as possible. *)
	type time = int (* Becomes abstract *)
    exception Time

	open RuntimeCalls

	val doTiming: int*int->int = RunCall.run_call2 POLY_SYS_timing_dispatch
	fun callTiming (code: int) args = doTiming (code,args);

	(* Get the number of ticks per microsecond and compute the corresponding
	   values for milliseconds and seconds. *)
	val ticksPerMicrosecond = callTiming 0 0
	val ticksPerMillisecond = ticksPerMicrosecond * 1000
	val ticksPerSecond = ticksPerMillisecond * 1000

	(* Check for very large time values.  These cause problems if
	   converted to dates. *)
	local
		val Years100000 = ticksPerSecond*60*60*24*365*100000
	in
		fun checkTimeValue t =
			if t <  ~ Years100000 orelse t > Years100000
			then raise Time else t
	end;

	(* The real representation is as a number of seconds. *)
	local
		val realTicks = Real.fromInt ticksPerSecond
	in
		fun fromReal (x: real): time = 
			checkTimeValue(Real.round (x * realTicks))
		and toReal (t: time): real = Real.fromInt t / realTicks
	end

	val zeroTime = fromReal 0.0

	(* Convert to seconds, etc.*)
	fun toSeconds x = x div ticksPerSecond
	and toMilliseconds x = x div ticksPerMillisecond
	and toMicroseconds x = x div ticksPerMicrosecond
	and toNanoseconds x = x * 1000 div ticksPerMicrosecond

	(* Convert from the integer representations. *)
	fun fromSeconds i = checkTimeValue(i * ticksPerSecond)
	and fromMilliseconds i = checkTimeValue(i * ticksPerMillisecond)
	and fromMicroseconds i = checkTimeValue(i * ticksPerMicrosecond)
	and fromNanoseconds i = checkTimeValue(i * ticksPerMicrosecond div 1000)

	(* Format as a fixed precision number.  if n < 0 treat as n = 0. *)
	fun fmt n r = Real.fmt (StringCvt.FIX(SOME(Int.max(n, 0)))) (toReal r)
	val toString = fmt 3

	(* The scanned string is a subset of the format of a real number.
	   It does not have an exponent.  At present we convert it as a real
	   number but it would probably be better to treat it as an integer. *)
	fun scan getc src =
	let
		(* Return a list of digits. *)
		fun getdigits inp src =
			case getc src of
				NONE => (List.rev inp, src)
			  | SOME(ch, src') =>
			  		if ch >= #"0" andalso ch <= #"9"
					then getdigits ((Char.ord ch - Char.ord #"0") :: inp) src'
					else (List.rev inp, src)

		fun read_number sign src =
			case getc src of
				NONE => NONE
			  | SOME(ch, src') =>
					if not (ch >= #"0" andalso ch <= #"9" orelse ch = #".")
					then NONE (* Bad "*)
					else (* Digits or decimal. *)
					let
						(* Get the digits before the decimal point (if any) *)
						val (intPart, src'') = getdigits [] src
						(* Get the digits after the decimal point (if any).
						   If there is a decimal point we swallow the decimal only
						   if there is at least one digit after it. *)
						val (decPart, srcAfterMant) =
							case getc src'' of
								SOME (#".", src''') =>
							 		( (* Check that the next character is a digit. *)
									case getc src''' of
										NONE => ([], src'')
									  | SOME(ch, _) =>
									  		if ch >= #"0" andalso ch <= #"9"
											then getdigits [] src'''
											else ([], src'')
									)
							 |  _ => ([], src'')
					in
						case (intPart, decPart) of
							([], []) => NONE (* Must have a digit either before or after the dp. *)
						|	_ =>
						let
							(* Get exactly 9 digits after the decimal point. *)
							val decs = intPart @ (List.take(decPart @ [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], 9));
							(* It's now in nanoseconds. *)
							val toInt = List.foldl (fn (i, j) => i + j*10) 0 decs
						in
							SOME(fromNanoseconds(if sign then ~toInt else toInt), srcAfterMant)
						end
					end
	in
		case getc src of
			NONE => NONE
		 |  SOME(ch, src') =>
		 	if Char.isSpace ch (* Skip white space. *)
			then scan getc src' (* Recurse *)
			else if ch = #"+" (* Remove the + sign *)
			then read_number false src'
			else if ch = #"-" orelse ch = #"~"
			then read_number true src'
			else  (* See if it's a valid digit or decimal point. *)
				read_number false src
	end
	
	val fromString = StringCvt.scanString scan

	(* Use the integer operations for these. *)
    val op < : (time * time) -> bool = Int.<
    val op <= : (time * time) -> bool = Int.<=
    val op > : (time * time) -> bool = Int.>
    val op >= : (time * time) -> bool = Int.>=;

	val compare = Int.compare

    val op + : (time * time) -> time = Int.+
    val op - : (time * time) -> time = Int.-

	fun now () = callTiming 1 0 handle _ => raise Time

end;


local
	(* Install the pretty printer for Time.time.  This has to be
	   done outside the structure because of the opaque matching. *)
	fun pretty(p, _, _, _) _ _ x = p(Time.toString x)
in
	val it = PolyML.install_pp pretty
	(* Add overloads for +, -, <= etc *)
	val it = RunCall.addOverload Time.+ "+";
	val it = RunCall.addOverload Time.- "-";
	val it = RunCall.addOverload Time.< "<";
	val it = RunCall.addOverload Time.> ">";
	val it = RunCall.addOverload Time.<= "<=";
	val it = RunCall.addOverload Time.>= ">=";
end