File: PrimIO.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 (575 lines) | stat: -rw-r--r-- 17,353 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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
(*
    Title:      Standard Basis Library: PrimIO functor
    Copyright   David C.J. 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: Done *)

functor PrimIO (
    structure Vector : MONO_VECTOR
	structure VectorSlice: MONO_VECTOR_SLICE
	structure Array : MONO_ARRAY
	structure ArraySlice : MONO_ARRAY_SLICE
    sharing type Array.elem = Vector.elem = VectorSlice.elem = ArraySlice.elem
    sharing type Array.vector = Vector.vector = VectorSlice.vector = ArraySlice.vector
	sharing type VectorSlice.slice = ArraySlice.vector_slice
	sharing type Array.array = ArraySlice.array
    val someElem : Array.elem
    eqtype pos (* Note: this was shown as just a type in the functor arg. *)
    val compare : pos * pos -> order
	): PRIM_IO =
struct
	type array = Array.array 
	and  vector = Vector.vector
	and  elem = Array.elem
	and  vector_slice = VectorSlice.slice
	and  array_slice = ArraySlice.slice

	type pos = pos

	val compare = compare

	datatype reader
	= RD of {
		name : string,
		chunkSize : int,
		readVec : (int -> vector) Option.option, (* Use Option once to ensure dependency. *)
		readArr : (array_slice -> int) Option.option,
		readVecNB : (int -> vector Option.option) Option.option,
		readArrNB : (array_slice -> int Option.option) Option.option,
		block : (unit -> unit) option,
		canInput : (unit -> bool) option,
		avail : unit -> int option,
		getPos : (unit -> pos) option,
		setPos : (pos -> unit) option,
		endPos : (unit -> pos) option,
		verifyPos : (unit -> pos) option,
		close : unit -> unit,
		ioDesc : OS.IO.iodesc option
	}

	datatype writer = WR of {
		name : string,
		chunkSize : int,
		writeVec : (vector_slice -> int) Option.option,
		writeArr : (array_slice -> int) Option.option,
		writeVecNB : (vector_slice -> int Option.option) Option.option,
		writeArrNB : (array_slice -> int Option.option) Option.option,
		block : (unit -> unit) option,
		canOutput : (unit -> bool) option,
		getPos : (unit -> pos) option,
		setPos : (pos -> unit) option,
		endPos : (unit -> pos) option,
		verifyPos : (unit -> pos) option,
		close : unit -> unit,
		ioDesc : OS.IO.iodesc option
	}

	(* Define readVec, readArr, readVecNB, readArrNB if they are not
	   provided using the functions which are. *)
	fun augmentReader ( 
		RD {
			name : string,
			chunkSize : int,
			readVec : (int -> vector) Option.option,
			readArr : (array_slice -> int) Option.option,
			readVecNB : (int -> vector Option.option) Option.option,
			readArrNB : (array_slice -> int Option.option) Option.option,
			block : (unit -> unit) option,
			canInput : (unit -> bool) option,
			avail : unit -> int option,
			getPos : (unit -> pos) option,
			setPos : (pos -> unit) option,
			endPos : (unit -> pos) option,
			verifyPos : (unit -> pos) option,
			close : unit -> unit,
			ioDesc : OS.IO.iodesc option
	}) : reader =
	let
		(* First try defining readVec in terms of readArr. *)
		val readVec' =
			case (readVec, readArr) of
				(s as SOME _, _) => s (* If readVec exists use it. *)
			|	(NONE, SOME ra) =>
				(* if readVec doesn't exists but readArr does *)
					SOME(
					fn (l: int) =>
						let
							(* Create an array initialised to zeros.
							   We have to be careful here.  Suppose
							   the caller was using "readVec maxInt" to mean
							   "give me the rest of the file" knowing that it
							   was only small. To avoid problems we
							   only read the smaller of the size requested or
							   the block size. *)
							val v = Array.array(Int.min(l, chunkSize), someElem)
							(* Read as much as we can. *)
							val n = ra(ArraySlice.full v)
						in
							(* Return the section read. *)
							ArraySlice.vector(ArraySlice.slice(v, 0, SOME n))
						end
					)
			| 	(NONE, NONE) => NONE

		(* And vice-versa *)
		val readArr' =
			case (readArr, readVec) of
				(s as SOME _, _) => s(* If readArr exists use it. *)
			|	(NONE, SOME rv) =>
				(* if readArr doesn't exists but readVec does *)
					SOME(
					fn slice =>
						let
							val (buff, i, len) = ArraySlice.base slice
							(* Read a vector and try and put that into
							   the array. *)
							val r = rv len
						in
							(* Copy the vector into the array. *)
							Array.copyVec{src=r, dst = buff, di=i};
							(* Return the number of characters read. *)
							Vector.length r
						end
					)
			| 	(NONE, NONE) => NONE

		(* We now have the blocking versions of readVec and readArr if either
		   of them existed. Now defining the non-blocking versions using these
		   blocking versions if we have to. *)

		val readVecNB' =
			case (readVecNB, readArrNB) of
				(s as SOME _, _) => s (* If readVecNB exists use it. *)
			|	(NONE, SOME ra) => 
				(* If readVecNB does not exist but readArrNB does*)
					SOME(
					fn (l: int) =>
						let
							val v = Array.array(Int.min(l, chunkSize), someElem)
						in
							case ra(ArraySlice.full v) of
								NONE => NONE
							|	SOME n => (* Return the section read. *)
									SOME (ArraySlice.vector(ArraySlice.slice(v, 0, SOME n)))
						end
					)
			|	(NONE, NONE) => 
				(* Try using the blocking readVec' with canInput.
				   We use the readVec' we defined above so that this will
				   also try using readArr. *)
				case (canInput, readVec') of
					(SOME canIn, SOME rv) =>
						SOME(
						fn (l: int) =>
							if canIn()
							then SOME(rv l)
							else NONE
						)
				|	_ => NONE (* Can't do it. *)

		val readArrNB' =
			case (readArrNB, readVecNB) of
				(s as SOME _, _) => s(* If readArrNB exists use it. *)
			|	(NONE, SOME rv) =>
				(* if readArrNB doesn't exists but readVecNB does *)
					SOME(
					fn slice =>
						let
							val (buff, i, len) = ArraySlice.base slice
						in
							(* Try reading a vector of this size. *)
							case rv len of
								NONE => NONE
							|	SOME r =>
								(
								(* Copy the vector into the array. *)
								Array.copyVec{src=r, dst = buff, di=i};
								(* Return the number of characters read. *)
								SOME(Vector.length r)
							)
						end
					)
			| 	(NONE, NONE) =>
				(* Try using the blocking readArr' with canInput.
				   We use the readArr' we defined above so that this will
				   also try using readVec. *)
				case (canInput, readArr') of
					(SOME canIn, SOME ra) =>
						SOME(
						fn slice =>
							if canIn()
							then SOME(ra slice)
							else NONE
						)
				|	_ => NONE (* Can't do it. *)

		(* Finally define the blocking functions in terms of the non-blocking
		   if we have to. *)
		val readVec'' =
			case readVec' of
				(* If readVec' exists use it. i.e. if readVec or readArr were
				   defined. *)
				(s as SOME _) => s
			|	NONE =>
				(* No blocking version exists - try using block and the
				   synthesised non-blocking version. *)
				case (block, readVecNB') of
					(SOME blk, SOME rv) =>
						SOME(
						fn (l: int) =>
							(
							blk();
							case rv l of
								NONE => (* Should not occur. *)
									raise IO.Io{
										name=name,
										function="readVec",
										cause = IO.BlockingNotSupported }
							| 	SOME v => v
							)
						)
				|	_ => NONE (* Can't do it. *)

		val readArr'' =
			case readArr' of
				(* If readArr' exists use it. *)
				(s as SOME _) => s
			|	NONE =>
				(* Try using block and the synthesised readArrNB'. *)
				case (block, readArrNB') of
					(SOME blk, SOME ra) =>
						SOME(
							fn slice =>
								(
								blk();
								case ra slice of
									NONE => 
										raise IO.Io{
											name=name,
											function="readArr",
											cause = IO.BlockingNotSupported }
								|	SOME l => l
								)
						)
					|	_ => NONE (* Can't do it. *)
	in
		RD {
			name = name,
			chunkSize = chunkSize,
			readVec = readVec'',
			readArr = readArr'',
			readVecNB = readVecNB',
			readArrNB = readArrNB',
			block = block,
			canInput = canInput,
			avail = avail,
			getPos = getPos,
			setPos = setPos,
			endPos = endPos,
			verifyPos = verifyPos,
			close = close,
			ioDesc = ioDesc
		}
	end

	fun augmentWriter (WR {
		name : string,
		chunkSize : int,
		writeVec : (vector_slice -> int) Option.option,
		writeArr : (array_slice -> int) Option.option,
		writeVecNB : (vector_slice -> int Option.option) Option.option,
		writeArrNB : (array_slice -> int Option.option) Option.option,
		block : (unit -> unit) option,
		canOutput : (unit -> bool) option,
		getPos : (unit -> pos) option,
		setPos : (pos -> unit) option,
		endPos : (unit -> pos) option,
		verifyPos : (unit -> pos) option,
		close : unit -> unit,
		ioDesc : OS.IO.iodesc option
	}) : writer =
	let
		(* First try defining writeVec in terms of writeArr. *)
		val writeVec' =
			case (writeVec, writeArr) of
				(s as SOME _, _) => s (* If writeVec exists use it. *)
			|	(NONE, SOME ra) =>
				(* if writeVec doesn't exists but writeArr does *)
					SOME(
					fn slice =>
						let
							(* Create an array to hold this slice. *)
							val a = Array.array(VectorSlice.length slice, someElem)
						in
							(* Copy in the vector. *)
							ArraySlice.copyVec{src=slice, dst=a, di=0};
							(* write as much as we can. *)
							ra(ArraySlice.full a)
						end
					)
			| 	(NONE, NONE) => NONE

		(* And vice-versa *)
		val writeArr' =
			case (writeArr, writeVec) of
				(s as SOME _, _) => s (* If writeArr exists use it. *)
			|	(NONE, SOME wv) =>
				(* if writeArr doesn't exists but writeVec does *)
					SOME(
					fn slice =>
						let
							(* Construct a vector from this slice. *)
							val v = ArraySlice.vector slice;
						in
							(* Try writing this vector. *)
							wv(VectorSlice.full v)
						end
					)
			| 	(NONE, NONE) => NONE

		(* We now have the blocking versions of writeVec and writeArr if either
		   of them existed. Now defining the non-blocking versions using these
		   blocking versions if we have to. *)

		val writeVecNB' =
			case (writeVecNB, writeArrNB) of
				(s as SOME _, _) => s (* If writeVecNB exists use it. *)
			|	(NONE, SOME wa) => 
				(* If writeVecNB does not exist but writeArrNB does*)
					SOME(
					fn slice =>
						let
							val len = VectorSlice.length slice
							(* Create an array to hold this slice. *)
							val a = Array.array(len, someElem)
						in
							(* Copy in the vector. *)
							ArraySlice.copyVec{src=slice, dst=a, di=0};
							(* Try writing it and see what happened. *)
							wa(ArraySlice.full a)
						end
					)
			|	(NONE, NONE) => 
				(* Try using the blocking writeVec' with canOutput.
				   We use the writeVec' we defined above so that this will
				   also try using writeArr. *)
				case (canOutput, writeVec') of
					(SOME canOut, SOME wv) =>
						SOME(
						fn slice =>
							if canOut() then SOME(wv slice) else NONE
						)
				|	_ => NONE (* Can't do it. *)

		val writeArrNB' =
			case (writeArrNB, writeVecNB) of
				(s as SOME _, _) => s (* If writeArrNB exists use it. *)
			|	(NONE, SOME wv) =>
				(* if writeArrNB doesn't exists but writeVecNB does *)
					SOME(
					fn slice =>
						let
							(* Construct a vector from this slice. *)
							val v = ArraySlice.vector slice;
						in
							(* Try writing the vector. *)
							wv(VectorSlice.full v)
						end
					)
			| 	(NONE, NONE) =>
				(* Try using the blocking writeArr' with canOutput.
				   We use the writeArr' we defined above so that this will
				   also try using writeVec. *)
				case (canOutput, writeArr') of
					(SOME canOut, SOME wa) =>
						SOME(
						fn slice =>
							if canOut() then SOME(wa slice) else NONE
						)
				|	_ => NONE (* Can't do it. *)

		(* Finally define the blocking functions in terms of the non-blocking
		   if we have to. *)
		val writeVec'' =
			case writeVec' of
				(* If writeVec' exists use it. i.e. if writeVec or writeArr were
				   defined. *)
				(s as SOME _) => s
			|	NONE =>
				(* No blocking version exists - try using block and the
				   synthesised non-blocking version. *)
				case (block, writeVecNB') of
					(SOME blk, SOME wv) =>
						SOME(
						fn slice =>
							(
								blk();
								case wv slice of
									NONE => (* Should not occur. *)
										raise IO.Io{
											name=name,
											function="writeVec",
											cause = IO.BlockingNotSupported }
								| 	SOME l => l
							)
						)
				|	_ => NONE (* Can't do it. *)

		val writeArr'' =
			case writeArr' of
				(* If writeArr' exists use it. *)
				(s as SOME _) => s
			|	NONE =>
				(* Try using block and the synthesised writeArrNB'. *)
				case (block, writeArrNB') of
					(SOME blk, SOME wa) =>
						SOME(
							fn slice =>
							(
								blk();
								case wa slice of
									NONE => 
										raise IO.Io{
											name=name,
											function="writeArr",
											cause = IO.BlockingNotSupported }
								|	SOME l => l
							)
						)
					|	_ => NONE (* Can't do it. *)
	in
		WR {
		name = name,
		chunkSize = chunkSize,
		writeVec = writeVec'',
		writeArr = writeArr'',
		writeVecNB = writeVecNB',
		writeArrNB = writeArrNB',
		block = block,
		canOutput = canOutput,
		getPos = getPos,
		setPos = setPos,
		endPos = endPos,
		verifyPos = verifyPos,
		close = close,
		ioDesc = ioDesc
		}
	end
	
	(* Null reader - always returns end-of-file except when closed when it raises IO.ClosedStream. *)
	fun nullRd () =
	let
		val isOpen = ref true
	in
		RD {
		name = "nullRd",
		chunkSize = 1,
		readVec = SOME(fn n => if n < 0 then raise Size else if !isOpen then Vector.fromList [] else raise IO.ClosedStream),
		readArr = SOME(fn _ => if !isOpen then 0 else raise IO.ClosedStream),
		readVecNB = SOME(fn n => if n < 0 then raise Size else if !isOpen then SOME(Vector.fromList []) else raise IO.ClosedStream),
		readArrNB = SOME(fn _ => if !isOpen then SOME 0 else raise IO.ClosedStream),
		block = SOME(fn () => if !isOpen then () else raise IO.ClosedStream),
		canInput = SOME(fn () => if !isOpen then true else raise IO.ClosedStream),
		avail = fn () => if !isOpen then NONE else raise IO.ClosedStream,
		getPos = NONE,
		setPos = NONE,
		endPos = NONE,
		verifyPos = NONE,
		close = fn () => isOpen := false,
		ioDesc = NONE
		}
	end

	(* Null writer - always swallows input except when closed when it raises IO.ClosedStream. *)
	fun nullWr () =
	let
		val isOpen = ref true
	in
		WR {
		name = "nullWr",
		chunkSize = 1,
		writeVec = SOME(fn slice => if !isOpen then VectorSlice.length slice else raise IO.ClosedStream),
		writeArr = SOME(fn slice => if !isOpen then ArraySlice.length slice else raise IO.ClosedStream),
		writeVecNB = SOME(fn slice => if !isOpen then SOME(VectorSlice.length slice) else raise IO.ClosedStream),
		writeArrNB = SOME(fn slice => if !isOpen then SOME(ArraySlice.length slice) else raise IO.ClosedStream),
		block = SOME(fn () => if !isOpen then () else raise IO.ClosedStream),
		canOutput = SOME(fn () => if !isOpen then true else raise IO.ClosedStream),
		getPos = NONE,
		setPos = NONE,
		endPos = NONE,
		verifyPos = NONE,
		close = fn () => isOpen := false,
		ioDesc = NONE
		}
	end
	
	fun openVector v =
	let
		val isOpen = ref true
		val len = Vector.length v
		val p = ref 0 (* Pointer to current element. *)

		(* Return a slice of the vector from the current position for either the rest of
		   the vector or the size requested if that's smaller. *)
		fun getSlice n =
			if not (! isOpen) then raise IO.ClosedStream
			else
			let
				val toRead = Int.min(n, len - !p) (* Return the smaller of the size requested or the size left. *)
				val resSlice = VectorSlice.slice(v, !p, SOME toRead)
			in
				p := !p + toRead;
				resSlice
			end

		(* Return a slice of the vector. *)
		fun readVec n = if n < 0 then raise Size else VectorSlice.vector(getSlice n)

		(* Copy a portion of the vector into the array.  We can probably copy directly
		   from the original vector whereas if we synthesised this function it would
		   require an extra copy. *)
		fun readArr slice = 
			let
				val (base, di, len) = ArraySlice.base slice
				val resSlice = getSlice len
			in
				ArraySlice.copyVec{src=resSlice, dst=base, di=di};
				VectorSlice.length resSlice
			end
	in
		RD {
		name = "openVector",
		chunkSize = 1, (* Or the size of the vector? *)
		readVec = SOME readVec,
		readArr = SOME readArr,
		readVecNB = NONE,
		readArrNB = NONE,
		block = SOME(fn () => if !isOpen then () else raise IO.ClosedStream),
		canInput = SOME(fn () => if !isOpen then true else raise IO.ClosedStream),
		(* avail returns the number of bytes and since we don't know the size of "elem" we return NONE here *)
		avail = fn () => if !isOpen then NONE else raise IO.ClosedStream,
		getPos = NONE,
		setPos = NONE,
		endPos = NONE,
		verifyPos = NONE,
		close = fn () => isOpen := false,
		ioDesc = NONE
		}
	end

end;