From c308e2b80915a0cb61e54fb100c8cb2d5bebf69a Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Thu, 6 Feb 2025 18:28:03 -0500 Subject: [PATCH 01/24] bump stanzapm to 0.19.0 --- compiler/params.stanza | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/params.stanza b/compiler/params.stanza index ab93bbc4..fb23f7db 100644 --- a/compiler/params.stanza +++ b/compiler/params.stanza @@ -18,7 +18,7 @@ public defn compiler-flags () : to-tuple(COMPILE-FLAGS) ;========= Stanza Configuration ======== -public val STANZA-VERSION = [0 18 97] +public val STANZA-VERSION = [0 19 0] public var STANZA-INSTALL-DIR:String = "" public var OUTPUT-PLATFORM:Symbol = `platform public var STANZA-PKG-DIRS:List = List() From ae78ab04924599d05523a5cb715a72adb532d309 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Thu, 6 Feb 2025 18:29:39 -0500 Subject: [PATCH 02/24] ci: point to stanzapm pipelines --- .github/workflows/concourse-notify-pull-request.yml | 2 +- .github/workflows/concourse-notify-push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/concourse-notify-pull-request.yml b/.github/workflows/concourse-notify-pull-request.yml index 0d763cc1..335969f9 100644 --- a/.github/workflows/concourse-notify-pull-request.yml +++ b/.github/workflows/concourse-notify-pull-request.yml @@ -3,7 +3,7 @@ on: [ pull_request, workflow_dispatch ] env: HOST: https://ci.jitx.com TEAM: main - PIPELINE: lbstanza + PIPELINE: stanzapm INSTVARS: vars.branch="${{ github.base_ref }}" TOKEN: ${{ secrets.CONCOURSE_WEBHOOK_TOKEN }} jobs: diff --git a/.github/workflows/concourse-notify-push.yml b/.github/workflows/concourse-notify-push.yml index f8f4dcce..edc0a98c 100644 --- a/.github/workflows/concourse-notify-push.yml +++ b/.github/workflows/concourse-notify-push.yml @@ -3,7 +3,7 @@ on: [ push, workflow_dispatch ] env: HOST: https://ci.jitx.com TEAM: main - PIPELINE: lbstanza + PIPELINE: stanzapm INSTVARS: vars.branch="${{ github.ref_name }}" TOKEN: ${{ secrets.CONCOURSE_WEBHOOK_TOKEN }} jobs: From 7f2a205cf30da54fd0226fd8245e0094b7a65075 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Thu, 6 Feb 2025 18:55:33 -0500 Subject: [PATCH 03/24] ci: point to stanzapm pipelines (2) --- ci/build-stanza.sh | 4 ++-- ci/calc-stanza-version-bump.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/build-stanza.sh b/ci/build-stanza.sh index 604f0d66..829a7a7b 100755 --- a/ci/build-stanza.sh +++ b/ci/build-stanza.sh @@ -11,7 +11,7 @@ USAGE="STANZA_CONFIG=/path $0" echo " STANZA_CONFIG:" "${STANZA_CONFIG:?Usage: ${USAGE}}" # directory where .stanza config file will be stored, as in normal stanza behavior # Defaulted env var inputs - can override if necessary -echo " REPODIR:" "${REPODIR:=lbstanza}" +echo " REPODIR:" "${REPODIR:=stanzapm}" echo " CONAN_USER_HOME:" "${CONAN_USER_HOME:=${REPODIR}}" echo " CREATE_ARCHIVE:" "${CREATE_ARCHIVE:=false}" echo " CREATE_PACKAGE:" "${CREATE_PACKAGE:=false}" @@ -79,7 +79,7 @@ esac cd "${REPODIR}" -echo "Building lbstanza version ${VER} in ${PWD}" +echo "Building stanzapm version ${VER} in ${PWD}" mkdir -p build mkdir -p bin diff --git a/ci/calc-stanza-version-bump.sh b/ci/calc-stanza-version-bump.sh index 305c5755..b2ebac9a 100755 --- a/ci/calc-stanza-version-bump.sh +++ b/ci/calc-stanza-version-bump.sh @@ -10,7 +10,7 @@ TOP="${PWD}" >&2 echo " BRANCH:" "${BRANCH:?Usage: BRANCH=foo $0}" # Defaulted env var inputs - can override if necessary ->&2 echo " REPODIR:" "${REPODIR:=lbstanza}" +>&2 echo " REPODIR:" "${REPODIR:=stanzapm}" ## By default, get the most recent previous tag on this branch from git ### note: if multiple tags exist on one commit, git doesn't always desecribe the most recent one ### ### maybe use: git tag --sort=committerdate --contains HEAD~ | tail -1 From 9c1cbe8cb584e8db21cc4e8e51b98c72114ab669 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Thu, 6 Feb 2025 19:02:47 -0500 Subject: [PATCH 04/24] ci: point to stanzapm pipelines (3) --- .github/workflows/concourse-notify-pull-request.yml | 2 +- .github/workflows/concourse-notify-push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/concourse-notify-pull-request.yml b/.github/workflows/concourse-notify-pull-request.yml index 335969f9..f7e29adf 100644 --- a/.github/workflows/concourse-notify-pull-request.yml +++ b/.github/workflows/concourse-notify-pull-request.yml @@ -10,7 +10,7 @@ jobs: trigger-pr: runs-on: ubuntu-latest env: - RESOURCE: github--lbstanza--pr + RESOURCE: github--stanzapm--pr steps: - name: Trigger Concourse Pull Request run: | diff --git a/.github/workflows/concourse-notify-push.yml b/.github/workflows/concourse-notify-push.yml index edc0a98c..0ee2e879 100644 --- a/.github/workflows/concourse-notify-push.yml +++ b/.github/workflows/concourse-notify-push.yml @@ -10,7 +10,7 @@ jobs: trigger-push: runs-on: ubuntu-latest env: - RESOURCE: git--lbstanza + RESOURCE: git--stanzapm steps: - name: Trigger Concourse resource check run: | From b17face8cf060c62ae410809f2ad47c7a0866331 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Thu, 6 Feb 2025 20:51:32 -0500 Subject: [PATCH 05/24] ci: build using stanzapm release --- ci/build-stanza-version.txt | 2 +- ci/install-stanza.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/build-stanza-version.txt b/ci/build-stanza-version.txt index 71434844..53753a14 100644 --- a/ci/build-stanza-version.txt +++ b/ci/build-stanza-version.txt @@ -7,4 +7,4 @@ # like 1.23.45 # # Use version 0.17.56 to compile 0.18.0 -0.18.96 +0.19.0 diff --git a/ci/install-stanza.sh b/ci/install-stanza.sh index eff3409e..5afc2481 100755 --- a/ci/install-stanza.sh +++ b/ci/install-stanza.sh @@ -11,8 +11,8 @@ TOP="${PWD}" # the machine that you are building for (host) # and the machine that GCC will produce code for (target). -USAGE="STANZA_BUILD_PLATFORM={linux|macos|windows} STANZA_BUILD_VER=0.17.56 STANZA_CONFIG=/path STANZA_INSTALL_DIR=/path $0" -STANZA_DOWNLOAD_BASEURL="https://github.com/StanzaOrg/lbstanza/releases/download" +USAGE="STANZA_BUILD_PLATFORM={linux|macos|windows} STANZA_BUILD_VER=0.19.0 STANZA_CONFIG=/path STANZA_INSTALL_DIR=/path $0" +STANZA_DOWNLOAD_BASEURL="https://github.com/jitx-inc/stanzapm/releases/download" # Required env var inputs @@ -27,7 +27,7 @@ BSVTXT="${THISDIR}/build-stanza-version.txt" # extract the version from first non-comment line of the file BSTZVER=$(grep -v ^\# "${BSVTXT}" | head -1 | awk '{ print $1}') echo "Using existing stanza version $BSTZVER" -echo " STANZA_BUILD_VER:" "${STANZA_BUILD_VER:=${BSTZVER}}" # 0.17.56 +echo " STANZA_BUILD_VER:" "${STANZA_BUILD_VER:=${BSTZVER}}" # 0.19.0 echo "STANZA_BUILD_PLATFORM:" "${STANZA_BUILD_PLATFORM:=$(uname -s)}" # linux|macos|Darwin|windows|MINGW64 # var input validation From 09bbc2af67f8815b216ac7af98d803d5c02e14b4 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Fri, 7 Feb 2025 12:36:47 -0500 Subject: [PATCH 06/24] Bump version to 0.19.1 --- compiler/params.stanza | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/params.stanza b/compiler/params.stanza index fb23f7db..cb5e6ae8 100644 --- a/compiler/params.stanza +++ b/compiler/params.stanza @@ -18,7 +18,7 @@ public defn compiler-flags () : to-tuple(COMPILE-FLAGS) ;========= Stanza Configuration ======== -public val STANZA-VERSION = [0 19 0] +public val STANZA-VERSION = [0 19 1] public var STANZA-INSTALL-DIR:String = "" public var OUTPUT-PLATFORM:Symbol = `platform public var STANZA-PKG-DIRS:List = List() From b8812b58c3beb470e22b836d00f4495cd21f2f58 Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Tue, 11 Mar 2025 13:38:06 -0700 Subject: [PATCH 07/24] optionally set max-heap-size in gigs using STANZA_MAX_HEAP_SIZE env var at startup --- runtime/driver.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/runtime/driver.c b/runtime/driver.c index 2222b12a..01cdd038 100644 --- a/runtime/driver.c +++ b/runtime/driver.c @@ -677,7 +677,16 @@ STANZA_API_FUNC int MAIN_FUNC (int argc, char* argv[]) { VMInit init; //Allocate heap - const stz_long min_heap_size = ROUND_UP_TO_WHOLE_PAGES(8 * 1024 * 1024); + char* max_heap_gigs_var = getenv("STANZA_MAX_HEAP_SIZE"); + stz_long max_heap_gigs = STZ_LONG(8); + if (max_heap_gigs_var != NULL) { + max_heap_gigs = atol(max_heap_gigs_var); + if (max_heap_gigs <= 0L) { + fprintf(stderr, "STANZA_MAX_HEAP_SIZE must be an integer number of gigabytes: %s\n", max_heap_gigs_var); + exit(-1); + } + } + const stz_long min_heap_size = ROUND_UP_TO_WHOLE_PAGES(max_heap_gigs * 1024 * 1024); const stz_long max_heap_size = ROUND_UP_TO_WHOLE_PAGES(STZ_LONG(8) * 1024 * 1024 * 1024); init.heap_start = (stz_byte*)stz_memory_map(min_heap_size, max_heap_size); init.heap_max_size = max_heap_size; From 5301126cf16949cba37eadccba4dba4002c770e4 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Tue, 11 Mar 2025 16:48:52 -0400 Subject: [PATCH 08/24] Reset version to 0.19.4-rc.0 From 90e2ca359e16596540742cad1837e5f46ad2f911 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Tue, 11 Mar 2025 16:54:21 -0400 Subject: [PATCH 09/24] Reset version to 0.19.4-rc.0 (params) --- compiler/params.stanza | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/params.stanza b/compiler/params.stanza index cb5e6ae8..a4504488 100644 --- a/compiler/params.stanza +++ b/compiler/params.stanza @@ -18,7 +18,7 @@ public defn compiler-flags () : to-tuple(COMPILE-FLAGS) ;========= Stanza Configuration ======== -public val STANZA-VERSION = [0 19 1] +public val STANZA-VERSION = [0 19 3] public var STANZA-INSTALL-DIR:String = "" public var OUTPUT-PLATFORM:Symbol = `platform public var STANZA-PKG-DIRS:List = List() From d675285c1e9c882e5afced6ace1c23dca41fcd80 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Tue, 11 Mar 2025 16:54:35 -0400 Subject: [PATCH 10/24] Reset version to 0.19.4-rc.0 (again) From 6d36e42b8fdbaf196ef2a72404b7253b87c34081 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Tue, 11 Mar 2025 16:56:29 -0400 Subject: [PATCH 11/24] Reset version to 0.19.4-rc.0 (3) From 6358ede3119420d6ce2affeda79304f4e0e86fde Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Tue, 11 Mar 2025 16:56:47 -0400 Subject: [PATCH 12/24] Reset version to 0.19.4-rc.0 (4) From 3e9a114d56fc4dddd7beab1bb21d92988f9b01de Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Tue, 11 Mar 2025 16:59:50 -0400 Subject: [PATCH 13/24] Reset version to 0.19.4-rc.0 (5) From 5ca58b46f13dc5d2c933e099f7e436fb487ec062 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Tue, 11 Mar 2025 16:59:58 -0400 Subject: [PATCH 14/24] Reset version to 0.19.4-rc.0 (6) From ff679f0c471be858e73a3cd6d6c87478b62b9139 Mon Sep 17 00:00:00 2001 From: Jason Watson Date: Tue, 11 Mar 2025 17:15:39 -0400 Subject: [PATCH 15/24] Bump version to 0.19.4 --- compiler/params.stanza | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/params.stanza b/compiler/params.stanza index a4504488..829338fc 100644 --- a/compiler/params.stanza +++ b/compiler/params.stanza @@ -18,7 +18,7 @@ public defn compiler-flags () : to-tuple(COMPILE-FLAGS) ;========= Stanza Configuration ======== -public val STANZA-VERSION = [0 19 3] +public val STANZA-VERSION = [0 19 4] public var STANZA-INSTALL-DIR:String = "" public var OUTPUT-PLATFORM:Symbol = `platform public var STANZA-PKG-DIRS:List = List() From 1f115e1b5f9d4d871cce39b8a5aeb1850113fa62 Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Wed, 12 Mar 2025 13:52:01 -0700 Subject: [PATCH 16/24] use raw array as array to make it concrete and rename array to arrayable --- core/core.stanza | 102 +++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 65 deletions(-) diff --git a/core/core.stanza b/core/core.stanza index a2a602ac..cc5109ad 100644 --- a/core/core.stanza +++ b/core/core.stanza @@ -7517,83 +7517,55 @@ public defn lazy-qsort (key:T -> ?S&Comparable, coll:Seqable) : ;======================= Arrays ============================= ;============================================================ -public deftype Array <: IndexedCollection & Unique +public deftype Arrayable <: IndexedCollection & Unique ; Implementation ; ============== -lostanza deftype RawArray <: Array : +public lostanza deftype Array <: Arrayable : length: long var items: ref ... -lostanza defn RawArray (n:ref, x:ref) -> ref> : - val l = n.value - val a = new RawArray{l} - for (var i:long = 0, i < l, i = i + 1) : - a.items[i] = x - return a +lostanza defn Array* (n:ref, x:ref) -> ref> : + val l = n.value + val a = new Array{l} + for (var i:long = 0, i < l, i = i + 1) : + a.items[i] = x + return a + +public defn Array (n:Int, x:T) -> Array : + core/ensure-non-negative("length", n) + Array*(n, x) + +public defn Array (n:Int) -> Array : + Array*(n, sentinel) -lostanza defmethod get (a:ref>, i:ref) -> ref : +lostanza defmethod get (a:ref>, i:ref) -> ref : + #if-not-defined(OPTIMIZE) : + core/ensure-index-in-bounds(a, i) return a.items[i.value] -lostanza defmethod set (a:ref>, i:ref, v:ref) -> ref : +lostanza defmethod set (a:ref>, i:ref, v:ref) -> ref : + #if-not-defined(OPTIMIZE) : + core/ensure-index-in-bounds(a, i) a.items[i.value] = v return false -lostanza defmethod set-all (xs:ref>, r:ref, v:ref) -> ref : - val range = range-bound(xs, r) as ref> - val b = range.items[0].value - val e = range.items[1].value - for (var i:long = b, i < e, i = i + 1) : - xs.items[i] = v - return false - -lostanza defmethod length (a:ref) -> ref : - return new Int{a.length as int} - -defmethod print (o:OutputStream, a:RawArray) -> False : - print(o, "[%@]" % [a]) - -; Wrapping -; ======== - -#if-defined(OPTIMIZE) : - - public defn Array (n:Int) -> RawArray : - RawArray(n, sentinel) - - public defn Array (n:Int, x:T) -> RawArray : - RawArray(n, x) +lostanza defmethod set-all (xs:ref>, r:ref, v:ref) -> ref : + #if-not-defined(OPTIMIZE) : + core/ensure-index-range(xs, r) + val range = core/range-bound(xs, r) as ref> + val b = range.items[0].value + val e = range.items[1].value + for (var i:long = b, i < e, i = i + 1) : + xs.items[i] = v + return false -#else : +lostanza defmethod length (a:ref) -> ref : + return new Int{a.length as int} - deftype WrappedArray <: Array - - public defn Array (n:Int) -> Array : - ensure-non-negative("length", n) - Array(RawArray(n, sentinel)) - - public defn Array (n:Int, x:T) -> Array : - ensure-non-negative("length", n) - Array(RawArray(n, x)) - - defn Array (a:RawArray) -> Array : - new WrappedArray : - defmethod get (this, i:Int) : - ensure-index-in-bounds(a, i) - match(a[i]) : - (v:Sentinel) : fatal("Index (%_) is uninitialized." % [i]) - (v) : v - defmethod set (this, i:Int, v:T) : - ensure-index-in-bounds(a, i) - a[i] = v - defmethod set-all (this, r:Range, v:T) : - ensure-index-range(a, r) - set-all(a, r, v) - defmethod length (this) : - length(a) - defmethod print (o:OutputStream, this) : - print(o, a) +defmethod print (o:OutputStream, a:Array) -> False : + print(o, "[%@]" % [a]) public defn map (xs:Array, f: T -> R) -> Array : map(f, xs) @@ -7616,7 +7588,7 @@ public defn map (f: T -> R, xs:Array) -> Array : ; Declaration ; =========== - public lostanza deftype PrimArray <: Array : + public lostanza deftype PrimArray <: Arrayable : length: long var data: prim ... @@ -7688,7 +7660,7 @@ public defn map (f: T -> R, xs:Array) -> Array : ;==================== CharArrays ============================ ;============================================================ -public lostanza deftype CharArray <: Array : +public lostanza deftype CharArray <: Arrayable : length: long var chars: byte ... @@ -7754,7 +7726,7 @@ defmethod block-copy (n:Int, dst:IndexedCollection, di:Int, src:IndexedC for i in 0 to n do : dst[di + i] = src[si + i] -lostanza defmethod block-copy (ref-n:ref, dst:ref, ref-di:ref, src:ref, ref-si:ref) -> ref : +lostanza defmethod block-copy (ref-n:ref, dst:ref, ref-di:ref, src:ref, ref-si:ref) -> ref : ensure-block-copy-preconditions(ref-n, dst, ref-di, src, ref-si) val dst-ptr = addr!(dst.items) val src-ptr = addr!(src.items) From 213c2e13ed09cafb773eb77b30666d1c3f14cbd8 Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Wed, 12 Mar 2025 13:52:41 -0700 Subject: [PATCH 17/24] convert vector to defstruct with lostanza deftype and use intarray where you can in sets/tables --- core/collections.stanza | 209 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 191 insertions(+), 18 deletions(-) diff --git a/core/collections.stanza b/core/collections.stanza index c0a80c26..fe72c40f 100644 --- a/core/collections.stanza +++ b/core/collections.stanza @@ -53,6 +53,17 @@ defn bsearch (less?: (T, S) -> True|False, if xs[i + m] < v : loop(i + m + 1, n - m - 1) else : loop(i, m) +defn bsearch (less?: (Int, Int) -> True|False, xs:IntArray, n:Int, v:Int) -> Int : + ;All items with index less than i are known to be smaller than v. + ;All items with index (i + n) or greater are known to be greater or equal to v. + let loop (i:Int = 0, n:Int = n) : + if n == 0 : + i + else : + val m = n / 2 + if xs[i + m] < v : loop(i + m + 1, n - m - 1) + else : loop(i, m) + ;============================================================ ;===================== Vectors ============================== ;============================================================ @@ -60,7 +71,28 @@ defn bsearch (less?: (T, S) -> True|False, ; Interface ; ========= -public deftype Vector <: IndexedCollection +public lostanza deftype Vector <: IndexedCollection : + var size: long + var array: ref> + +public lostanza defn Vector (cap:ref) -> ref> : + core/ensure-non-negative(String("capacity"), cap) + return new Vector{0L, Array(cap)} + +lostanza defn size (v:ref) -> ref : + return new Int{v.size as int} + +lostanza defn set-size (v:ref, s:ref) -> ref : + v.size = s.value as long + return false + +lostanza defn array (v:ref>) -> ref> : + return v.array + +lostanza defn set-array (v:ref, a:ref) -> ref : + v.array = a + return false + public defmulti add (v:Vector, value:T) -> False public defmulti add-all (v:Vector, vs:Seqable) -> False public defmulti clear (v:Vector) -> False @@ -81,6 +113,146 @@ public defmulti set-length (v:Vector, length:Int, x:T) -> False ; Implementation ; ============== +defn set-capacity (v:Vector, c:Int) : + val new-array = Array(c) + new-array[0 to size(v)] = array(v) + set-array(v, new-array) + +defn ensure-capacity (v:Vector, c:Int) : + val cur-c = length(array(v)) + set-capacity(v, max(c, 2 * cur-c)) when c > cur-c + +defmethod get (v:Vector, i:Int) : + core/ensure-index-in-bounds(v, i) + array(v)[i] + +defmethod set (v:Vector, i:Int, value:T) : + if i == size(v) : + add(v, value) + else : + core/ensure-index-in-bounds(v, i) + array(v)[i] = value + +defmethod set-all (v:Vector, r:Range, x:T) : + core/ensure-index-range(v, r) + set-all(array(v), r, x) + +defmethod length (v:Vector) : + size(v) + +defmethod trim (v:Vector) : + set-capacity(v, size(v)) + +defmethod set-length (v:Vector, len:Int, value:T) : + if len > size(v) : lengthen(v, len, value) + else : shorten(v, len) + +defmethod shorten (v:Vector, new-size:Int) : + #if-not-defined(OPTIMIZE) : + core/ensure-non-negative("size", new-size) + if new-size > size(v) : + fatal("Given size (%_) is larger than current size (%_)." % [new-size, size(v)]) + set-size(v, new-size) + +defmethod lengthen (v:Vector, new-size:Int, x:T) : + #if-not-defined(OPTIMIZE) : + if new-size < size(v) : + fatal("Given size (%_) is smaller than current size (%_)." % [new-size, size(v)]) + ensure-capacity(v, new-size) + set-all(array(v), size(v) to new-size, x) + set-size(v, new-size) + +defmethod add (v:Vector, value:T) : + val sz = size(v) + ensure-capacity(v, sz + 1) + array(v)[sz] = value + set-size(v, sz + 1) + +defmethod add-all (v:Vector, vs:Seqable) : + match(vs) : + (vs:Seqable & Lengthable) : + val n = length(vs) + ensure-capacity(v, size(v) + n) + array(v)[size(v) to (size(v) + n)] = vs + set-size(v, size(v) + n) + (vs) : + do(add{v, _}, vs) + +defmethod pop (v:Vector) : + #if-not-defined(OPTIMIZE) : + fatal("Empty Vector") when size(v) == 0 + set-size(v, size(v) - 1) + array(v)[size(v)] + +defmethod peek (v:Vector) : + #if-not-defined(OPTIMIZE) : + fatal("Empty Vector") when size(v) == 0 + array(v)[size(v) - 1] + +defmethod clear (v:Vector) : + set-size(v, 0) + +defmethod clear (v:Vector, n:Int, x0:T) : + if length(array(v)) < n : + val cap = max(n, 2 * length(array(v))) + set-array(v, Array(cap, x0)) + set-size(v, n) + else : + set-all(array(v), 0 to n, x0) + set-size(v, n) + +defmethod remove-when (f: T -> True|False, v:Vector) : + for x in v update : + if f(x) : None() + else : One(x) + +defmethod remove (v:Vector, i:Int) : + core/ensure-index-in-bounds(v, i) + val a = array(v) + val x = a[i] + for i in i to (size(v) - 1) do : + a[i] = a[i + 1] + set-size(v, size(v) - 1) + x + +defmethod remove (v:Vector, r:Range) : + core/ensure-index-range(v, r) + val [s,e] = core/range-bound(v, r) + val n = e - s + val a = array(v) + val sz = size(v) + if n > 0 : + for i in s to (sz - n) do : + a[i] = a[i + n] + set-size(v, sz - n) + +defmethod remove-item (v:Vector, x:T&Equalable) : + match(index-of(v, x)) : + (i:Int) : (remove(v, i), true) + (i:False) : false + +defmethod update (f: T -> Maybe, v:Vector) : + val a = array(v) + let loop (dst:Int = 0, src:Int = 0) : + if src < size(v) : + match(f(a[src])) : + (x:One) : + a[dst] = value(x) + loop(dst + 1, src + 1) + (x:None) : + loop(dst, src + 1) + else : + set-size(v, dst) + +defmethod do (f: T -> ?, v:Vector) : + val n = size(v) + val a = array(v) + let loop (i:Int = 0) : + if i < n : + f(a[i]) + loop(i + 1) + +; public defn Vector (cap:Int) -> Vector : core/ensure-non-negative("capacity", cap) var array = Array(cap) @@ -220,6 +392,7 @@ public defn Vector (cap:Int) -> Vector : if i < n : f(array[i]) loop(i + 1) +; public defn update (v:Vector, f: T -> Maybe) -> False : update(f,v) @@ -438,7 +611,7 @@ public defn HashTable (cap0:Int limit = c * 3 / 4 mask = cap - 1 slots = Array|Array>>(cap, sentinel()) - sizes = Array(cap, 0) + sizes = IntArray(cap, 0) size = 0 defn clear () : @@ -861,7 +1034,7 @@ public defn IntTable (cap0:Int limit = c * 3 / 4 mask = cap - 1 slots = Array|Array>>(cap, sentinel()) - sizes = Array(cap, 0) + sizes = IntArray(cap, 0) size = 0 defn clear () : @@ -1280,7 +1453,7 @@ public defn HashSet (cap0:Int limit = c * 3 / 4 mask = cap - 1 slots = Array|Array>>(cap, sentinel()) - sizes = Array(cap, 0) + sizes = IntArray(cap, 0) size = 0 defn clear () : @@ -1533,8 +1706,8 @@ public defn IntSet (cap0:Int) : cap = c limit = c * 3 / 4 mask = cap - 1 - slots = Array>(cap, sentinel()) - sizes = Array(cap, 0) + slots = Array(cap, sentinel()) + sizes = IntArray(cap, 0) size = 0 defn clear () : @@ -1550,28 +1723,28 @@ public defn IntSet (cap0:Int) : h & mask ;Find number of items whose hash is less than h - defn num-before (xs:Array, n:Int, x:Int) : + defn num-before (xs:IntArray, n:Int, x:Int) : bsearch(less?, xs, n, x) ;Look for item with given hash and key starting from i - defn* index-of-item (xs:Array, i:Int, n:Int, y:Int) : + defn* index-of-item (xs:IntArray, i:Int, n:Int, y:Int) : if i < n : val x = xs[i] if x == y : i ;Shift items in xs from i to n right by one element - defn* shift-right (xs:Array, i:Int, n:Int) : + defn* shift-right (xs:IntArray, i:Int, n:Int) : for j in n to i by -1 do : xs[j] = xs[j - 1] ;Shift items in xs from (i + 1) to n left by one element - defn* shift-left (xs:Array, i:Int, n:Int) : + defn* shift-left (xs:IntArray, i:Int, n:Int) : for j in i to (n - 1) do : xs[j] = xs[j + 1] ;Copy to new array with hole in position i - defn* copy-with-hole (xs:Array, i:Int, n:Int) : - val xs* = Array(length(xs) * 2) + defn* copy-with-hole (xs:IntArray, i:Int, n:Int) : + val xs* = IntArray(length(xs) * 2) xs*[0 to i] = xs[0 to i] xs*[(i + 1) to (n + 1)] = xs[i to n] xs* @@ -1592,7 +1765,7 @@ public defn IntSet (cap0:Int) : do(put, items) defn create-bucket (slot:Int, x0:Int, x1:Int) : - val bucket = Array(4) + val bucket = IntArray(4) slots[slot] = bucket sizes[slot] = 2 ;Populate bucket @@ -1605,7 +1778,7 @@ public defn IntSet (cap0:Int) : bucket[0] = x1 bucket[1] = x0 - defn add-to-bucket (slot:Int, bucket:Array, i:Int, n:Int, x:Int) : + defn add-to-bucket (slot:Int, bucket:IntArray, i:Int, n:Int, x:Int) : ;Case 1 of 2: Bucket has space. if n + 1 < length(bucket) : shift-right(bucket, i, n) @@ -1641,7 +1814,7 @@ public defn IntSet (cap0:Int) : increment-size() true ;Case 3 of 3: Multiple item bucket - (s:Array) : + (s:IntArray) : val n = sizes[slot] val i = num-before(s, n, x) match(index-of-item(s, i, n, x)) : @@ -1665,7 +1838,7 @@ public defn IntSet (cap0:Int) : ;Case 2 of 3: Single item bucket (s:Int) : s == x ;Case 3 of 3: Multiple item bucket - (s:Array) : + (s:IntArray) : val n = sizes[slot] val i = num-before(s, n, x) index-of-item(s, i, n, x) is Int @@ -1687,7 +1860,7 @@ public defn IntSet (cap0:Int) : decrement-size() true ;Case 3 of 3: Multiple item bucket - (s:Array) : + (s:IntArray) : val n = sizes[slot] val i = num-before(s, n, x) match(index-of-item(s, i, n, x)) : @@ -1709,7 +1882,7 @@ public defn IntSet (cap0:Int) : match(slots[idx]) : (s:Sentinel) : false (s:Int) : yield(s) - (s:Array) : for j in 0 to sizes[idx] do : yield(s[j]) + (s:IntArray) : for j in 0 to sizes[idx] do : yield(s[j]) ;====================== ;==== Table Object ==== From 2558a378a23c5ed11f0da7ea3dea6db53734f266 Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Wed, 12 Mar 2025 20:05:43 -0700 Subject: [PATCH 18/24] define Vector and Queue using defstruct --- core/collections.stanza | 281 ++++++++++------------------------------ 1 file changed, 65 insertions(+), 216 deletions(-) diff --git a/core/collections.stanza b/core/collections.stanza index fe72c40f..f718b90d 100644 --- a/core/collections.stanza +++ b/core/collections.stanza @@ -71,27 +71,15 @@ defn bsearch (less?: (Int, Int) -> True|False, xs:IntArray, n:Int, v:Int) -> Int ; Interface ; ========= -public lostanza deftype Vector <: IndexedCollection : - var size: long - var array: ref> +public defstruct Vector <: IndexedCollection : + size: Int with: (setter => set-size, init => 0) + array: Array with: (setter => set-array) +with: + constructor => #Vector -public lostanza defn Vector (cap:ref) -> ref> : +public defn Vector (cap:Int) -> Vector : core/ensure-non-negative(String("capacity"), cap) - return new Vector{0L, Array(cap)} - -lostanza defn size (v:ref) -> ref : - return new Int{v.size as int} - -lostanza defn set-size (v:ref, s:ref) -> ref : - v.size = s.value as long - return false - -lostanza defn array (v:ref>) -> ref> : - return v.array - -lostanza defn set-array (v:ref, a:ref) -> ref : - v.array = a - return false + #Vector(Array(cap)) public defmulti add (v:Vector, value:T) -> False public defmulti add-all (v:Vector, vs:Seqable) -> False @@ -252,148 +240,6 @@ defmethod do (f: T -> ?, v:Vector) : f(a[i]) loop(i + 1) -; -public defn Vector (cap:Int) -> Vector : - core/ensure-non-negative("capacity", cap) - var array = Array(cap) - var size = 0 - - defn set-capacity (c:Int) : - val new-array = Array(c) - new-array[0 to size] = array - array = new-array - - defn ensure-capacity (c:Int) : - val cur-c = length(array) - set-capacity(max(c, 2 * cur-c)) when c > cur-c - - new Vector : - defmethod get (this, i:Int) : - core/ensure-index-in-bounds(this, i) - array[i] - - defmethod set (this, i:Int, value:T) : - if i == size : - add(this, value) - else : - core/ensure-index-in-bounds(this, i) - array[i] = value - - defmethod set-all (this, r:Range, v:T) : - core/ensure-index-range(this, r) - set-all(array, r, v) - - defmethod length (this) : - size - - defmethod trim (this) : - set-capacity(size) - - defmethod set-length (this, len:Int, value:T) : - if len > size : lengthen(this, len, value) - else : shorten(this, len) - - defmethod shorten (this, new-size:Int) : - #if-not-defined(OPTIMIZE) : - core/ensure-non-negative("size", new-size) - if new-size > size : - fatal("Given size (%_) is larger than current size (%_)." % [new-size, size]) - size = new-size - - defmethod lengthen (this, new-size:Int, x:T) : - #if-not-defined(OPTIMIZE) : - if new-size < size : - fatal("Given size (%_) is smaller than current size (%_)." % [new-size, size]) - ensure-capacity(new-size) - set-all(array, size to new-size, x) - size = new-size - - defmethod add (this, value:T) : - ensure-capacity(size + 1) - array[size] = value - size = size + 1 - - defmethod add-all (this, vs:Seqable) : - match(vs) : - (vs:Seqable & Lengthable) : - val n = length(vs) - ensure-capacity(size + n) - array[size to (size + n)] = vs - size = size + n - (vs) : - do(add{this, _}, vs) - - defmethod pop (this) : - #if-not-defined(OPTIMIZE) : - fatal("Empty Vector") when size == 0 - size = size - 1 - array[size] - - defmethod peek (this) : - #if-not-defined(OPTIMIZE) : - fatal("Empty Vector") when size == 0 - array[size - 1] - - defmethod clear (this) : - size = 0 - - defmethod clear (this, n:Int, x0:T) : - if length(array) < n : - val cap = max(n, 2 * length(array)) - array = Array(cap, x0) - size = n - else : - set-all(array, 0 to n, x0) - size = n - - defmethod remove-when (f: T -> True|False, this) : - for x in this update : - if f(x) : None() - else : One(x) - - defmethod remove (this, i:Int) : - core/ensure-index-in-bounds(this, i) - val x = array[i] - for i in i to (size - 1) do : - array[i] = array[i + 1] - size = size - 1 - x - - defmethod remove (this, r:Range) : - core/ensure-index-range(this, r) - val [s,e] = core/range-bound(this, r) - val n = e - s - if n > 0 : - for i in s to (size - n) do : - array[i] = array[i + n] - size = size - n - - defmethod remove-item (this:Vector, x:T&Equalable) : - match(index-of(this, x)) : - (i:Int) : (remove(this, i), true) - (i:False) : false - - defmethod update (f: T -> Maybe, this) : - defn* loop (dst:Int, src:Int) : - if src < size : - match(f(array[src])) : - (x:One) : - array[dst] = value(x) - loop(dst + 1, src + 1) - (x:None) : - loop(dst, src + 1) - else : - size = dst - loop(0, 0) - - defmethod do (f: T -> ?, this) : - val n = size - let loop (i:Int = 0) : - if i < n : - f(array[i]) - loop(i + 1) -; - public defn update (v:Vector, f: T -> Maybe) -> False : update(f,v) @@ -430,7 +276,6 @@ defmethod print (o:OutputStream, v:Vector) : ; Interface ; ========= -public deftype Queue <: IndexedCollection public defmulti add (q:Queue, x:T) -> False public defmulti clear (q:Queue) -> False public defmulti pop (q:Queue) -> T @@ -439,63 +284,67 @@ public defmulti peek (q:Queue) -> T ; Implementation ; ============== +public defstruct Queue <: IndexedCollection : + cap:Int with: (setter => set-cap) + array:Array with: (setter => set-array, init => Array(cap)) + begin:Int with: (setter => set-begin, init => 0) + size:Int with: (setter => set-size, init => 0) +with: + constructor => #Queue + public defn Queue (initial-cap:Int) -> Queue : - core/ensure-non-negative("capacity", initial-cap) - var cap:Int = next-pow2(initial-cap) - var array:Array = Array(cap) - var begin:Int = 0 - var size:Int = 0 - - defn ensure-capacity (c:Int) : - defn set-capacity (c:Int) : - val new-array = Array(c) - for i in 0 to size do : - new-array[i] = array[wrapped-index(i)] - array = new-array - cap = c - begin = 0 - set-capacity(next-pow2(c)) when c > cap - - defn wrapped-index (i:Int) : - (begin + i) & (cap - 1) - - new Queue : - defmethod get (this, i:Int) : - core/ensure-index-in-bounds(this, i) - array[wrapped-index(i)] - - defmethod set (this, i:Int, value:T) : - if i == -1 : - add(this, value) - else : - core/ensure-index-in-bounds(this, i) - array[wrapped-index(i)] = value - - defmethod add (this, x:T) : - ensure-capacity(size + 1) - begin = wrapped-index(-1 + cap) - array[begin] = x - size = size + 1 - - defmethod pop (this) : - #if-not-defined(OPTIMIZE) : - fatal("Empty Queue") when size == 0 - size = size - 1 - array[wrapped-index(size)] - - defmethod peek (this) : - #if-not-defined(OPTIMIZE) : - fatal("Empty Queue") when size == 0 - array[wrapped-index(size - 1)] - - defmethod length (this) : - size - - defmethod clear (this) : - size = 0 + core/ensure-non-negative("capacity", initial-cap) + #Queue(next-pow2(initial-cap)) + +defn ensure-capacity (q:Queue, c:Int) : + defn set-capacity (c:Int) : + val new-array = Array(c) + for i in 0 to size(q) do : + new-array[i] = array(q)[wrapped-index(q, i)] + set-array(q, new-array) + set-cap(q, c) + set-begin(q, 0) + set-capacity(next-pow2(c)) when c > cap(q) + +defn wrapped-index (q:Queue, i:Int) : + (begin(q) + i) & (cap(q) - 1) + +defmethod get (q:Queue, i:Int) : + core/ensure-index-in-bounds(q, i) + array(q)[wrapped-index(q, i)] + +defmethod set (q:Queue, i:Int, value:T) : + if i == -1 : + add(q, value) + else : + core/ensure-index-in-bounds(q, i) + array(q)[wrapped-index(q, i)] = value + +defmethod add (q:Queue, x:T) : + ensure-capacity(q, size(q) + 1) + set-begin(q, wrapped-index(q, -1 + cap(q))) + array(q)[begin(q)] = x + set-size(q, size(q) + 1) + +defmethod pop (q:Queue) : + #if-not-defined(OPTIMIZE) : + fatal("Empty Queue") when size(q) == 0 + set-size(q, size(q) - 1) + array(q)[wrapped-index(q, size(q))] + +defmethod peek (q:Queue) : + #if-not-defined(OPTIMIZE) : + fatal("Empty Queue") when size(q) == 0 + array(q)[wrapped-index(q, size(q) - 1)] + +defmethod length (q:Queue) : + size(q) + +defmethod clear (q:Queue) : + set-size(q, 0) public defn Queue () -> Queue : - Queue(8) + Queue(8) ;================================== ;======== Printer / Writer ======== From 1fa416f3e1578e396b05b3dc3e44d4221338fa26 Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Thu, 13 Mar 2025 16:28:39 -0700 Subject: [PATCH 19/24] converted all tables and sets to use defstruct --- core/collections.stanza | 2195 +++++++++++++++++++-------------------- 1 file changed, 1078 insertions(+), 1117 deletions(-) diff --git a/core/collections.stanza b/core/collections.stanza index f718b90d..38ea55ff 100644 --- a/core/collections.stanza +++ b/core/collections.stanza @@ -438,370 +438,362 @@ defmethod same-contents? (a:Table, b:Table) : ;====================== HashTables ========================== ;============================================================ -public deftype HashTable <: Table +public defstruct HashTable <: Table : + cap : Int with: (setter => set-cap) + limit : Int with: (setter => set-limit, init => cap * 3 / 4) + mask : Int with: (setter => set-mask, init => cap - 1) + slots : Array|Array>> with: (setter => set-slots, init => Array|Array>>(cap, sentinel())) + sizes : IntArray with: (setter => set-sizes, init => IntArray(cap, 0)) + size : Int with: (setter => set-size, init => 0) + key-hash : K -> Int + key-equal? : (K,K) -> True | False + default : K -> V + create-on-default: True|False +with: + constructor => #HashTable + +defn key-hash (t:HashTable, k:K) -> Int : + key-hash(t)(k) + +defn key-equal? (t:HashTable, x:K, y:K) -> True|False : + key-equal?(t)(x, y) + +defn init (t:HashTable, c:Int) : + set-cap(t, c) + set-limit(t, c * 3 / 4) + set-mask(t, c - 1) + set-slots(t, Array|Array>>(c, sentinel())) + set-sizes(t, IntArray(c, 0)) + set-size(t, 0) + +defn clear (t:HashTable) : + set-size(t, 0) + set-all(slots(t), 0 to false, sentinel()) -public defn HashTable (cap0:Int - key-hash: K -> Int +public defn HashTable (cap0:Int, + key-hash: K -> Int, key-equal?: (K,K) -> True|False default: K -> V, - create-on-default:True|False) : - ;===================== - ;==== Table State ==== - ;===================== - var cap - var limit - var mask - var slots - var sizes - var size - - defn init (c:Int) : - cap = c - limit = c * 3 / 4 - mask = cap - 1 - slots = Array|Array>>(cap, sentinel()) - sizes = IntArray(cap, 0) - size = 0 - - defn clear () : - size = 0 - set-all(slots, 0 to false, sentinel()) - - init(next-pow2(max(8, cap0))) - - ;=================== - ;==== Utilities ==== - ;=================== - defn loc (h:Int) : - h & mask - - ;Matching predicate for TableItem - defn match? (a:TableItem, h:Int, k:K) : - hash(a) == h and - key-equal?(key(a), k) - defn match? (a:TableItem, b:TableItem) : - match?(a, hash(b), key(b)) - - ;Find number of items whose hash is less than h - defn num-before (xs:Array>, n:Int, h:Int) : - bsearch({hash(_) < _}, xs, n, h) - - ;Look for item with given hash and key starting from i - defn* index-of-item (xs:Array>, i:Int, n:Int, h:Int, k:K) : - if i < n : - val x = xs[i] - if hash(x) == h : - if key-equal?(key(x), k) : i - else : index-of-item(xs, i + 1, n, h, k) - - ;Shift items in xs from i to n right by one element - defn* shift-right (xs:Array>, i:Int, n:Int) : - for j in n to i by -1 do : - xs[j] = xs[j - 1] - - ;Shift items in xs from (i + 1) to n left by one element - defn* shift-left (xs:Array>, i:Int, n:Int) : - for j in i to (n - 1) do : - xs[j] = xs[j + 1] - - ;Copy to new array with hole in position i - defn* copy-with-hole (xs:Array>, i:Int, n:Int) : - val xs* = Array>(length(xs) * 2) - xs*[0 to i] = xs[0 to i] - xs*[(i + 1) to (n + 1)] = xs[i to n] - xs* - - ;========================== - ;==== Entry Operations ==== - ;========================== - defn increment-size () : - size = size + 1 - increase-capacity() when size >= limit - - defn decrement-size () : - size = size - 1 - - defn increase-capacity () : - val items = sequence({_}) - init(cap * 2) - do(put, items) - - defn create-bucket (slot:Int, x0:TableItem, x1:TableItem) : - val bucket = Array>(4) - slots[slot] = bucket - sizes[slot] = 2 - ;Populate bucket - if hash(x0) < hash(x1) : - ;Add in front - bucket[0] = x0 - bucket[1] = x1 - else : - ;Add in back - bucket[0] = x1 - bucket[1] = x0 - - defn add-to-bucket (slot:Int, bucket:Array>, i:Int, n:Int, x:TableItem) : - ;Case 1 of 2: Bucket has space. - if n + 1 < length(bucket) : - shift-right(bucket, i, n) - bucket[i] = x - ;Case 2 of 2: Bucket is full. - else : - val bucket* = copy-with-hole(bucket, i, n) - slots[slot] = bucket* - bucket*[i] = x - sizes[slot] = n + 1 - - ;======================= - ;==== Put Operation ==== - ;======================= - defn put (x:TableItem) : - val slot = loc(hash(x)) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - ;New Entry - slots[slot] = x - increment-size() - ;Case 2 of 3: Single item bucket - (s:TableItem) : - ;Case 1 of 2: Item matches - if match?(s,x) : - ;Replace Entry - slots[slot] = x - ;Case 2 of 2: Add Item - else : - create-bucket(slot, s, x) - increment-size() - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, hash(x)) - match(index-of-item(s, i, n, hash(x), key(x))) : - ;Case 1 of 2: Item exists in bucket - (idx:Int) : - s[idx] = x - ;Case 2 of 2: Add new item to bucket - (idx:False) : - add-to-bucket(slot, s, i, n, x) - increment-size() - - ;=========================== - ;==== Lookup? Operation ==== - ;=========================== - defn lookup? (k:K, default:?D) : - val h = key-hash(k) - val slot = loc(h) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - default - ;Case 2 of 3: Single item bucket - (s:TableItem) : - ;Case 1 of 2: Item matches - if match?(s,h,k) : value(s) - else : default - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, h) - match(index-of-item(s, i, n, h, k)) : - (idx:Int) : value(s[idx]) - (idx:False) : default - - ;========================== - ;==== Lookup Operation ==== - ;========================== - defn lookup (k:K) : - val h = key-hash(k) - defn item (v:V) : TableItem(h,k,v) - val slot = loc(h) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - val v = default(k) - if create-on-default : - slots[slot] = item(v) - increment-size() + create-on-default:True|False) -> HashTable : + #HashTable(next-pow2(max(8, cap0)), key-hash, key-equal?, default, create-on-default) + +;=================== +;==== Utilities ==== +;=================== +defn loc (t:HashTable, h:Int) -> Int : + h & mask(t) + +;Matching predicate for TableItem +defn match? (t:HashTable, a:TableItem, h:Int, k:K) : + hash(a) == h and + key-equal?(t, key(a), k) +defn match? (t:HashTable, a:TableItem, b:TableItem) : + match?(t, a, hash(b), key(b)) + +;Find number of items whose hash is less than h +defn num-before (t:HashTable, xs:Array>, n:Int, h:Int) : + bsearch({hash(_) < _}, xs, n, h) + +;Look for item with given hash and key starting from i +defn* index-of-item (t:HashTable, xs:Array>, i:Int, n:Int, h:Int, k:K) : + if i < n : + val x = xs[i] + if hash(x) == h : + if key-equal?(t, key(x), k) : i + else : index-of-item(t, xs, i + 1, n, h, k) + +;Shift items in xs from i to n right by one element +defn* shift-right (xs:Array>, i:Int, n:Int) : + for j in n to i by -1 do : + xs[j] = xs[j - 1] + +;Shift items in xs from (i + 1) to n left by one element +defn* shift-left (xs:Array>, i:Int, n:Int) : + for j in i to (n - 1) do : + xs[j] = xs[j + 1] + +;Copy to new array with hole in position i +defn* copy-with-hole (t:HashTable, xs:Array>, i:Int, n:Int) : + val xs* = Array>(length(xs) * 2) + xs*[0 to i] = xs[0 to i] + xs*[(i + 1) to (n + 1)] = xs[i to n] + xs* + +;========================== +;==== Entry Operations ==== +;========================== +defn increment-size (t:HashTable) : + set-size(t, size(t) + 1) + increase-capacity(t) when size(t) >= limit(t) + +defn decrement-size (t:HashTable) : + set-size(t, size(t) - 1) + +defn increase-capacity (t:HashTable) : + val items = sequence(t, {_}) + init(t, cap(t) * 2) + do(put{t, _}, items) + +defn create-bucket (t:HashTable, slot:Int, x0:TableItem, x1:TableItem) : + val bucket = Array>(4) + slots(t)[slot] = bucket + sizes(t)[slot] = 2 + ;Populate bucket + if hash(x0) < hash(x1) : + ;Add in front + bucket[0] = x0 + bucket[1] = x1 + else : + ;Add in back + bucket[0] = x1 + bucket[1] = x0 + +defn add-to-bucket (t:HashTable, slot:Int, bucket:Array>, i:Int, n:Int, x:TableItem) : + ;Case 1 of 2: Bucket has space. + if n + 1 < length(bucket) : + shift-right(bucket, i, n) + bucket[i] = x + ;Case 2 of 2: Bucket is full. + else : + val bucket* = copy-with-hole(t, bucket, i, n) + slots(t)[slot] = bucket* + bucket*[i] = x + sizes(t)[slot] = n + 1 + +;======================= +;==== Put Operation ==== +;======================= +defmethod set (t:HashTable, k:K, v:V) : + put(t, TableItem(key-hash(t, k), k, v)) + +defn put (t:HashTable, x:TableItem) : + val slot = loc(t, hash(x)) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + ;New Entry + slots(t)[slot] = x + increment-size(t) + ;Case 2 of 3: Single item bucket + (s:TableItem) : + ;Case 1 of 2: Item matches + if match?(t,s,x) : + ;Replace Entry + slots(t)[slot] = x + ;Case 2 of 2: Add Item + else : + create-bucket(t, slot, s, x) + increment-size(t) + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val h = hash(x) + val i = num-before(t, s, n, h) + match(index-of-item(t, s, i, n, h, key(x))) : + ;Case 1 of 2: Item exists in bucket + (idx:Int) : + s[idx] = x + ;Case 2 of 2: Add new item to bucket + (idx:False) : + add-to-bucket(t, slot, s, i, n, x) + increment-size(t) + +;=========================== +;==== Lookup? Operation ==== +;=========================== +defmethod get? (t:HashTable, k:K, default:?D) : + val h = key-hash(t, k) + val slot = loc(t, h) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + default + ;Case 2 of 3: Single item bucket + (s:TableItem) : + ;Case 1 of 2: Item matches + if match?(t,s,h,k) : value(s) + else : default + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(t, s, n, h) + match(index-of-item(t, s, i, n, h, k)) : + (idx:Int) : value(s[idx]) + (idx:False) : default + +;========================== +;==== Lookup Operation ==== +;========================== +defmethod get (t:HashTable, k:K) : + val h = key-hash(t, k) + defn item (v:V) : TableItem(h,k,v) + val slot = loc(t, h) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + val v = default(t)(k) + if create-on-default(t) : + slots(t)[slot] = item(v) + increment-size(t) + v + ;Case 2 of 3: Single item bucket + (s:TableItem) : + ;Case 1 of 2: Item matches + if match?(t, s,h,k) : + value(s) + else : + val v = default(t)(k) + if create-on-default(t) : + create-bucket(t, slot, s, item(v)) + increment-size(t) + v + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(t, s, n, h) + match(index-of-item(t, s, i, n, h, k)) : + (idx:Int) : + value(s[idx]) + (idx:False) : + val v = default(t)(k) + if create-on-default(t) : + add-to-bucket(t,slot, s, i, n, item(v)) + increment-size(t) + v + +;========================== +;==== Update Operation ==== +;========================== +defmethod update (t:HashTable, f:V -> V, k:K) : + val h = key-hash(t,k) + defn item (v:V) : TableItem(h,k,v) + val slot = loc(t,h) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + val v = f(default(t)(k)) + slots(t)[slot] = item(v) + increment-size(t) + v + ;Case 2 of 3: Single item bucket + (s:TableItem) : + ;Case 1 of 2: Item matches + if match?(t,s,h,k) : + val v = f(value(s)) + slots(t)[slot] = item(v) v - ;Case 2 of 3: Single item bucket - (s:TableItem) : - ;Case 1 of 2: Item matches - if match?(s,h,k) : - value(s) - else : - val v = default(k) - if create-on-default : - create-bucket(slot, s, item(v)) - increment-size() - v - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, h) - match(index-of-item(s, i, n, h, k)) : - (idx:Int) : - value(s[idx]) - (idx:False) : - val v = default(k) - if create-on-default : - add-to-bucket(slot, s, i, n, item(v)) - increment-size() - v - - ;========================== - ;==== Update Operation ==== - ;========================== - defn update (f:V -> V, k:K) : - val h = key-hash(k) - defn item (v:V) : TableItem(h,k,v) - val slot = loc(h) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - val v = f(default(k)) - slots[slot] = item(v) - increment-size() + else : + val v = f(default(t)(k)) + create-bucket(t,slot, s, item(v)) + increment-size(t) v - ;Case 2 of 3: Single item bucket - (s:TableItem) : - ;Case 1 of 2: Item matches - if match?(s,h,k) : - val v = f(value(s)) - slots[slot] = item(v) + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(t, s, n, h) + match(index-of-item(t, s, i, n, h, k)) : + (idx:Int) : + val v = f(value(s[idx])) + s[idx] = item(v) v - else : - val v = f(default(k)) - create-bucket(slot, s, item(v)) - increment-size() + (idx:False) : + val v = f(default(t)(k)) + add-to-bucket(t, slot, s, i, n, item(v)) + increment-size(t) v - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, h) - match(index-of-item(s, i, n, h, k)) : - (idx:Int) : - val v = f(value(s[idx])) - s[idx] = item(v) - v - (idx:False) : - val v = f(default(k)) - add-to-bucket(slot, s, i, n, item(v)) - increment-size() - v - - ;======================== - ;==== Key? Operation ==== - ;======================== - defn key? (k:K) : - val h = key-hash(k) - val slot = loc(h) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : false - ;Case 2 of 3: Single item bucket - (s:TableItem) : match?(s,h,k) - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, h) - index-of-item(s, i, n, h, k) is Int - - ;========================== - ;==== Remove Operation ==== - ;========================== - defn remove (k:K) : - val h = key-hash(k) - val slot = loc(h) - match(slots[slot]) : + +;======================== +;==== Key? Operation ==== +;======================== +defmethod key? (t:HashTable, k:K) : + val h = key-hash(t, k) + val slot = loc(t, h) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : false + ;Case 2 of 3: Single item bucket + (s:TableItem) : match?(t,s,h,k) + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(t, s, n, h) + index-of-item(t, s, i, n, h, k) is Int + +;========================== +;==== Remove Operation ==== +;========================== +defmethod remove (t:HashTable, k:K) : + val h = key-hash(t,k) + val slot = loc(t,h) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + false + ;Case 2 of 3: Single item bucket + (s:TableItem) : + if match?(t,s,h,k) : + slots(t)[slot] = sentinel() + decrement-size(t) + true + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(t, s, n, h) + match(index-of-item(t, s, i, n, h, k)) : + (idx:False) : false + (idx:Int) : + shift-left(s, idx, n) + sizes(t)[slot] = n - 1 + decrement-size(t) + true + +;======================== +;==== Map! Operation ==== +;======================== +defn map! (t:HashTable, f:KeyValue -> V) : + for (slot in slots(t), idx in 0 to false) do : + match(slot) : ;Case 1 of 3: Unoccupied bucket (s:Sentinel) : false ;Case 2 of 3: Single item bucket (s:TableItem) : - if match?(s,h,k) : - slots[slot] = sentinel() - decrement-size() - true + val v = f(key(s) => value(s)) + slots(t)[idx] = TableItem(hash(s), key(s), v) ;Case 3 of 3: Multiple item bucket (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, h) - match(index-of-item(s, i, n, h, k)) : - (idx:False) : false - (idx:Int) : - shift-left(s, idx, n) - sizes[slot] = n - 1 - decrement-size() - true - - ;======================== - ;==== Map! Operation ==== - ;======================== - defn map! (f:KeyValue -> V) : - for (slot in slots, idx in 0 to false) do : - match(slot) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - false - ;Case 2 of 3: Single item bucket - (s:TableItem) : - val v = f(key(s) => value(s)) - slots[idx] = TableItem(hash(s), key(s), v) - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[idx] - for i in 0 to n do : - val x = s[i] - val v = f(key(x) => value(x)) - s[i] = TableItem(hash(x), key(x), v) - - ;============================= - ;==== Iteration Operation ==== - ;============================= - defn sequence (f:TableItem -> ?T) : - val sizes = sizes - val slots = slots - generate : - for idx in 0 to length(slots) do : - match(slots[idx]) : - (s:Sentinel) : false - (s:TableItem) : yield(f(s)) - (s:Array>) : for j in 0 to sizes[idx] do : yield(f(s[j])) - - ;====================== - ;==== Table Object ==== - ;====================== - new HashTable : - defmethod set (this, k:K, v:V) : - put(TableItem(key-hash(k), k, v)) - defmethod get? (this, k:K, d:?D) : - lookup?(k, d) - defmethod get (this, k:K) : - lookup(k) - defmethod remove (this, k:K) : - remove(k) - defmethod clear (this) : - clear() - defmethod key? (this, k:K) : - key?(k) - defmethod update (this, f:V -> V, k:K) : - update(f, k) - defmethod map! (f:KeyValue -> V, this) : - map!(f) - defmethod to-seq (this) : - defn make-entry (x:TableItem) : key(x) => value(x) - sequence(make-entry) - defmethod keys (this) : - sequence(key) - defmethod values (this) : - sequence(value) - defmethod length (this) : - size - defmethod default (this, k:K) : - val v = default(k) - if create-on-default : this[k] = v - v + val n = sizes(t)[idx] + for i in 0 to n do : + val x = s[i] + val v = f(key(x) => value(x)) + s[i] = TableItem(hash(x), key(x), v) + +;============================= +;==== Iteration Operation ==== +;============================= +defn sequence (t:HashTable, f:TableItem -> ?T) : + val sizes = sizes(t) + val slots = slots(t) + generate : + for idx in 0 to length(slots) do : + match(slots[idx]) : + (s:Sentinel) : false + (s:TableItem) : yield(f(s)) + (s:Array>) : for j in 0 to sizes[idx] do : yield(f(s[j])) + +defmethod to-seq (t:HashTable) : + defn make-entry (x:TableItem) : key(x) => value(x) + sequence(t, make-entry) +defmethod keys (t:HashTable) : + sequence(t, key) +defmethod values (t:HashTable) : + sequence(t, value) +defmethod length (t:HashTable) : + size(t) +defmethod default (t:HashTable, k:K) : + val v = default(t)(k) + if create-on-default(t) : t[k] = v + v ;================================== ;==== Convenience Constructors ==== @@ -863,360 +855,345 @@ defmethod print (o:OutputStream, t:HashTable) : ;===================== Int Tables =========================== ;============================================================ -public deftype IntTable <: Table +public defstruct IntTable <: Table : + cap : Int with: (setter => set-cap) + limit : Int with: (setter => set-limit, init => cap * 3 / 4) + mask : Int with: (setter => set-mask, init => cap - 1) + slots : Array|Array>> with: (setter => set-slots, init => Array|Array>>(cap, sentinel())) + sizes : IntArray with: (setter => set-sizes, init => IntArray(cap, 0)) + size : Int with: (setter => set-size, init => 0) + default : Int -> V + create-on-default: True|False +with: + constructor => #IntTable + +defn init (t:IntTable, c:Int) : + set-cap(t, c) + set-limit(t, c * 3 / 4) + set-mask(t, c - 1) + set-slots(t, Array|Array>>(c, sentinel())) + set-sizes(t, IntArray(c, 0)) + set-size(t, 0) -public defn IntTable (cap0:Int +defn clear (t:IntTable) : + set-size(t, 0) + set-all(slots(t), 0 to false, sentinel()) + +public defn IntTable (cap0:Int, default: Int -> V, - create-on-default:True|False) : - ;===================== - ;==== Table State ==== - ;===================== - var cap - var limit - var mask - var slots - var sizes - var size - - defn init (c:Int) : - cap = c - limit = c * 3 / 4 - mask = cap - 1 - slots = Array|Array>>(cap, sentinel()) - sizes = IntArray(cap, 0) - size = 0 - - defn clear () : - size = 0 - set-all(slots, 0 to false, sentinel()) - - init(next-pow2(max(8, cap0))) - - ;=================== - ;==== Utilities ==== - ;=================== - defn loc (h:Int) : - h & mask - - ;Matching predicate for IntItem - defn match? (a:IntItem, k:Int) : - key(a) == k - defn match? (a:IntItem, b:IntItem) : - match?(a, key(b)) - - ;Find number of items whose hash is less than h - defn num-before (xs:Array>, n:Int, k:Int) : - bsearch({key(_) < _}, xs, n, k) - - ;Look for item with given hash and key starting from i - defn* index-of-item (xs:Array>, i:Int, n:Int, k:Int) : - if i < n : - val x = xs[i] - if key(x) == k : i - - ;Shift items in xs from i to n right by one element - defn* shift-right (xs:Array>, i:Int, n:Int) : - for j in n to i by -1 do : - xs[j] = xs[j - 1] - - ;Shift items in xs from (i + 1) to n left by one element - defn* shift-left (xs:Array>, i:Int, n:Int) : - for j in i to (n - 1) do : - xs[j] = xs[j + 1] - - ;Copy to new array with hole in position i - defn* copy-with-hole (xs:Array>, i:Int, n:Int) : - val xs* = Array>(length(xs) * 2) - xs*[0 to i] = xs[0 to i] - xs*[(i + 1) to (n + 1)] = xs[i to n] - xs* - - ;========================== - ;==== Entry Operations ==== - ;========================== - defn increment-size () : - size = size + 1 - increase-capacity() when size >= limit - - defn decrement-size () : - size = size - 1 - - defn increase-capacity () : - val items = sequence({_}) - init(cap * 2) - do(put, items) - - defn create-bucket (slot:Int, x0:IntItem, x1:IntItem) : - val bucket = Array>(4) - slots[slot] = bucket - sizes[slot] = 2 - ;Populate bucket - if key(x0) < key(x1) : - ;Add in front - bucket[0] = x0 - bucket[1] = x1 - else : - ;Add in back - bucket[0] = x1 - bucket[1] = x0 - - defn add-to-bucket (slot:Int, bucket:Array>, i:Int, n:Int, x:IntItem) : - ;Case 1 of 2: Bucket has space. - if n + 1 < length(bucket) : - shift-right(bucket, i, n) - bucket[i] = x - ;Case 2 of 2: Bucket is full. - else : - val bucket* = copy-with-hole(bucket, i, n) - slots[slot] = bucket* - bucket*[i] = x - sizes[slot] = n + 1 - - ;======================= - ;==== Put Operation ==== - ;======================= - defn put (x:IntItem) : - val slot = loc(key(x)) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - ;New Entry - slots[slot] = x - increment-size() - ;Case 2 of 3: Single item bucket - (s:IntItem) : - ;Case 1 of 2: Item matches - if match?(s,x) : - ;Replace Entry - slots[slot] = x - ;Case 2 of 2: Add Item - else : - create-bucket(slot, s, x) - increment-size() - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, key(x)) - match(index-of-item(s, i, n, key(x))) : - ;Case 1 of 2: Item exists in bucket - (idx:Int) : - s[idx] = x - ;Case 2 of 2: Add new item to bucket - (idx:False) : - add-to-bucket(slot, s, i, n, x) - increment-size() - - ;=========================== - ;==== Lookup? Operation ==== - ;=========================== - defn lookup? (k:Int, default:?D) : - val slot = loc(k) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - default - ;Case 2 of 3: Single item bucket - (s:IntItem) : - ;Case 1 of 2: Item matches - if match?(s,k) : value(s) - else : default - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, k) - match(index-of-item(s, i, n, k)) : - (idx:Int) : value(s[idx]) - (idx:False) : default - - ;========================== - ;==== Lookup Operation ==== - ;========================== - defn lookup (k:Int) : - defn item (v:V) : IntItem(k,v) - val slot = loc(k) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - val v = default(k) - if create-on-default : - slots[slot] = item(v) - increment-size() + create-on-default:True|False) -> IntTable : + #IntTable(next-pow2(max(8, cap0)), default, create-on-default) + +defmethod length (t:IntTable) : + size(t) + +defmethod default (t:IntTable, k:Int) : + val v = default(t)(k) + if create-on-default(t) : t[k] = v + v + +;=================== +;==== Utilities ==== +;=================== +defn loc (t:IntTable, h:Int) : + h & mask(t) + +;Matching predicate for IntItem +defn match? (a:IntItem, k:Int) : + key(a) == k +defn match? (a:IntItem, b:IntItem) : + match?(a, key(b)) + +;Find number of items whose hash is less than h +defn num-before (xs:Array>, n:Int, k:Int) : + bsearch({key(_) < _}, xs, n, k) + +;Look for item with given hash and key starting from i +defn* index-of-item (xs:Array>, i:Int, n:Int, k:Int) : + if i < n : + val x = xs[i] + if key(x) == k : i + +;Shift items in xs from i to n right by one element +defn* shift-right (xs:Array>, i:Int, n:Int) : + for j in n to i by -1 do : + xs[j] = xs[j - 1] + +;Shift items in xs from (i + 1) to n left by one element +defn* shift-left (xs:Array>, i:Int, n:Int) : + for j in i to (n - 1) do : + xs[j] = xs[j + 1] + +;Copy to new array with hole in position i +defn* copy-with-hole (xs:Array>, i:Int, n:Int) : + val xs* = Array>(length(xs) * 2) + xs*[0 to i] = xs[0 to i] + xs*[(i + 1) to (n + 1)] = xs[i to n] + xs* + +;========================== +;==== Entry Operations ==== +;========================== +defn increment-size (t:IntTable) : + set-size(t, size(t) + 1) + increase-capacity(t) when size(t) >= limit(t) + +defn decrement-size (t:IntTable) : + set-size(t, size(t) - 1) + +defn increase-capacity (t:IntTable) : + val items = sequence(t, {_}) + init(t, cap(t) * 2) + do(put{t, _}, items) + +defn create-bucket (t:IntTable, slot:Int, x0:IntItem, x1:IntItem) : + val bucket = Array>(4) + slots(t)[slot] = bucket + sizes(t)[slot] = 2 + ;Populate bucket + if key(x0) < key(x1) : + ;Add in front + bucket[0] = x0 + bucket[1] = x1 + else : + ;Add in back + bucket[0] = x1 + bucket[1] = x0 + +defn add-to-bucket (t:IntTable, slot:Int, bucket:Array>, i:Int, n:Int, x:IntItem) : + ;Case 1 of 2: Bucket has space. + if n + 1 < length(bucket) : + shift-right(bucket, i, n) + bucket[i] = x + ;Case 2 of 2: Bucket is full. + else : + val bucket* = copy-with-hole(bucket, i, n) + slots(t)[slot] = bucket* + bucket*[i] = x + sizes(t)[slot] = n + 1 + +;======================= +;==== Put Operation ==== +;======================= +defmethod set (t:IntTable, k:Int, v:V) : + put(t, IntItem(k, v)) + +defn put (t:IntTable, x:IntItem) : + val slot = loc(t, key(x)) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + ;New Entry + slots(t)[slot] = x + increment-size(t) + ;Case 2 of 3: Single item bucket + (s:IntItem) : + ;Case 1 of 2: Item matches + if match?(s,x) : + ;Replace Entry + slots(t)[slot] = x + ;Case 2 of 2: Add Item + else : + create-bucket(t, slot, s, x) + increment-size(t) + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(s, n, key(x)) + match(index-of-item(s, i, n, key(x))) : + ;Case 1 of 2: Item exists in bucket + (idx:Int) : + s[idx] = x + ;Case 2 of 2: Add new item to bucket + (idx:False) : + add-to-bucket(t, slot, s, i, n, x) + increment-size(t) + +;=========================== +;==== Lookup? Operation ==== +;=========================== +defmethod get? (t:IntTable, k:Int, default:?D) : + val slot = loc(t, k) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + default + ;Case 2 of 3: Single item bucket + (s:IntItem) : + ;Case 1 of 2: Item matches + if match?(s,k) : value(s) + else : default + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(s, n, k) + match(index-of-item(s, i, n, k)) : + (idx:Int) : value(s[idx]) + (idx:False) : default + +;========================== +;==== Lookup Operation ==== +;========================== +defmethod get (t:IntTable, k:Int) : + defn item (v:V) : IntItem(k,v) + val slot = loc(t, k) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + val v = default(t)(k) + if create-on-default(t) : + slots(t)[slot] = item(v) + increment-size(t) + v + ;Case 2 of 3: Single item bucket + (s:IntItem) : + ;Case 1 of 2: Item matches + if match?(s,k) : + value(s) + else : + val v = default(t)(k) + if create-on-default(t) : + create-bucket(t, slot, s, item(v)) + increment-size(t) + v + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(s, n, k) + match(index-of-item(s, i, n, k)) : + (idx:Int) : + value(s[idx]) + (idx:False) : + val v = default(t)(k) + if create-on-default(t) : + add-to-bucket(t, slot, s, i, n, item(v)) + increment-size(t) + v + +;========================== +;==== Update Operation ==== +;========================== +defn update (t:IntTable, f:V -> V, k:Int) : + defn item (v:V) : IntItem(k,v) + val slot = loc(t, k) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + val v = f(default(t)(k)) + slots(t)[slot] = item(v) + increment-size(t) + v + ;Case 2 of 3: Single item bucket + (s:IntItem) : + ;Case 1 of 2: Item matches + if match?(s,k) : + val v = f(value(s)) + slots(t)[slot] = item(v) v - ;Case 2 of 3: Single item bucket - (s:IntItem) : - ;Case 1 of 2: Item matches - if match?(s,k) : - value(s) - else : - val v = default(k) - if create-on-default : - create-bucket(slot, s, item(v)) - increment-size() - v - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, k) - match(index-of-item(s, i, n, k)) : - (idx:Int) : - value(s[idx]) - (idx:False) : - val v = default(k) - if create-on-default : - add-to-bucket(slot, s, i, n, item(v)) - increment-size() - v - - ;========================== - ;==== Update Operation ==== - ;========================== - defn update (f:V -> V, k:Int) : - defn item (v:V) : IntItem(k,v) - val slot = loc(k) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - val v = f(default(k)) - slots[slot] = item(v) - increment-size() + else : + val v = f(default(t)(k)) + create-bucket(t, slot, s, item(v)) + increment-size(t) v - ;Case 2 of 3: Single item bucket - (s:IntItem) : - ;Case 1 of 2: Item matches - if match?(s,k) : - val v = f(value(s)) - slots[slot] = item(v) + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(s, n, k) + match(index-of-item(s, i, n, k)) : + (idx:Int) : + val v = f(value(s[idx])) + s[idx] = item(v) v - else : - val v = f(default(k)) - create-bucket(slot, s, item(v)) - increment-size() + (idx:False) : + val v = f(default(t)(k)) + add-to-bucket(t, slot, s, i, n, item(v)) + increment-size(t) v - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, k) - match(index-of-item(s, i, n, k)) : - (idx:Int) : - val v = f(value(s[idx])) - s[idx] = item(v) - v - (idx:False) : - val v = f(default(k)) - add-to-bucket(slot, s, i, n, item(v)) - increment-size() - v - - ;======================== - ;==== Key? Operation ==== - ;======================== - defn key? (k:Int) : - val slot = loc(k) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : false - ;Case 2 of 3: Single item bucket - (s:IntItem) : match?(s,k) - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, k) - index-of-item(s, i, n, k) is Int - - ;========================== - ;==== Remove Operation ==== - ;========================== - defn remove (k:Int) : - val slot = loc(k) - match(slots[slot]) : + +;======================== +;==== Key? Operation ==== +;======================== +defn key? (t:IntTable, k:Int) : + val slot = loc(t, k) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : false + ;Case 2 of 3: Single item bucket + (s:IntItem) : match?(s,k) + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(s, n, k) + index-of-item(s, i, n, k) is Int + +;========================== +;==== Remove Operation ==== +;========================== +defn remove (t:IntTable, k:Int) : + val slot = loc(t, k) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + false + ;Case 2 of 3: Single item bucket + (s:IntItem) : + if match?(s,k) : + slots(t)[slot] = sentinel() + decrement-size(t) + true + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(s, n, k) + match(index-of-item(s, i, n, k)) : + (idx:False) : false + (idx:Int) : + shift-left(s, idx, n) + sizes(t)[slot] = n - 1 + decrement-size(t) + true + +;======================== +;==== Map! Operation ==== +;======================== +defmethod map! (f:KeyValue -> V, t:IntTable) : + for (slot in slots(t), idx in 0 to false) do : + match(slot) : ;Case 1 of 3: Unoccupied bucket (s:Sentinel) : false ;Case 2 of 3: Single item bucket (s:IntItem) : - if match?(s,k) : - slots[slot] = sentinel() - decrement-size() - true + val v = f(key(s) => value(s)) + slots(t)[idx] = IntItem(key(s), v) ;Case 3 of 3: Multiple item bucket (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, k) - match(index-of-item(s, i, n, k)) : - (idx:False) : false - (idx:Int) : - shift-left(s, idx, n) - sizes[slot] = n - 1 - decrement-size() - true - - ;======================== - ;==== Map! Operation ==== - ;======================== - defn map! (f:KeyValue -> V) : - for (slot in slots, idx in 0 to false) do : - match(slot) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - false - ;Case 2 of 3: Single item bucket - (s:IntItem) : - val v = f(key(s) => value(s)) - slots[idx] = IntItem(key(s), v) - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[idx] - for i in 0 to n do : - val x = s[i] - val v = f(key(x) => value(x)) - s[i] = IntItem(key(x), v) - - ;============================= - ;==== Iteration Operation ==== - ;============================= - defn sequence (f:IntItem -> ?T) : - val sizes = sizes - val slots = slots - generate : - for idx in 0 to length(slots) do : - match(slots[idx]) : - (s:Sentinel) : false - (s:IntItem) : yield(f(s)) - (s:Array>) : for j in 0 to sizes[idx] do : yield(f(s[j])) - - ;====================== - ;==== Table Object ==== - ;====================== - new IntTable : - defmethod set (this, k:Int, v:V) : - put(IntItem(k, v)) - defmethod get? (this, k:Int, d:?D) : - lookup?(k, d) - defmethod get (this, k:Int) : - lookup(k) - defmethod remove (this, k:Int) : - remove(k) - defmethod clear (this) : - clear() - defmethod key? (this, k:Int) : - key?(k) - defmethod update (this, f:V -> V, k:Int) : - update(f, k) - defmethod map! (f:KeyValue -> V, this) : - map!(f) - defmethod to-seq (this) : - defn make-entry (x:IntItem) : key(x) => value(x) - sequence(make-entry) - defmethod keys (this) : - sequence(key) - defmethod values (this) : - sequence(value) - defmethod length (this) : - size - defmethod default (this, k:Int) : - val v = default(k) - if create-on-default : this[k] = v - v + val n = sizes(t)[idx] + for i in 0 to n do : + val x = s[i] + val v = f(key(x) => value(x)) + s[i] = IntItem(key(x), v) + +;============================= +;==== Iteration Operation ==== +;============================= +defn sequence (t:IntTable, f:IntItem -> ?T) : + val sizes = sizes(t) + val slots = slots(t) + generate : + for idx in 0 to length(slots) do : + match(slots[idx]) : + (s:Sentinel) : false + (s:IntItem) : yield(f(s)) + (s:Array>) : for j in 0 to sizes[idx] do : yield(f(s[j])) + +defmethod to-seq (t:IntTable) : + defn make-entry (x:IntItem) : key(x) => value(x) + sequence(t, make-entry) +defmethod keys (t:IntTable) : + sequence(t, key) +defmethod values (t:IntTable) : + sequence(t, value) ;================================== ;==== Convenience Constructors ==== @@ -1282,229 +1259,230 @@ defmethod same-contents? (a:Set, b:Set) : ;====================== HashSets ============================ ;============================================================ -public deftype HashSet <: Set - -public defn HashSet (cap0:Int - key-hash: K -> Int - key-equal?: (K,K) -> True|False) : - ;===================== - ;==== Table State ==== - ;===================== - var cap - var limit - var mask - var slots - var sizes - var size - - defn init (c:Int) : - cap = c - limit = c * 3 / 4 - mask = cap - 1 - slots = Array|Array>>(cap, sentinel()) - sizes = IntArray(cap, 0) - size = 0 - - defn clear () : - size = 0 - set-all(slots, 0 to false, sentinel()) - - init(next-pow2(max(8, cap0))) - - ;=================== - ;==== Utilities ==== - ;=================== - defn set-item (k:K) : - SetItem(key-hash(k), k) - - defn loc (h:Int) : - h & mask - - ;Matching predicate for TableItem - defn match? (a:SetItem, b:SetItem) : - hash(a) == hash(b) and - key-equal?(key(a), key(b)) - - ;Find number of items whose hash is less than h - defn num-before (xs:Array>, n:Int, x:SetItem) : - bsearch({hash(_) < hash(_)}, xs, n, x) - - ;Look for item with given hash and key starting from i - defn* index-of-item (xs:Array>, i:Int, n:Int, y:SetItem) : - if i < n : - val x = xs[i] - if hash(x) == hash(y) : - if key-equal?(key(x), key(y)) : i - else : index-of-item(xs, i + 1, n, y) - - ;Shift items in xs from i to n right by one element - defn* shift-right (xs:Array>, i:Int, n:Int) : - for j in n to i by -1 do : - xs[j] = xs[j - 1] - - ;Shift items in xs from (i + 1) to n left by one element - defn* shift-left (xs:Array>, i:Int, n:Int) : - for j in i to (n - 1) do : - xs[j] = xs[j + 1] - - ;Copy to new array with hole in position i - defn* copy-with-hole (xs:Array>, i:Int, n:Int) : - val xs* = Array>(length(xs) * 2) - xs*[0 to i] = xs[0 to i] - xs*[(i + 1) to (n + 1)] = xs[i to n] - xs* - - ;========================== - ;==== Entry Operations ==== - ;========================== - defn increment-size () : - size = size + 1 - increase-capacity() when size >= limit - - defn decrement-size () : - size = size - 1 - - defn increase-capacity () : - val items = sequence({_}) - init(cap * 2) - do(put, items) - - defn create-bucket (slot:Int, x0:SetItem, x1:SetItem) : - val bucket = Array>(4) - slots[slot] = bucket - sizes[slot] = 2 - ;Populate bucket - if hash(x0) < hash(x1) : - ;Add in front - bucket[0] = x0 - bucket[1] = x1 - else : - ;Add in back - bucket[0] = x1 - bucket[1] = x0 - - defn add-to-bucket (slot:Int, bucket:Array>, i:Int, n:Int, x:SetItem) : - ;Case 1 of 2: Bucket has space. - if n + 1 < length(bucket) : - shift-right(bucket, i, n) - bucket[i] = x - ;Case 2 of 2: Bucket is full. - else : - val bucket* = copy-with-hole(bucket, i, n) - slots[slot] = bucket* - bucket*[i] = x - sizes[slot] = n + 1 - - ;======================= - ;==== Put Operation ==== - ;======================= - ;Returns true if new item is added - defn put (x:SetItem) : - val slot = loc(hash(x)) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - ;New Entry - slots[slot] = x - increment-size() +public defstruct HashSet <: Set : + cap : Int with: (setter => set-cap) + limit : Int with: (setter => set-limit, init => cap * 3 / 4) + mask : Int with: (setter => set-mask, init => cap - 1) + slots : Array|Array>> with: (setter => set-slots, init => Array|Array>>(cap, sentinel())) + sizes : IntArray with: (setter => set-sizes, init => IntArray(cap, 0)) + size : Int with: (setter => set-size, init => 0) + key-hash : K -> Int + key-equal? : (K,K) -> True | False +with: + constructor => #HashSet + +defn init (t:HashSet, c:Int) : + set-cap(t, c) + set-limit(t, c * 3 / 4) + set-mask(t, c - 1) + set-slots(t, Array|Array>>(c, sentinel())) + set-sizes(t, IntArray(c, 0)) + set-size(t, 0) + +defn clear (t:HashSet) : + set-size(t, 0) + set-all(slots(t), 0 to false, sentinel()) + +public defn HashSet (cap0:Int, + key-hash: K -> Int, + key-equal?: (K,K) -> True|False) -> HashSet : + #HashSet(next-pow2(max(8, cap0)), key-hash, key-equal?) + + +;=================== +;==== Utilities ==== +;=================== +defn set-item (s:HashSet, k:K) : + SetItem(key-hash(s, k), k) + +defn loc (s:HashSet, h:Int) : + h & mask(s) + +defn key-hash (t:HashSet, k:K) -> Int : + key-hash(t)(k) + +defn key-equal? (t:HashSet, x:K, y:K) -> True|False : + key-equal?(t)(x, y) + +;Matching predicate for TableItem +defn match? (s:HashSet, a:SetItem, b:SetItem) : + hash(a) == hash(b) and + key-equal?(s, key(a), key(b)) + +;Find number of items whose hash is less than h +defn num-before (s:HashSet, xs:Array>, n:Int, x:SetItem) : + bsearch({hash(_) < hash(_)}, xs, n, x) + +;Look for item with given hash and key starting from i +defn* index-of-item (s:HashSet, xs:Array>, i:Int, n:Int, y:SetItem) : + if i < n : + val x = xs[i] + if hash(x) == hash(y) : + if key-equal?(s, key(x), key(y)) : i + else : index-of-item(s, xs, i + 1, n, y) + +;Shift items in xs from i to n right by one element +defn* shift-right (xs:Array>, i:Int, n:Int) : + for j in n to i by -1 do : + xs[j] = xs[j - 1] + +;Shift items in xs from (i + 1) to n left by one element +defn* shift-left (xs:Array>, i:Int, n:Int) : + for j in i to (n - 1) do : + xs[j] = xs[j + 1] + +;Copy to new array with hole in position i +defn* copy-with-hole (xs:Array>, i:Int, n:Int) : + val xs* = Array>(length(xs) * 2) + xs*[0 to i] = xs[0 to i] + xs*[(i + 1) to (n + 1)] = xs[i to n] + xs* + +;========================== +;==== Entry Operations ==== +;========================== +defn increment-size (s:HashSet) : + set-size(s, size(s) + 1) + increase-capacity(s) when size(s) >= limit(s) + +defn decrement-size (s:HashSet) : + set-size(s, size(s) - 1) + +defn increase-capacity (s:HashSet) : + val items = sequence(s, {_}) + init(s, cap(s) * 2) + do(put{s, _}, items) + +defn create-bucket (t:HashSet, slot:Int, x0:SetItem, x1:SetItem) : + val bucket = Array>(4) + slots(t)[slot] = bucket + sizes(t)[slot] = 2 + ;Populate bucket + if hash(x0) < hash(x1) : + ;Add in front + bucket[0] = x0 + bucket[1] = x1 + else : + ;Add in back + bucket[0] = x1 + bucket[1] = x0 + +defn add-to-bucket (t:HashSet, slot:Int, bucket:Array>, i:Int, n:Int, x:SetItem) : + ;Case 1 of 2: Bucket has space. + if n + 1 < length(bucket) : + shift-right(bucket, i, n) + bucket[i] = x + ;Case 2 of 2: Bucket is full. + else : + val bucket* = copy-with-hole(bucket, i, n) + slots(t)[slot] = bucket* + bucket*[i] = x + sizes(t)[slot] = n + 1 + +;======================= +;==== Put Operation ==== +;======================= +;Returns true if new item is added +defn put (t:HashSet, x:SetItem) : + val slot = loc(t, hash(x)) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + ;New Entry + slots(t)[slot] = x + increment-size(t) + true + ;Case 2 of 3: Single item bucket + (s:SetItem) : + ;Case 1 of 2: Item matches + if match?(t,s,x) : + false + ;Case 2 of 2: Add Item + else : + create-bucket(t, slot, s, x) + increment-size(t) true - ;Case 2 of 3: Single item bucket - (s:SetItem) : - ;Case 1 of 2: Item matches - if match?(s,x) : + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(t, s, n, x) + match(index-of-item(t, s, i, n, x)) : + ;Case 1 of 2: Item exists in bucket + (idx:Int) : false - ;Case 2 of 2: Add Item - else : - create-bucket(slot, s, x) - increment-size() + ;Case 2 of 2: Add new item to bucket + (idx:False) : + add-to-bucket(t, slot, s, i, n, x) + increment-size(t) true - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, x) - match(index-of-item(s, i, n, x)) : - ;Case 1 of 2: Item exists in bucket - (idx:Int) : - false - ;Case 2 of 2: Add new item to bucket - (idx:False) : - add-to-bucket(slot, s, i, n, x) - increment-size() - true - - ;======================== - ;==== Key? Operation ==== - ;======================== - defn exists? (x:SetItem) : - val slot = loc(hash(x)) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : false - ;Case 2 of 3: Single item bucket - (s:SetItem) : match?(s,x) - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, x) - index-of-item(s, i, n, x) is Int - - ;========================== - ;==== Remove Operation ==== - ;========================== - ;Returns true if item was removed - defn remove (x:SetItem) : - val slot = loc(hash(x)) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - false - ;Case 2 of 3: Single item bucket - (s:SetItem) : - if match?(s,x) : - slots[slot] = sentinel() - decrement-size() + +;======================== +;==== Key? Operation ==== +;======================== +defn exists? (t:HashSet, x:SetItem) : + val slot = loc(t, hash(x)) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : false + ;Case 2 of 3: Single item bucket + (s:SetItem) : match?(t,s,x) + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(t, s, n, x) + index-of-item(t, s, i, n, x) is Int + +;========================== +;==== Remove Operation ==== +;========================== +;Returns true if item was removed +defn remove (t:HashSet,x:SetItem) : + val slot = loc(t, hash(x)) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + false + ;Case 2 of 3: Single item bucket + (s:SetItem) : + if match?(t,s,x) : + slots(t)[slot] = sentinel() + decrement-size(t) + true + ;Case 3 of 3: Multiple item bucket + (s:Array>) : + val n = sizes(t)[slot] + val i = num-before(t, s, n, x) + match(index-of-item(t, s, i, n, x)) : + (idx:False) : false + (idx:Int) : + shift-left(s, idx, n) + sizes(t)[slot] = n - 1 + decrement-size(t) true - ;Case 3 of 3: Multiple item bucket - (s:Array>) : - val n = sizes[slot] - val i = num-before(s, n, x) - match(index-of-item(s, i, n, x)) : - (idx:False) : false - (idx:Int) : - shift-left(s, idx, n) - sizes[slot] = n - 1 - decrement-size() - true - - ;============================= - ;==== Iteration Operation ==== - ;============================= - defn sequence (f:SetItem -> ?T) : - val sizes = sizes - val slots = slots - generate : - for idx in 0 to length(slots) do : - match(slots[idx]) : - (s:Sentinel) : false - (s:SetItem) : yield(f(s)) - (s:Array>) : for j in 0 to sizes[idx] do : yield(f(s[j])) - - ;====================== - ;==== Table Object ==== - ;====================== - new HashSet : - defmethod add (this, k:K) : - put(set-item(k)) - defmethod get (this, k:K) : - exists?(set-item(k)) - defmethod remove (this, k:K) : - remove(set-item(k)) - defmethod clear (this) : - clear() - defmethod to-seq (this) : - sequence(key) - defmethod length (this) : - size + +;============================= +;==== Iteration Operation ==== +;============================= +defn sequence (s:HashSet, f:SetItem -> ?T) : + val sizes = sizes(s) + val slots = slots(s) + generate : + for idx in 0 to length(slots) do : + match(slots[idx]) : + (s:Sentinel) : false + (s:SetItem) : yield(f(s)) + (s:Array>) : for j in 0 to sizes[idx] do : yield(f(s[j])) + +defmethod add (s:HashSet, k:K) : + put(s, set-item(s, k)) +defmethod get (s:HashSet, k:K) : + exists?(s, set-item(s, k)) +defmethod remove (s:HashSet, k:K) : + remove(s, set-item(s, k)) +defmethod to-seq (s:HashSet) : + sequence(s, key) +defmethod length (s:HashSet) : + size(s) ;================================== ;==== Convenience Constructors ==== @@ -1538,217 +1516,200 @@ defmethod print (o:OutputStream, s:HashSet) : ;====================== IntSets ============================= ;============================================================ -public deftype IntSet <: Set - -public defn IntSet (cap0:Int) : - ;===================== - ;==== Table State ==== - ;===================== - var cap - var limit - var mask - var slots - var sizes - var size - - defn init (c:Int) : - cap = c - limit = c * 3 / 4 - mask = cap - 1 - slots = Array(cap, sentinel()) - sizes = IntArray(cap, 0) - size = 0 - - defn clear () : - size = 0 - set-all(slots, 0 to false, sentinel()) - - init(next-pow2(max(8, cap0))) - - ;=================== - ;==== Utilities ==== - ;=================== - defn loc (h:Int) : - h & mask - - ;Find number of items whose hash is less than h - defn num-before (xs:IntArray, n:Int, x:Int) : - bsearch(less?, xs, n, x) - - ;Look for item with given hash and key starting from i - defn* index-of-item (xs:IntArray, i:Int, n:Int, y:Int) : - if i < n : - val x = xs[i] - if x == y : i - - ;Shift items in xs from i to n right by one element - defn* shift-right (xs:IntArray, i:Int, n:Int) : - for j in n to i by -1 do : - xs[j] = xs[j - 1] - - ;Shift items in xs from (i + 1) to n left by one element - defn* shift-left (xs:IntArray, i:Int, n:Int) : - for j in i to (n - 1) do : - xs[j] = xs[j + 1] - - ;Copy to new array with hole in position i - defn* copy-with-hole (xs:IntArray, i:Int, n:Int) : - val xs* = IntArray(length(xs) * 2) - xs*[0 to i] = xs[0 to i] - xs*[(i + 1) to (n + 1)] = xs[i to n] - xs* - - ;========================== - ;==== Entry Operations ==== - ;========================== - defn increment-size () : - size = size + 1 - increase-capacity() when size >= limit - - defn decrement-size () : - size = size - 1 - - defn increase-capacity () : - val items = sequence() - init(cap * 2) - do(put, items) - - defn create-bucket (slot:Int, x0:Int, x1:Int) : - val bucket = IntArray(4) - slots[slot] = bucket - sizes[slot] = 2 - ;Populate bucket - if x0 < x1 : - ;Add in front - bucket[0] = x0 - bucket[1] = x1 - else : - ;Add in back - bucket[0] = x1 - bucket[1] = x0 - - defn add-to-bucket (slot:Int, bucket:IntArray, i:Int, n:Int, x:Int) : - ;Case 1 of 2: Bucket has space. - if n + 1 < length(bucket) : - shift-right(bucket, i, n) - bucket[i] = x - ;Case 2 of 2: Bucket is full. - else : - val bucket* = copy-with-hole(bucket, i, n) - slots[slot] = bucket* - bucket*[i] = x - sizes[slot] = n + 1 - - ;======================= - ;==== Put Operation ==== - ;======================= - ;Returns true if new item is added - defn put (x:Int) : - val slot = loc(x) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - ;New Entry - slots[slot] = x - increment-size() +public defstruct IntSet <: Set : + cap : Int with: (setter => set-cap) + limit : Int with: (setter => set-limit, init => cap * 3 / 4) + mask : Int with: (setter => set-mask, init => cap - 1) + slots : Array with: (setter => set-slots, init => Array(cap, sentinel())) + sizes : IntArray with: (setter => set-sizes, init => IntArray(cap, 0)) + size : Int with: (setter => set-size, init => 0) +with: + constructor => #IntSet + +defn init (t:IntSet, c:Int) : + set-cap(t, c) + set-limit(t, c * 3 / 4) + set-mask(t, c - 1) + set-slots(t, Array(c, sentinel())) + set-sizes(t, IntArray(c, 0)) + set-size(t, 0) + +defmethod clear (t:IntSet) : + set-size(t, 0) + set-all(slots(t), 0 to false, sentinel()) + +public defn IntSet (cap0:Int) -> IntSet : + #IntSet(next-pow2(max(8, cap0))) + +;=================== +;==== Utilities ==== +;=================== +defn loc (t:IntSet, h:Int) : + h & mask(t) + +;Find number of items whose hash is less than h +defn num-before (xs:IntArray, n:Int, x:Int) : + bsearch(less?, xs, n, x) + +;Look for item with given hash and key starting from i +defn* index-of-item (xs:IntArray, i:Int, n:Int, y:Int) : + if i < n : + val x = xs[i] + if x == y : i + +;Shift items in xs from i to n right by one element +defn* shift-right (xs:IntArray, i:Int, n:Int) : + for j in n to i by -1 do : + xs[j] = xs[j - 1] + +;Shift items in xs from (i + 1) to n left by one element +defn* shift-left (xs:IntArray, i:Int, n:Int) : + for j in i to (n - 1) do : + xs[j] = xs[j + 1] + +;Copy to new array with hole in position i +defn* copy-with-hole (xs:IntArray, i:Int, n:Int) : + val xs* = IntArray(length(xs) * 2) + xs*[0 to i] = xs[0 to i] + xs*[(i + 1) to (n + 1)] = xs[i to n] + xs* + +;========================== +;==== Entry Operations ==== +;========================== +defn increment-size (t:IntSet) : + set-size(t, length(t) + 1) + increase-capacity(t) when length(t) >= limit(t) + +defn decrement-size (t:IntSet) : + set-size(t, length(t) - 1) + +defn increase-capacity (t:IntSet) : + init(t, cap(t) * 2) + do(add{t, _}, to-seq(t)) + +defn create-bucket (t:IntSet, slot:Int, x0:Int, x1:Int) : + val bucket = IntArray(4) + slots(t)[slot] = bucket + sizes(t)[slot] = 2 + ;Populate bucket + if x0 < x1 : + ;Add in front + bucket[0] = x0 + bucket[1] = x1 + else : + ;Add in back + bucket[0] = x1 + bucket[1] = x0 + +defn add-to-bucket (t:IntSet, slot:Int, bucket:IntArray, i:Int, n:Int, x:Int) : + ;Case 1 of 2: Bucket has space. + if n + 1 < length(bucket) : + shift-right(bucket, i, n) + bucket[i] = x + ;Case 2 of 2: Bucket is full. + else : + val bucket* = copy-with-hole(bucket, i, n) + slots(t)[slot] = bucket* + bucket*[i] = x + sizes(t)[slot] = n + 1 + +;======================= +;==== Put Operation ==== +;======================= +;Returns true if new item is added +defmethod add (t:IntSet, x:Int) : + val slot = loc(t, x) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + ;New Entry + slots(t)[slot] = x + increment-size(t) + true + ;Case 2 of 3: Single item bucket + (s:Int) : + ;Case 1 of 2: Item matches + if s == x : + false + ;Case 2 of 2: Add Item + else : + create-bucket(t, slot, s, x) + increment-size(t) true - ;Case 2 of 3: Single item bucket - (s:Int) : - ;Case 1 of 2: Item matches - if s == x : + ;Case 3 of 3: Multiple item bucket + (s:IntArray) : + val n = sizes(t)[slot] + val i = num-before(s, n, x) + match(index-of-item(s, i, n, x)) : + ;Case 1 of 2: Item exists in bucket + (idx:Int) : false - ;Case 2 of 2: Add Item - else : - create-bucket(slot, s, x) - increment-size() + ;Case 2 of 2: Add new item to bucket + (idx:False) : + add-to-bucket(t, slot, s, i, n, x) + increment-size(t) true - ;Case 3 of 3: Multiple item bucket - (s:IntArray) : - val n = sizes[slot] - val i = num-before(s, n, x) - match(index-of-item(s, i, n, x)) : - ;Case 1 of 2: Item exists in bucket - (idx:Int) : - false - ;Case 2 of 2: Add new item to bucket - (idx:False) : - add-to-bucket(slot, s, i, n, x) - increment-size() - true - - ;======================== - ;==== Key? Operation ==== - ;======================== - defn exists? (x:Int) : - val slot = loc(x) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : false - ;Case 2 of 3: Single item bucket - (s:Int) : s == x - ;Case 3 of 3: Multiple item bucket - (s:IntArray) : - val n = sizes[slot] - val i = num-before(s, n, x) - index-of-item(s, i, n, x) is Int - - ;========================== - ;==== Remove Operation ==== - ;========================== - ;Returns true if item was removed - defn remove (x:Int) : - val slot = loc(hash(x)) - match(slots[slot]) : - ;Case 1 of 3: Unoccupied bucket - (s:Sentinel) : - false - ;Case 2 of 3: Single item bucket - (s:Int) : - if s == x : - slots[slot] = sentinel() - decrement-size() + +;======================== +;==== Key? Operation ==== +;======================== +defmethod get (t:IntSet, x:Int) : + val slot = loc(t, x) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : false + ;Case 2 of 3: Single item bucket + (s:Int) : s == x + ;Case 3 of 3: Multiple item bucket + (s:IntArray) : + val n = sizes(t)[slot] + val i = num-before(s, n, x) + index-of-item(s, i, n, x) is Int + +;========================== +;==== Remove Operation ==== +;========================== +;Returns true if item was removed +defmethod remove (t:IntSet, x:Int) : + val slot = loc(t, x) + match(slots(t)[slot]) : + ;Case 1 of 3: Unoccupied bucket + (s:Sentinel) : + false + ;Case 2 of 3: Single item bucket + (s:Int) : + if s == x : + slots(t)[slot] = sentinel() + decrement-size(t) + true + ;Case 3 of 3: Multiple item bucket + (s:IntArray) : + val n = sizes(t)[slot] + val i = num-before(s, n, x) + match(index-of-item(s, i, n, x)) : + (idx:False) : false + (idx:Int) : + shift-left(s, idx, n) + sizes(t)[slot] = n - 1 + decrement-size(t) true - ;Case 3 of 3: Multiple item bucket - (s:IntArray) : - val n = sizes[slot] - val i = num-before(s, n, x) - match(index-of-item(s, i, n, x)) : - (idx:False) : false - (idx:Int) : - shift-left(s, idx, n) - sizes[slot] = n - 1 - decrement-size() - true - - ;============================= - ;==== Iteration Operation ==== - ;============================= - defn sequence () : - val sizes = sizes - val slots = slots - generate : - for idx in 0 to length(slots) do : - match(slots[idx]) : - (s:Sentinel) : false - (s:Int) : yield(s) - (s:IntArray) : for j in 0 to sizes[idx] do : yield(s[j]) - - ;====================== - ;==== Table Object ==== - ;====================== - new IntSet : - defmethod add (this, k:Int) : - put(k) - defmethod get (this, k:Int) : - exists?(k) - defmethod remove (this, k:Int) : - remove(k) - defmethod clear (this) : - clear() - defmethod to-seq (this) : - sequence() - defmethod length (this) : - size + +;============================= +;==== Iteration Operation ==== +;============================= +defmethod to-seq (t:IntSet) : + val sizes = sizes(t) + val slots = slots(t) + generate : + for idx in 0 to length(slots) do : + match(slots[idx]) : + (s:Sentinel) : false + (s:Int) : yield(s) + (s:IntArray) : for j in 0 to sizes[idx] do : yield(s[j]) + +defmethod length (t:IntSet) : + size(t) ;================================== ;==== Convenience Constructors ==== From aa26038e46aa1f7ea54cda71dbd0e0b48d0f636f Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Thu, 13 Mar 2025 20:16:51 -0700 Subject: [PATCH 20/24] speed up conversion to tuples and arrays --- core/core.stanza | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/core/core.stanza b/core/core.stanza index cc5109ad..fe2dfc2a 100644 --- a/core/core.stanza +++ b/core/core.stanza @@ -8846,16 +8846,20 @@ defmethod to-seq (r:Range) : ;------------- Converting Seq to Core Types ----------------- ;------------------------------------------------------------ +; assumes that n is correct and elts have length n +lostanza defn Tuple! (n:ref, elts:ref>) -> ref> : + val len = n.value + val t = new Tuple{len} + for (var i:long = 0, i < len, i = i + 1) : + t.items[i] = next(elts) + return t + public defn to-tuple (xs:Seqable) -> Tuple : match(xs) : (xs:Tuple) : xs (xs:Seqable & Lengthable) : - val n = length(xs) - val t = Tuple(n, false as ?) - for (x in xs, i in 0 to n) do : - t[i] = x - t + Tuple!(length(xs), to-seq(xs)) (xs) : to-tuple(to-vector(xs)) @@ -8881,14 +8885,28 @@ public defn to-list (xs:Seqable) -> List : else : accum loop(length(vec) - 1, List()) +; assumes n is correct and elts is correct length +lostanza defn Array! (n:ref, elts:ref>) -> ref> : + val len = n.value + val a = new Array{len} + for (var i:long = 0, i < len, i = i + 1) : + a.items[i] = next(elts) + return a + +; assumes n is correct and elts is correct length +lostanza defn Array! (n:ref, elts:ref|Tuple>) -> ref> : + val len = n.value + val a = new Array{len} + for (var i:int = 0, i < len, i = i + 1) : + a.items[i] = get(elts, new Int{i}) + return a + public defn to-array (xs:Seqable) -> Array : match(xs) : + (xs:Seqable & Lengthable) : + Array!(length(xs), to-seq(xs)) (xs:Vector|Tuple|Array) : - val n = length(xs) - val a = Array(n) - for i in 0 to n do : - a[i] = xs[i] - a + Array!(length(xs), xs) (xs) : to-array(to-vector(xs)) From d2eb95c6f65339f3d50ae2e66763f976940bc1b5 Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Mon, 17 Mar 2025 16:44:02 -0700 Subject: [PATCH 21/24] use IntTable where you can and switch to Arrayable for abstract array --- compiler/algorithms.stanza | 2 +- compiler/hash.stanza | 8 ++++---- compiler/reg-alloc.stanza | 24 ++++++++++++------------ compiler/set-simplifier.stanza | 6 +++--- compiler/stable-arrays.stanza | 2 +- compiler/vm-table.stanza | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/compiler/algorithms.stanza b/compiler/algorithms.stanza index 9ec57e3a..d98f1745 100644 --- a/compiler/algorithms.stanza +++ b/compiler/algorithms.stanza @@ -261,7 +261,7 @@ public defn strong-components (graph: Seqable : +public lostanza deftype BitArray <: Arrayable : words: long length: long var bits: long ... diff --git a/compiler/hash.stanza b/compiler/hash.stanza index 9590a336..08708954 100644 --- a/compiler/hash.stanza +++ b/compiler/hash.stanza @@ -88,16 +88,16 @@ public defn PerfectHashTable (entries0:Collection> & Length ;Hold buckets and sorted bucket indices var buckets:Array>> - var bucket-indices:Array - var dtable:Array + var bucket-indices:IntArray + var dtable:IntArray var etable:Array|False> ;Put all entries in buckets defn put-in-buckets (d0:Int) : ;Initialize all tables buckets = Array>>(n, List()) - bucket-indices = to-array(0 to n) - dtable = Array(n, 0) + bucket-indices = to-intarray(0 to n) + dtable = IntArray(n, 0) etable = Array|False>(n, false) ;Put in buckets diff --git a/compiler/reg-alloc.stanza b/compiler/reg-alloc.stanza index 135bc8e1..d0315d1e 100644 --- a/compiler/reg-alloc.stanza +++ b/compiler/reg-alloc.stanza @@ -1043,7 +1043,7 @@ defn unused-regs (used:Seqable, num:Int, backend:Backend) -> Vector : defn remove-critical-edges () : ;Count predecessors - val num-preds-table = Array(nblocks(),0) + val num-preds-table = IntArray(nblocks(),0) for (b in BLOCKS, i in 0 to false) do : for n in next(b) do : num-preds-table[n] = 1 + num-preds-table[n] @@ -1171,8 +1171,8 @@ defn liveness-analysis () : ;Propagate liveness clear(IN-PORTS, nblocks(), List()) clear(OUT-PORTS, nblocks(), List()) - val in-dists = Array(nblocks(), INT-MAX) - val out-dists = Array(nblocks(), INT-MAX) + val in-dists = IntArray(nblocks(), INT-MAX) + val out-dists = IntArray(nblocks(), INT-MAX) val in-dirty = Vector() val out-dirty = Vector() @@ -1198,8 +1198,8 @@ defn liveness-analysis () : ;Mark that variable v is live-in to block b with distance d lostanza defn mark-live-in (defs:ref, - in-dists:ref>, - out-dists:ref>, + in-dists:ref, + out-dists:ref, in-dirty:ref>, out-dirty:ref>, b:ref, @@ -1230,8 +1230,8 @@ lostanza defn mark-live-in (defs:ref, ;Mark that variable v is live-out from block b with distance d lostanza defn mark-live-out (defs:ref, - in-dists:ref>, - out-dists:ref>, + in-dists:ref, + out-dists:ref, in-dirty:ref>, out-dirty:ref>, b:ref, @@ -2011,8 +2011,8 @@ defn stack-intervals () -> Seq : ;======================== ;==== Port Positions ==== ;======================== - val in-port-pos = Array(nblocks()) - val out-port-pos = Array(nblocks()) + val in-port-pos = IntArray(nblocks()) + val out-port-pos = IntArray(nblocks()) val num-pos = let : val pos-counter = Counter(0) for (blk in BLOCKS, b in 0 to false) do : @@ -2023,8 +2023,8 @@ defn stack-intervals () -> Seq : ;=========================== ;==== Interval Tracking ==== ;=========================== - val var-start = Array(nvars(), INT-MAX) - val var-end = Array(nvars(), INT-MIN) + val var-start = IntArray(nvars(), INT-MAX) + val var-end = IntArray(nvars(), INT-MIN) defn note-usage (v:Int, i:Int) : var-start[v] = min(i, var-start[v]) @@ -2414,7 +2414,7 @@ defn collapse-blocks () : ;====================== ;==== Block Labels ==== ;====================== - val lbls = Array(nblocks()) + val lbls = IntArray(nblocks()) lbls[0 to false] = repeatedly(unique-id{}) ;=================== diff --git a/compiler/set-simplifier.stanza b/compiler/set-simplifier.stanza index 2df76767..8b88f4db 100644 --- a/compiler/set-simplifier.stanza +++ b/compiler/set-simplifier.stanza @@ -191,9 +191,9 @@ defn dnf-form (term:Term) -> Term : (t) : [t] ;Permutations - defn permutations (return:Array -> ?, lengths:Tuple) : + defn permutations (return:IntArray -> ?, lengths:Tuple) : val dims = length(lengths) - val indices = Array(dims, 0) + val indices = IntArray(dims, 0) let loop (d:Int = 0) : if d < dims : for i in 0 to lengths[d] do : @@ -203,7 +203,7 @@ defn dnf-form (term:Term) -> Term : return(indices) ;Retrieve the given indices in the given term tuple. - defn gather-intersection-vars (termss:Tuple>, indices:Array) -> Seq : + defn gather-intersection-vars (termss:Tuple>, indices:IntArray) -> Seq : for (i in indices, terms in termss) seq-cat : match(terms[i]) : (t:Intersection) : /terms(t) diff --git a/compiler/stable-arrays.stanza b/compiler/stable-arrays.stanza index 0d2828ce..aa663097 100644 --- a/compiler/stable-arrays.stanza +++ b/compiler/stable-arrays.stanza @@ -14,7 +14,7 @@ lostanza defmethod run (a:ref) -> ref : StablePrimArray in [StableByteArray StableIntArray StableLongArray StableFloatArray StableDoubleArray] x0 in [0Y 0 0L 0.0f 0.0]) : - public lostanza deftype StablePrimArray <: Array & Unique : + public lostanza deftype StablePrimArray <: Arrayable & Unique : length: long data: ptr diff --git a/compiler/vm-table.stanza b/compiler/vm-table.stanza index d7350582..1b110136 100644 --- a/compiler/vm-table.stanza +++ b/compiler/vm-table.stanza @@ -363,7 +363,7 @@ public lostanza defn load-data (vmt:ref, d:ref) -> ref : public defn load-datas (vmt:VMTable, ds:Tuple) : do(load-data{vmt, _}, ds) -lostanza defn non-negative? (xs:ref>, i:ref) -> long : +lostanza defn non-negative? (xs:ref, i:ref) -> long : val l = length(xs).value if i.value < l : if get(xs,i).value >= 0 : return 1L From 2025412f7783f02b74bfbb5b760c292ace6c830f Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Tue, 18 Mar 2025 17:15:39 -0700 Subject: [PATCH 22/24] fix tiny buglets in tables/sets --- core/collections.stanza | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/core/collections.stanza b/core/collections.stanza index 38ea55ff..392a5eb9 100644 --- a/core/collections.stanza +++ b/core/collections.stanza @@ -466,7 +466,7 @@ defn init (t:HashTable, c:Int) : set-sizes(t, IntArray(c, 0)) set-size(t, 0) -defn clear (t:HashTable) : +defmethod clear (t:HashTable) : set-size(t, 0) set-all(slots(t), 0 to false, sentinel()) @@ -512,7 +512,7 @@ defn* shift-left (xs:Array>, i:Int, n:Int) : for j in i to (n - 1) do : xs[j] = xs[j + 1] -;Copy to new array with hole in position i +;Copy to array with hole in position i defn* copy-with-hole (t:HashTable, xs:Array>, i:Int, n:Int) : val xs* = Array>(length(xs) * 2) xs*[0 to i] = xs[0 to i] @@ -875,7 +875,7 @@ defn init (t:IntTable, c:Int) : set-sizes(t, IntArray(c, 0)) set-size(t, 0) -defn clear (t:IntTable) : +defmethod clear (t:IntTable) : set-size(t, 0) set-all(slots(t), 0 to false, sentinel()) @@ -1073,7 +1073,7 @@ defmethod get (t:IntTable, k:Int) : ;========================== ;==== Update Operation ==== ;========================== -defn update (t:IntTable, f:V -> V, k:Int) : +defmethod update (t:IntTable, f:V -> V, k:Int) : defn item (v:V) : IntItem(k,v) val slot = loc(t, k) match(slots(t)[slot]) : @@ -1113,7 +1113,7 @@ defn update (t:IntTable, f:V -> V, k:Int) : ;======================== ;==== Key? Operation ==== ;======================== -defn key? (t:IntTable, k:Int) : +defmethod key? (t:IntTable, k:Int) : val slot = loc(t, k) match(slots(t)[slot]) : ;Case 1 of 3: Unoccupied bucket @@ -1129,7 +1129,7 @@ defn key? (t:IntTable, k:Int) : ;========================== ;==== Remove Operation ==== ;========================== -defn remove (t:IntTable, k:Int) : +defmethod remove (t:IntTable, k:Int) : val slot = loc(t, k) match(slots(t)[slot]) : ;Case 1 of 3: Unoccupied bucket @@ -1228,6 +1228,7 @@ defmethod print (o:OutputStream, t:IntTable) : lnprint(o, Indented(entry)) print(o, ")") + ;============================================================ ;======================== Sets ============================== ;============================================================ @@ -1279,7 +1280,7 @@ defn init (t:HashSet, c:Int) : set-sizes(t, IntArray(c, 0)) set-size(t, 0) -defn clear (t:HashSet) : +defmethod clear (t:HashSet) : set-size(t, 0) set-all(slots(t), 0 to false, sentinel()) @@ -1585,8 +1586,9 @@ defn decrement-size (t:IntSet) : set-size(t, length(t) - 1) defn increase-capacity (t:IntSet) : + val s = to-seq(t) init(t, cap(t) * 2) - do(add{t, _}, to-seq(t)) + do(add{t, _}, s) defn create-bucket (t:IntSet, slot:Int, x0:Int, x1:Int) : val bucket = IntArray(4) @@ -1738,4 +1740,4 @@ public defstruct MissingTableKey <: RuntimeError : key defmethod print (o:OutputStream, e:MissingTableKey) : - print(o, "Key %_ does not exist in table." % [key(e)]) \ No newline at end of file + print(o, "Key %_ does not exist in table." % [key(e)]) From ced5704089b80f30e89e27f17bab711c972bdd2e Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Tue, 18 Mar 2025 17:23:46 -0700 Subject: [PATCH 23/24] initialize to false before to-seq'ing for to-tuple and to-array and add another case for to-tuple speed up --- core/core.stanza | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/core/core.stanza b/core/core.stanza index fe2dfc2a..00d24cda 100644 --- a/core/core.stanza +++ b/core/core.stanza @@ -8850,16 +8850,29 @@ defmethod to-seq (r:Range) : lostanza defn Tuple! (n:ref, elts:ref>) -> ref> : val len = n.value val t = new Tuple{len} + ;need to initialize first because Seq could cons and cause GC + for (var i:long = 0, i < len, i = i + 1) : + t.items[i] = false as ref for (var i:long = 0, i < len, i = i + 1) : t.items[i] = next(elts) return t +; assumes that n is correct and elts have length n +lostanza defn Tuple! (n:ref, elts:ref>) -> ref> : + val len = n.value + val t = new Tuple{len} + for (var i:int = 0, i < len, i = i + 1) : + t.items[i] = get(elts, new Int{i}) + return t + public defn to-tuple (xs:Seqable) -> Tuple : match(xs) : (xs:Tuple) : xs (xs:Seqable & Lengthable) : Tuple!(length(xs), to-seq(xs)) + (xs:IndexedCollection) : + Tuple!(length(xs), xs) (xs) : to-tuple(to-vector(xs)) @@ -8889,6 +8902,8 @@ public defn to-list (xs:Seqable) -> List : lostanza defn Array! (n:ref, elts:ref>) -> ref> : val len = n.value val a = new Array{len} + for (var i:long = 0, i < len, i = i + 1) : + a.items[i] = false as ref for (var i:long = 0, i < len, i = i + 1) : a.items[i] = next(elts) return a @@ -8905,7 +8920,7 @@ public defn to-array (xs:Seqable) -> Array : match(xs) : (xs:Seqable & Lengthable) : Array!(length(xs), to-seq(xs)) - (xs:Vector|Tuple|Array) : + (xs:IndexedCollection|Tuple) : Array!(length(xs), xs) (xs) : to-array(to-vector(xs)) From 2172b868781ee60337f69b51da9a6322ec0104ca Mon Sep 17 00:00:00 2001 From: jackbackrack Date: Wed, 19 Mar 2025 09:45:19 -0700 Subject: [PATCH 24/24] revert to-tuple and to-array because doesn't save that much and becomes more complicated --- core/core.stanza | 55 ++++++++++-------------------------------------- 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/core/core.stanza b/core/core.stanza index 00d24cda..cc5109ad 100644 --- a/core/core.stanza +++ b/core/core.stanza @@ -8846,33 +8846,16 @@ defmethod to-seq (r:Range) : ;------------- Converting Seq to Core Types ----------------- ;------------------------------------------------------------ -; assumes that n is correct and elts have length n -lostanza defn Tuple! (n:ref, elts:ref>) -> ref> : - val len = n.value - val t = new Tuple{len} - ;need to initialize first because Seq could cons and cause GC - for (var i:long = 0, i < len, i = i + 1) : - t.items[i] = false as ref - for (var i:long = 0, i < len, i = i + 1) : - t.items[i] = next(elts) - return t - -; assumes that n is correct and elts have length n -lostanza defn Tuple! (n:ref, elts:ref>) -> ref> : - val len = n.value - val t = new Tuple{len} - for (var i:int = 0, i < len, i = i + 1) : - t.items[i] = get(elts, new Int{i}) - return t - public defn to-tuple (xs:Seqable) -> Tuple : match(xs) : (xs:Tuple) : xs (xs:Seqable & Lengthable) : - Tuple!(length(xs), to-seq(xs)) - (xs:IndexedCollection) : - Tuple!(length(xs), xs) + val n = length(xs) + val t = Tuple(n, false as ?) + for (x in xs, i in 0 to n) do : + t[i] = x + t (xs) : to-tuple(to-vector(xs)) @@ -8898,30 +8881,14 @@ public defn to-list (xs:Seqable) -> List : else : accum loop(length(vec) - 1, List()) -; assumes n is correct and elts is correct length -lostanza defn Array! (n:ref, elts:ref>) -> ref> : - val len = n.value - val a = new Array{len} - for (var i:long = 0, i < len, i = i + 1) : - a.items[i] = false as ref - for (var i:long = 0, i < len, i = i + 1) : - a.items[i] = next(elts) - return a - -; assumes n is correct and elts is correct length -lostanza defn Array! (n:ref, elts:ref|Tuple>) -> ref> : - val len = n.value - val a = new Array{len} - for (var i:int = 0, i < len, i = i + 1) : - a.items[i] = get(elts, new Int{i}) - return a - public defn to-array (xs:Seqable) -> Array : match(xs) : - (xs:Seqable & Lengthable) : - Array!(length(xs), to-seq(xs)) - (xs:IndexedCollection|Tuple) : - Array!(length(xs), xs) + (xs:Vector|Tuple|Array) : + val n = length(xs) + val a = Array(n) + for i in 0 to n do : + a[i] = xs[i] + a (xs) : to-array(to-vector(xs))