-
Notifications
You must be signed in to change notification settings - Fork 28
Vector module (#258) #306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Vector module (#258) #306
Changes from all commits
bf4a720
04c589f
51ef7c2
b8b37ea
06537ac
77d9937
40abb96
3906ceb
0d8a228
10501dd
923f8a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see, why the capacity of a vector must be a power of 2 (except for the empty vector). Maybe it would be better to allow any capacity, and multiply it by 2 (or any other constant), when the vector must be resized. This would allow to convert lists to vectors without unnecessary memory overhead, and I thing would slightly simplify the code. Moreover, I don't see why the vector is never resized down. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| ## ## Vector library | ||
| {# | ||
| This file is part of DBL, released under MIT license. | ||
| See LICENSE for details. | ||
| #} | ||
|
|
||
| import open Mutable | ||
| import open /Base/Bool | ||
| import open /List | ||
|
|
||
| abstr data Vector E T = Vector of | ||
| { content : Ref E (Array E T) | ||
| , size : Ref E Int | ||
| , capacity : Ref E Int | ||
| , mut : Mut E | ||
| } | ||
|
|
||
| parameter E | ||
| parameter T | ||
|
|
||
| # Helper methods for vector implementation | ||
| method getContentAt (Vector {content} : Vector E T) (n : Int) = | ||
| content.get.get n | ||
|
|
||
| method setContentAt (Vector {content} : Vector E T) (n : Int) (x : T) = | ||
| content.get.at n := x | ||
|
|
||
| method setContent (Vector {content} : Vector E T) newContent = | ||
| content := newContent | ||
|
|
||
| method mut (Vector {mut} : Vector E T) = mut | ||
|
|
||
| let getSmallestUpperPow2 (n : Int) = | ||
| let n = if n == 0 then 1 else n in | ||
| let n = n-1 in | ||
| let n = n ||| (n>>1) in | ||
| let n = n ||| (n>>2) in | ||
| let n = n ||| (n>>4) in | ||
| let n = n ||| (n>>8) in | ||
| let n = n ||| (n>>16) in | ||
| let n = n ||| (n>>32) in | ||
| n+1 | ||
|
|
||
| {## Creates vector of given size. ##} | ||
| pub let makeEmptyVector {T, ~mut : Mut E} (size : Int) = | ||
| let capacity = (getSmallestUpperPow2 size) in | ||
| Vector | ||
| { content = ~mut.ref (~mut.makeArray capacity ((extern dbl_magic : Int -> T) 0)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The extern results in runtime error. To avoid such problems we should forbid creating non-empty vectors without providing the default value. Creating empty vectors is still ok. |
||
| , size = ~mut.ref size | ||
| , capacity = ~mut.ref capacity | ||
| , mut = ~mut | ||
| } | ||
|
|
||
| {## Creates a vector of a given size filled with a given value v. ##} | ||
| pub let makeVector {T, ~mut : Mut E} (size : Int) (v : T) = | ||
| let capacity = (getSmallestUpperPow2 size) in | ||
| Vector | ||
| { content = ~mut.ref (~mut.makeArray capacity v) | ||
| , size = ~mut.ref size | ||
| , capacity = ~mut.ref capacity | ||
| , mut = ~mut | ||
| } | ||
|
|
||
| {## Returns vector of given size. ##} | ||
| pub method capacity (Vector {capacity} : Vector E T) = capacity.get | ||
|
|
||
| method setCapacity (Vector {capacity} : Vector E T) (n : Int) = capacity := n | ||
|
|
||
| {## Returns the number of elements. ##} | ||
| pub method size (Vector {size} : Vector E T) = size.get | ||
|
|
||
| method setSize (Vector {size} : Vector E T) (n : Int) = size := n | ||
|
|
||
| {## Returns true if the vector is empty. ##} | ||
| pub method empty (Vector {size} : Vector E T) = size.get == 0 | ||
|
|
||
| {## | ||
| Resizes the vector to contain n elements. | ||
| If n is smaller than the current size, the vector is truncated. | ||
| If n is greater than size, the vector is expanded. | ||
| ##} | ||
| pub method resize {T} (self : Vector E T) (n : Int) = | ||
| assert {msg="Capacity overflow"} (n >= 0 && n <= maxArrayLength); | ||
| self.setSize n; | ||
| if n > self.capacity then ( | ||
| let newCapacity = min (self.capacity * 2) maxArrayLength | ||
| let newContent = self.mut.initArray newCapacity (fn i => | ||
| if i < self.capacity then self.getContentAt i | ||
| else ((extern dbl_magic : Int -> T) 0)) in | ||
| self.setContent newContent; | ||
| self.setCapacity newCapacity | ||
| ) else if n * 2 < self.capacity then ( | ||
| let newCapacity = self.capacity / 2 | ||
| let newContent = self.mut.initArray newCapacity (fn i => | ||
| if i <= self.size then self.getContentAt i | ||
| else ((extern dbl_magic : Int -> T) 0)) in | ||
| self.setContent newContent; | ||
| self.setCapacity newCapacity | ||
| ) else () | ||
|
|
||
| {## Get the nth element of a vector. ##} | ||
| pub method get (self : Vector E T) (n : Int) = | ||
| assert {msg="Index out of range"} (n >= 0 && n < self.size); | ||
| self.getContentAt n | ||
|
|
||
| {## Set the nth element of a vector. ##} | ||
| pub method set (self : Vector E T) (n : Int) (x : T) = | ||
| assert {msg="Index out of range"} (n >= 0 && n < self.size); | ||
| self.setContentAt n x | ||
|
|
||
| {## Access the first element. ##} | ||
| pub method front (self : Vector E T) = self.get 0 | ||
|
|
||
| {## Access the last element. ##} | ||
| pub method back (self : Vector E T) = self.get (self.size - 1) | ||
|
|
||
| {## Add element at the end. ##} | ||
| pub method pushBack (self : Vector E T) (x : T) = | ||
| self.resize (self.size + 1); | ||
| self.set (self.size - 1) x | ||
|
|
||
| {## Removes the last element. ##} | ||
| pub method popBack (self : Vector E T) = | ||
| assert {msg="Vector is empty"} (self.empty.neg); | ||
| self.resize (self.size - 1) | ||
|
|
||
| {## Converts a list into a vector. ##} | ||
| pub let fromList {~mut : Mut E} (l : List T) = | ||
| let vec = makeEmptyVector {T} l.length in | ||
| let rec aux (n : Int) acc = | ||
| match acc with | ||
| | [] => vec | ||
| | x :: xs => | ||
| vec.set n x; | ||
| aux (n + 1) xs | ||
| end | ||
| in aux 0 l | ||
|
|
||
| {## Converts a vector into a list. ##} | ||
| pub method toList (self : Vector E T) = | ||
| let rec aux (n : Int) acc = | ||
| if n < 0 then acc | ||
| else aux (n - 1) (self.get n :: acc) | ||
| in aux (self.size - 1) [] | ||
|
|
||
| {## Clears the vector. ##} | ||
| pub method clear (self : Vector E T) = | ||
| self.setSize 0; | ||
| self.setCapacity 0; | ||
| self.setContent (self.mut.makeArray 0 ((extern dbl_magic : Int -> T) 0)) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import open Mutable | ||
| import open /Vector | ||
| import open /String | ||
| import open Testing | ||
|
|
||
| let _ = testSuite "vector" (fn _ => | ||
|
|
||
| testCase "size and capacity" (fn _ => | ||
| let vec = makeEmptyVector {T=Int} 4 in | ||
| let sz = vec.size in | ||
| let cap = vec.capacity in | ||
| assertEqS sz 4; | ||
| assertEqS cap 4); | ||
|
|
||
| testCase "front and back" (fn _ => | ||
| let vec = makeEmptyVector {T=Int} 4 in | ||
| vec.set 0 1; | ||
| vec.set 1 2; | ||
| vec.set 2 3; | ||
| vec.set 3 4; | ||
| vec.pushBack 5; | ||
| let fst = vec.front in | ||
| let lst = vec.back in | ||
| assertEqS fst 1; | ||
| assertEqS lst 5); | ||
|
|
||
| testCase "get" (fn _ => | ||
| let vec = makeEmptyVector {T=Int} 0 in | ||
| vec.pushBack 6; | ||
| vec.pushBack 7; | ||
| vec.pushBack 8; | ||
| vec.pushBack 9; | ||
| let x = vec.get 1 in | ||
| let y = vec.get 3 in | ||
| assertEqS x 7; | ||
| assertEqS y 9); | ||
|
|
||
| testCase "clear" (fn _ => | ||
| let vec = makeEmptyVector {T=Int} 4 in | ||
| vec.clear; | ||
| let sz = vec.size in | ||
| let cap = vec.capacity in | ||
| assertEqS sz 0; | ||
| assertEqS cap 0); | ||
|
|
||
| testCase "from/to list" (fn _ => | ||
| let xs = [1,2,3,4] in | ||
| let vec = fromList xs in | ||
| let x = vec.get 0 in | ||
| let y = vec.get 2 in | ||
| let ys = vec.toList in | ||
| let z = ys.hd in | ||
| assertEqS x 1; | ||
| assertEqS y 3; | ||
| assertEqS z (Some 1)); | ||
|
|
||
| testCase "vector of strings" (fn _ => | ||
| let vec = makeEmptyVector {T=String} 2 in | ||
| vec.set 0 "abc"; | ||
| vec.set 1 "ab"; | ||
| vec.pushBack "a"; | ||
| let fst = vec.front in | ||
| let lst = vec.back in | ||
| assertEqS fst "abc"; | ||
| assertEqS lst "a"); | ||
|
|
||
| testCase "filled vector" (fn _ => | ||
| let vec = makeVector {T=String} 42 "" in | ||
| assertEqS (vec.get 0 + "A") "A")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line character was removed from non changed file. First, we should avoid unnecessary changes like this, second, we use UNIX convention, where each nonempty text file ends with newline character.