File: ImperativeIO.sml

package info (click to toggle)
polyml 5.7.1-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid
  • size: 40,616 kB
  • sloc: cpp: 44,142; ansic: 26,963; sh: 22,002; asm: 13,486; makefile: 602; exp: 525; python: 253; awk: 91
file content (171 lines) | stat: -rw-r--r-- 6,638 bytes parent folder | download | duplicates (5)
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
(*
    Title:      Standard Basis Library: ImperativeIO functor
    Copyright   David C.J. Matthews 2000, 2015

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License version 2.1 as published by the Free Software Foundation.
    
    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
*)

(* This is also used in TextIO.  We need "protect". *)
functor BasicImperativeIO (
    structure StreamIO : STREAM_IO
    structure Vector : MONO_VECTOR
    structure Array : MONO_ARRAY
    sharing type StreamIO.elem = Vector.elem = Array.elem
    sharing type StreamIO.vector = Vector.vector = Array.vector
) (* No signature on the result *)
=
struct

    structure StreamIO = StreamIO
    type vector = Vector.vector
    and  elem = StreamIO.elem

    datatype instream = InStream of {
        (* An imperative input stream is a reference to a lazy functional stream. *)
        fStream: StreamIO.instream ref,
        lock: Thread.Mutex.mutex
        }
    and outstream = OutStream of {
        (* An imperative output stream is a reference to the underlying stream.
           Unlike instream the underlying stream is also imperative but we need
           a reference here to allow us to redirect. *)
        fStream: StreamIO.outstream ref
        }
    (* We don't need a mutex for outstream assuming := and ! are atomic
       i.e. '!' returns either the previous value or the current one and
       not some intermediate value. *)

    (* Use no-overwrite refs for imperative streams.  This is really only needed for
       stdIn to make sure that when we call PolyML.SaveState.loadState we don't
       overwrite any unread input by the contents of the buffer when saveState
       was called. *)

    fun mkInstream (s : StreamIO.instream) : instream =
        InStream{fStream = LibrarySupport.noOverwriteRef s, lock = Thread.Mutex.mutex()}
        
    fun protect (InStream{fStream, lock}) f =
        LibraryIOSupport.protect lock f fStream

    (* Get and set the underlying stream.  We have to interlock
       setInstream at least. *)
    fun getInstream s = protect s (fn fStream => !fStream) 
    and setInstream(InStream{fStream, lock}, s) =
        LibraryIOSupport.protect lock (fn fStream => fStream := s) fStream

    (* These are just wrappers for the underlying functional calls. *)
    fun input s = protect s 
           (fn fStream =>
            let
                val (v, f') = StreamIO.input(!fStream)
            in
                fStream := f';
                v
            end)

    (* We don't use StreamIO.input1 here because that never advances over
       a temporary EOF. *)
    fun input1 s = protect s
           (fn fStream =>
            let
                val (s, f') = StreamIO.inputN(!fStream, 1)
            in
                fStream := f';
                if Vector.length s = 0 then NONE else SOME(Vector.sub(s, 0))
            end)

    fun inputN(InStream{fStream, lock}, n) =
        LibraryIOSupport.protect lock
           (fn fStream =>
            let
                val (v, f') = StreamIO.inputN(!fStream, n)
            in
                fStream := f';
                v
            end) fStream

    fun inputAll s = protect s
           (fn fStream =>
            let
                val (v, f') = StreamIO.inputAll(!fStream)
            in
                fStream := f';
                v
            end)

    (* These next functions only query the stream and don't affect the
       fStream ref so don't really need interlocking.  If two threads
       call these functions simultaneously the result is non-deterministic
       anyway. *)
    fun canInput(InStream{fStream, lock}, n) =
        LibraryIOSupport.protect lock
           (fn fStream => StreamIO.canInput(! fStream, n)) fStream

    and closeIn s = protect s (fn fStream => StreamIO.closeIn(! fStream))
    and endOfStream s = protect s (fn fStream => StreamIO.endOfStream(! fStream))

    fun lookahead s = protect s
        (fn fStream =>
            case StreamIO.input1 (! fStream) of
                NONE => NONE
            |   SOME(s, _) => SOME s
        )

    (* These are simply wrappers. *)

    fun mkOutstream (s : StreamIO.outstream) : outstream =
        OutStream{fStream = LibrarySupport.noOverwriteRef s}

    fun getOutstream(OutStream{fStream = ref s}) = s
    and setOutstream(OutStream{fStream}, s) = fStream := s

    fun output(OutStream{fStream=ref f, ...}, v) = StreamIO.output(f, v)
    and output1(OutStream{fStream=ref f, ...}, c) = StreamIO.output1(f, c)
    and flushOut(OutStream{fStream=ref f, ...}) = StreamIO.flushOut f
    and closeOut(OutStream{fStream=ref f, ...}) = StreamIO.closeOut f
    and getPosOut(OutStream{fStream=ref f, ...}) = StreamIO.getPosOut f

    fun setPosOut(OutStream{fStream, ...}, p) = fStream := StreamIO.setPosOut p
    
    (* Add pretty printers to hide the internals.  These just use the implementation streams. *)
    local
        open PolyML
        fun prettyIn depth _ (InStream{ fStream = ref s, ...}) =
            PolyML.prettyRepresentation(s, depth)
        fun prettyOut depth _ (OutStream { fStream = ref s, ...}) =
            PolyML.prettyRepresentation(s, depth)
    in
        val () = addPrettyPrinter prettyIn
        val () = addPrettyPrinter prettyOut
    end
end;

(* General exported version with final signature. *)
functor ImperativeIO (
    structure StreamIO : STREAM_IO
    structure Vector : MONO_VECTOR
    structure Array : MONO_ARRAY
    sharing type StreamIO.elem = Vector.elem = Array.elem
    sharing type StreamIO.vector = Vector.vector = Array.vector
) : IMPERATIVE_IO
        where type StreamIO.elem = StreamIO.elem
        where type StreamIO.vector = StreamIO.vector
        where type StreamIO.instream = StreamIO.instream
        where type StreamIO.outstream = StreamIO.outstream
        where type StreamIO.out_pos = StreamIO.out_pos
        where type StreamIO.reader = StreamIO.reader
        where type StreamIO.writer = StreamIO.writer
        where type StreamIO.pos = StreamIO.pos
        =
    BasicImperativeIO(structure StreamIO = StreamIO and Vector = Vector and Array = Array);