File: LibrarySupport.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 (257 lines) | stat: -rw-r--r-- 8,986 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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
(*
    Title:      Standard Basis Library: Support functions
    Copyright   David C.J. Matthews 2000

	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
*)

(* We need to execute these calls BEFORE compiling LibrarySupport if
   we want them to be compiled in as constants. *)
structure MachineConstants =
struct
	val bigEndian : bool = RunCall.run_call0 RuntimeCalls.POLY_SYS_is_big_endian ();
	val wordSize : word = RunCall.run_call0 RuntimeCalls.POLY_SYS_bytes_per_word ();
end;

structure LibrarySupport :>
sig
	eqtype address (* eqtype so we can compare vectors. *)
	structure CharArray:
		sig
		datatype array = Array of word*address
		end
	structure Word8Array:
		sig
		datatype array = Array of word*address
		datatype vector = Vector of address
		val toString: address -> string
		and fromString: string -> address
		end
	val wordSize: word
	val bigEndian: bool
	val allocString: word -> string (* Create a mutable string. *)
	val allocBytes: word -> address
	val unsafeStringSub: string*word -> char
	val unsafeSubstring: string*word*word -> string
	val stringImplode: char list -> string
	val stringExplode: string * word * word -> char list
	val isShortString   : string -> bool
	val isShortInt   	: int -> bool
	val unsignedShortOrRaiseSize: int -> word
	val unsignedShortOrRaiseSubscript: int -> word
	val sizeAsWord		: string -> word
end
=
struct
	type address = string
	(* Provide the implementation of CharArray.array, Word8Array.array
	   and Word8Array.vector (= Word8Vector.vector) here so that they
	   are available to the IO routines. *)
	structure CharArray =
	struct
		datatype array = Array of word*address
	end
	structure Word8Array =
	struct
		(* Using the Vector and Array constructors here does not add any overhead since they are compiled
		   as identity functions.  We need to use a datatype, though, in order to hide the representation.
		   This is because we can't use opaque matching because we want to make use of the internal
		   representation in the IO structures. *)
		datatype array = Array of word*address
		and		 vector = Vector of address
	    fun toString s = s
		fun fromString s = s
	end

	open RuntimeCalls; (* for POLY_SYS and EXC numbers *)
	open MachineConstants;
	(* If a vector/string is short (i.e. has an integer tag) it must be the character
	   itself rather than a pointer to a segment. *)
	val isShortString: string -> bool = RunCall.run_call1 POLY_SYS_is_short

	local
		val F_mutable_bytes : word = 0wx41;
		val byteMask : word =  0w255;
		val System_alloc: word*word*word->string  =
			RunCall.run_call3 POLY_SYS_alloc_store

		val System_setb: string * word * char -> unit =
			RunCall.run_call3 POLY_SYS_assign_byte;

		val System_lock: string -> unit =
			RunCall.run_call1 POLY_SYS_lockseg;

		val System_loadb: string*word->char =
			RunCall.run_call2 POLY_SYS_load_byte;

		val And: word * word -> word =
		    RunCall.run_call2 POLY_SYS_and_word;

		val SetLengthWord: string * word -> unit =
		    RunCall.run_call2 POLY_SYS_set_string_length;
		  
		val MemMove: string*word*string*word*word -> unit = 
			RunCall.run_call5 POLY_SYS_move_bytes

		val >> : word * word -> word = 
		    RunCall.run_call2 POLY_SYS_shift_right_word;

		infix >> And;

		val maxString = 
			RunCall.run_call2 RuntimeCalls.POLY_SYS_process_env (101, ())

		(* These two functions are used to convert between single character
		   strings and the character representation. *)
		val vecAsChar: string->char = RunCall.unsafeCast
		val charAsVec: char->string = RunCall.unsafeCast
	in

		val isShortInt: int -> bool = RunCall.run_call1 POLY_SYS_is_short

		(* The length of a string is always a short integer so we
		   can simply cast the result of "size". *)
		fun sizeAsWord(s: string) : word = RunCall.unsafeCast (size s)

		fun unsignedShortOrRaiseSize (i: int): word =
			if isShortInt i andalso i >= 0
			then RunCall.unsafeCast i
			else raise Size

		fun unsignedShortOrRaiseSubscript (i: int): word =
			if isShortInt i andalso i >= 0
			then RunCall.unsafeCast i
			else raise Subscript

		fun allocBytes bytes : address =
			let
				val words : word =
					if bytes = 0w0
					then 0w1 (* Zero-sized objects are not allowed. *)
					else if bytes > maxString
					(* The maximum string size is slightly smaller than the
					   maximum array size because strings have a length word.
					   That means that System_alloc will not raise Size if "bytes"
					   size is between maxString and maxString+3. It seems best to
					   use the same maximum size for CharArray/Word8Array and
					   for String/Word8Vector so we need to check here. *) 
					then raise Size
					else (bytes + wordSize - 0w1) div wordSize
			in
				System_alloc(words, F_mutable_bytes, 0w0)
			end

		(* Allocate store for the string and set the first word to contain
		   the length and the rest zero. *)
		fun allocString charsW =
			let
				(* The space is the number of characters plus space for the length word
				   plus rounding. *)
				val words : word = (charsW + 0w2 * wordSize - 0w1) div wordSize
				(* We are relying on the allocator initialising the store
				   since we only copy as many bytes as we have in the string,
				   possibly leaving bytes in the last word unset.  Generally that
				   wouldn't be a problem, since we will use the string length word
				   to find out how many real characters there are, except in the
				   case of the structure equality function.  It uses the
				   segment length word and compares the whole of each word
				   so we must ensure that two equal strings are equal in every
				   WORD including any unused bytes at the end.
				   It might be faster if we didn't want to initialise every
				   byte to simply zero the last word of the segment. *)
				val vec = 
					System_alloc(words, F_mutable_bytes, 0w0) handle Range => raise General.Size
			in
				(* Set the length word.  Since this is untagged we can't simply
				   use assign_word.*)
				SetLengthWord(vec, charsW);
				vec
			end

		(* We need implode in StringCvt so we define it here rather
		   than in String. *)
		fun stringImplode [] : string = ""
		  | stringImplode (L as (H::_)) =
			let
				(* How many characters do we have to implode? *)
				val listLength = length L
				(* In practice we could never make a list with a
				   combined length which was a long integer but
				   we still check it here in unsignedShortOrRaiseSize. *)
				val chars: word = unsignedShortOrRaiseSize listLength
			in
				if chars = 0w1 then str H
		    	else let
					val dest = allocString chars;
		  
					fun copy (i, []:char list) = ()
					  | copy (i, H :: T) =
						(
			            System_setb (dest, i, H);
			            copy (i + 0w1, T)
						)
				in
					copy (wordSize, L);
					System_lock dest; (* reset mutable flag *)
					dest
				end
			end

		(* We use stringExplode in String and Substring. *)
		fun stringExplode (s: string, i: word, l: word) : char list =
		let 
			fun exp_str (num, res) =
				if num = 0w0
				then res
				else exp_str (num - 0w1, System_loadb(s, num+i-0w1+wordSize) :: res)
		in
			(* Handle the special case of a single character string which is
			   represented by the character itself.  N.B. because we use this
			   function to explode substrings as well as whole strings the test
			   here needs to be whether the base string is short not whether
			   l is one.  If l is zero we use exp_str which immediately returns nil. *)
			if isShortString s andalso l <> 0w0 then [ vecAsChar s ]
			else exp_str (l, [])
		end

	    (* We want this in both String and Substring. *)
		fun unsafeSubstring(s: string, i: word, l: word) : string =
		let
			val baseLen = sizeAsWord s (* Length of base string. *)
		in
			if i = 0w0 andalso l = baseLen then s
			else if l = 0w0 then "" (* Empty string. *)
			else if l = 0w1 (* Result is a single character string (and s isn't). *)
			then charAsVec(System_loadb(s, i + wordSize))
			else
				let
					(* Multiple character string. *)
					val vec = allocString l
				in
					MemMove(s, wordSize+i, vec, wordSize, l);
					System_lock vec;
					vec
				end
		end

		(* This can be used where we have already checked the range. *)
		fun unsafeStringSub(s: string, i: word): char =
			if isShortString s then RunCall.unsafeCast s
			else System_loadb(s, i + wordSize);

	end

end;