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