1(*
2    Title:      Standard Basis Library: Vector Structure
3    Author:     David Matthews
4    Copyright   David Matthews 1999, 2005, 2016
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License version 2.1 as published by the Free Software Foundation.
9    
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14    
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18*)
19local
20    (* Inherit the definition of vector in the initial environment.
21       We have to declare vector in the initial environment in order
22       for equality to work correctly. *)
23
24    (* It would be simpler to be able to define these as functions
25       to or from 'a vector but that gives error messages about free
26       type variables. *)
27
28    val vecAsWord: 'a vector -> word = RunCall.unsafeCast
29    and wordAsVec: word -> 'a vector = RunCall.unsafeCast
30    val intAsWord: int -> word = RunCall.unsafeCast
31    and wordAsInt: word -> int = RunCall.unsafeCast
32
33    (* All the arrays are initially created containing zeros and then initialised. *)
34    fun alloc len = RunCall.allocateWordMemory(Word.fromInt len, 0wx40, 0w0)
35    
36    fun unsafeSub(v: 'a vector, i: int): 'a = RunCall.loadWord (vecAsWord v, intAsWord i)
37    and unsafeUpdate(v: 'a vector, i: int, new: 'a): unit =
38        RunCall.storeWord (vecAsWord v, intAsWord i, RunCall.unsafeCast new)
39in
40
41structure Vector: VECTOR =
42struct
43    (* N.B.  This implementation of vectors is implicitly used in
44       Array.extract.  Don't change this implementation without also
45       changing that. It's also used in the interface to the RTS in OS.Poll and Socket.select. *)
46    type 'a vector = 'a vector
47
48    (* The maximum size of a vector is the maximum object size we can allocate.
49       This is one more than the maximum size of an array. *)
50    val maxLen = RunCall.unsafeCast LibrarySupport.maxAllocation
51
52    infix 9 sub (* For what it's worth *)
53  
54    (* Lock the arrays after they have been created.  All this does is
55       switch off the "mutable" bit.  This does not prevent updating of
56       itself, the signature does that by removing "update", but improves
57       g.c. performance and causes equality to check for value equality
58       not pointer equality. *)
59    val listLength = length; (* Pick this up from the prelude. *)
60 
61    fun length v = wordAsInt(RunCall.memoryCellLength(vecAsWord v));
62
63    fun op sub (vec:'a vector, i: int): 'a =
64    let
65        val v = vecAsWord vec
66    in
67        if not (LibrarySupport.isShortInt i) orelse intAsWord i >= RunCall.memoryCellLength v
68        then raise General.Subscript
69        else unsafeSub(vec, i)
70    end
71 
72    (* Create a vector from a list.  We have to treat an empty list specially
73       because we don't allow zero sized heap objects. *)
74    fun fromList [] : 'a vector = wordAsVec LibrarySupport.emptyVector (* Must not try to lock it. *)
75      | fromList (l : 'a list) : 'a vector =
76        let
77        val length = listLength l;
78        val () = if length >= maxLen then raise General.Size else ()
79            
80        (* Make a vector initialised to zero. *)
81        val vec = alloc length;
82        
83        (* Copy the list elements into the vector. *)
84        fun init (v, i, a :: l) =
85            (
86            RunCall.storeWord(v, intAsWord i, RunCall.unsafeCast a);
87            init(v, i + 1, l)
88            )
89        |  init (_, _, []) = ();
90        
91    in
92        init(vec, 0, l);
93        RunCall.clearMutableBit vec;
94        wordAsVec vec
95    end
96        
97    fun tabulate (0, _) : 'a vector = wordAsVec LibrarySupport.emptyVector (* Must not try to lock it. *)
98     |  tabulate (length: int , f : int->'a): 'a vector =
99    let
100        val vec =
101            if length > 0 andalso length < maxLen then alloc length else raise General.Size;
102        (* Initialise it to the function values. *)
103        fun init i = 
104            if length <= i then ()
105            else (RunCall.storeWord(vec, intAsWord i, RunCall.unsafeCast(f i)); init(i+1))
106    in
107        init 0;
108        RunCall.clearMutableBit vec;
109        wordAsVec vec
110    end
111    
112
113    fun concat [] = wordAsVec LibrarySupport.emptyVector
114     |  concat [v] = v (* Handle special cases to reduce copying. *)
115     |  concat l =
116    let
117        (* Calculate the total length *)
118        fun total [] i = i
119          | total (h::t) i = total t (i+length h)
120    
121        val total_len = total l 0
122    in
123        if total_len = 0 then wordAsVec LibrarySupport.emptyVector
124        else if total_len >= maxLen then raise General.Size
125        else
126        let
127            (* Allocate a new vector. *)
128            val new_vec = alloc total_len
129                
130            fun copy_list [] _ = ()
131              | copy_list (h::t) j =
132                let
133                    val v = vecAsWord h
134                    val src_len = length h
135                in
136                    RunCall.moveWords(v, new_vec, 0w0, Word.fromInt j, Word.fromInt src_len);
137                    copy_list t (j+src_len)
138                end
139        in
140            copy_list l 0;
141            RunCall.clearMutableBit new_vec;
142            wordAsVec new_vec
143        end
144    end
145    
146    
147    fun map (f: 'a->'b) (vec: 'a vector): 'b vector =
148    let
149        val len = length vec
150    in
151        if len = 0 then wordAsVec LibrarySupport.emptyVector
152        else
153        let
154            (* Allocate a new vector. *)
155            val new_vec = alloc len
156            val newResult = wordAsVec new_vec
157                
158            fun domap i =
159                if i >= len then ()
160                else (unsafeUpdate(newResult, i, f(unsafeSub(vec, i))); domap(i+1))
161        in
162            domap 0;
163            RunCall.clearMutableBit new_vec;
164            newResult
165        end
166    end
167
168    fun mapi (f: int*'a->'b) (vec:'a vector): 'b vector =
169    let
170        val len = length vec
171    in
172        if len = 0 then wordAsVec LibrarySupport.emptyVector
173        else
174        let
175            (* Allocate a new vector. *)
176            val new_vec = alloc len
177            val newResult = wordAsVec new_vec
178                
179            fun domap i =
180                if i >= len then ()
181                else (unsafeUpdate(newResult, i, f(i, unsafeSub(vec, i))); domap(i+1))
182        in
183            domap 0;
184            RunCall.clearMutableBit new_vec;
185            newResult
186        end
187    end
188    
189    (* Create a new vector with the ith element replaced by c *)
190    fun update(v: 'a vector, i , c) =
191        if i < 0 orelse i >= length v
192        then raise Subscript
193        else mapi (fn (j, s) => if j = i then c else s) v
194
195    (* Create the other functions. *)
196    structure VectorOps =
197        PolyVectorOperations(
198            struct
199                type 'a vector = 'a vector
200                fun length v = RunCall.memoryCellLength(vecAsWord v)
201                local val u = unsafeSub in fun unsafeSub (v: 'a vector, i: word) = u(v, wordAsInt i) end
202                fun unsafeSet _ = raise Fail "Should not be called"
203            end);
204
205    open VectorOps;
206
207    local
208        (* Install the pretty printer for vectors *)
209        (* We may have to do this outside the structure if we
210           have opaque signature matching. *)
211        fun pretty(depth: FixedInt.int)
212                  (printElem: 'a * FixedInt.int -> PolyML.pretty)
213                  (x: 'a vector) =
214            let
215                open PolyML
216                val last = length x - 1
217                fun put_elem (index, w, (l, d)) =
218                    if d = 0 then ([PrettyString "...]"], d+1)
219                    else if d < 0 then ([], d+1)
220                    else
221                    (
222                    printElem(w, d-1) ::
223                        (if index <> last then PrettyString "," :: PrettyBreak(1, 0) :: l else l),
224                    d+1
225                    )
226            in
227                PrettyBlock(3, false, [],
228                    PrettyString "fromList[" ::
229                    (if depth <= 0 then [PrettyString "...]"]
230                     else #1 (foldri put_elem ([PrettyString "]"], depth - FixedInt.fromInt last) x) )
231               )
232            end
233    in
234        val () = PolyML.addPrettyPrinter pretty
235    end
236
237end (* Vector *)
238
239structure VectorSlice =
240struct
241    datatype 'a slice = Slice of { vector: 'a vector,  start: int, length: int };
242    
243    fun length(Slice{length, ...}) = length
244    
245    fun op sub (Slice{vector, start, length}, i: int): 'a =
246        if i < 0 orelse i >= length then raise General.Subscript
247        else unsafeSub(vector, i+start)
248    
249    (* Create a slice from a vector. *)
250    fun slice(vec: 'a vector, i: int, NONE) =
251        let
252            val len = Vector.length vec
253        in
254            if i >= 0 andalso i <= len
255            then Slice{vector=vec, start=i, length=len-i} (* Length is rest of vector. *)
256            else raise General.Subscript
257        end
258     |  slice(vec: 'a vector, i: int, SOME l) =
259        let
260            val len = Vector.length vec
261        in
262            if i >= 0 andalso l >= 0 andalso i+l <= len
263            then Slice{vector=vec, start=i, length=l} (* Length is as given. *)
264            else raise General.Subscript
265        end
266        
267    (* Slice from the whole vector. *)
268    fun full v = Slice{vector=v, start=0, length=Vector.length v}
269
270    (* Slice from existing slice *)
271    fun subslice(Slice{vector, start, length}, i: int, NONE) =
272        if i >= 0 andalso i <= length
273        then Slice{vector=vector, start=i+start, length=length-i} (* Length is rest of array. *)
274        else raise General.Subscript
275
276     |  subslice(Slice{vector, start, length}, i: int, SOME l) =
277        if i >= 0 andalso l >= 0 andalso i+l <= length
278        then Slice{vector=vector, start=i+start, length=l} (* Length is as given. *)
279        else raise General.Subscript
280    
281    fun vector(Slice{vector, start, length}) =
282        if length = 0 then wordAsVec LibrarySupport.emptyVector (* Special case for zero *)
283        else
284        let
285            (* Make a vector initialised to zero. *)
286            val new_vec = alloc length
287        in
288            RunCall.moveWords(vecAsWord vector, new_vec, Word.fromInt start, 0w0, Word.fromInt length);
289            RunCall.clearMutableBit new_vec;
290            wordAsVec new_vec
291        end
292
293    fun base(Slice{vector, start, length}) = (vector, start, length)
294    
295    fun isEmpty(Slice{length, ...}) = length = 0
296
297    (* Return the first item of the slice and the rest of the slice. *)
298    fun getItem(Slice{length=0, ...}) = NONE
299     |  getItem(Slice{vector, start, length}) =
300            SOME(unsafeSub(vector, start), Slice{vector=vector, start=start+1, length=length-1})
301            
302
303    fun concat [] = wordAsVec LibrarySupport.emptyVector
304     |  concat l =
305    let
306        (* Calculate the total length *)
307        fun total [] i = i
308          | total (h::t) i = total t (i+length h)
309    
310        val total_len = total l 0
311    in
312        if total_len = 0 then wordAsVec LibrarySupport.emptyVector
313        else
314        let
315            (* Allocate a new vector. *)
316            val new_vec = alloc total_len
317                
318            fun copy_list [] _ = ()
319              | copy_list (Slice{vector, start, length}::t) j =
320                (
321                    RunCall.moveWords(vecAsWord vector, new_vec, Word.fromInt start, Word.fromInt j, Word.fromInt length);
322                    copy_list t (j+length)
323                )
324        in
325            copy_list l 0;
326            RunCall.clearMutableBit new_vec;
327            wordAsVec new_vec
328        end
329    end
330    
331    fun map (f: 'a->'b) (Slice{vector:'a Vector.vector, start, length}): 'b Vector.vector =
332        if length = 0 then wordAsVec LibrarySupport.emptyVector
333        else
334        let
335            (* Allocate a new vector. *)
336            val new_vec = alloc length
337            val newResult = wordAsVec new_vec
338                
339            fun domap i =
340                if i >= length then ()
341                else (unsafeUpdate(newResult, i, f(unsafeSub(vector, i+start))); domap(i+1))
342        in
343            domap 0;
344            RunCall.clearMutableBit new_vec;
345            newResult
346        end
347
348    fun mapi (f: int*'a->'b) (Slice{vector:'a Vector.vector, start, length}): 'b Vector.vector =
349        if length = 0 then wordAsVec LibrarySupport.emptyVector
350        else
351        let
352            (* Allocate a new vector. *)
353            val new_vec = alloc length
354            val newResult = wordAsVec new_vec
355                
356            fun domap i =
357                if i >= length then ()
358                else (unsafeUpdate(newResult, i, f(i, unsafeSub(vector, i+start))); domap(i+1))
359        in
360            domap 0;
361            RunCall.clearMutableBit new_vec;
362            newResult
363        end
364
365
366    (* Create the other functions. *)
367    structure VectorOps =
368        PolyVectorOperations(
369            struct
370                type 'a vector = 'a slice
371                fun length(Slice{length, ...}) = intAsWord length
372                val unsafeSub = fn (Slice{vector, start, ...}, i) => unsafeSub (vector, wordAsInt i + start)
373                fun unsafeSet _ = raise Fail "Should not be called"
374            end);
375
376    open VectorOps;
377
378end (* VectorSlice *)
379
380end (* Local in end *);
381  
382structure VectorSlice :> VECTOR_SLICE = VectorSlice;
383
384local
385    open VectorSlice
386    (* Install the pretty printer for vector slices *)
387    (* We may have to do this outside the structure if we
388       have opaque signature matching. *)
389    fun pretty(depth: FixedInt.int)
390              (printElem: 'a * FixedInt.int -> PolyML.pretty)
391              (x: 'a slice) =
392        let
393            open PolyML
394            val last = length x - 1
395            fun put_elem (index, w, (l, d)) =
396                if d = 0 then ([PrettyString "...]"], d+1)
397                else if d < 0 then ([], d+1)
398                else
399                (
400                printElem(w, d-1) ::
401                    (if index <> last then PrettyString "," :: PrettyBreak(1, 0) :: l else l),
402                d+1
403                )
404        in
405            PrettyBlock(3, false, [],
406                PrettyString "fromList[" ::
407                (if depth <= 0 then [PrettyString "...]"]
408                 else #1 (foldri put_elem ([PrettyString "]"], depth - FixedInt.fromInt last) x) )
409           )
410        end
411in
412    val () = PolyML.addPrettyPrinter pretty
413end
414;
415
416
417(* type 'a vector is available unqualified in the global basis. *)
418val vector : 'a list -> 'a vector = Vector.fromList;
419