From e7faf40f4d354f63d9f03ab4ee9dec97c2f0988e Mon Sep 17 00:00:00 2001 From: Robert Smith Date: Thu, 5 Oct 2023 18:30:52 -0700 Subject: [PATCH 1/3] implementation of RandomAccess class This adds a new class to the standard library (RandomAccess :F :T) allows the storage of elements of type :T inside of a storage type :F with efficient O(1) read/write access. The class implements a few instances (which could be expanded to all reasonable efficient types), and uses the convention of adding an 's' to the base type (e.g., a storage of Double-Float is DoubleFloats). We don't keep "legacy" '-' in existing names. All operations become efficient Common Lisp code, up to inlining. --- coalton.asd | 3 +- library/randomaccess.lisp | 68 +++++++++++++++++++++++++++++ src/doc/generate-documentation.lisp | 1 + 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 library/randomaccess.lisp diff --git a/coalton.asd b/coalton.asd index cafb1954f..f9e41fe6e 100644 --- a/coalton.asd +++ b/coalton.asd @@ -161,7 +161,8 @@ (:file "complex") (:file "elementary") (:file "dyadic") - (:file "dual"))) + (:file "dual"))) + (:file "randomaccess") (:file "cell") (:file "iterator") (:file "optional") diff --git a/library/randomaccess.lisp b/library/randomaccess.lisp new file mode 100644 index 000000000..27d15cfed --- /dev/null +++ b/library/randomaccess.lisp @@ -0,0 +1,68 @@ +(coalton-library/utils:defstdlib-package #:coalton-library/randomaccess + (:use + #:coalton + #:coalton-library/classes) + (:export + #:RandomAccess + #:make + #:length + #:readable? + #:writable? + #:unsafe-aref + #:unsafe-set! + + #:aref + #:set!)) + +(in-package #:coalton-library/randomaccess) + +(named-readtables:in-readtable coalton:coalton) + +#+coalton-release +(cl:declaim #.coalton-impl/settings:*coalton-optimize-library*) + +;;; Class Implementation +(coalton-toplevel + ;; The decision to use a functional dependency was an ergonomic one, + ;; not a technical one. If we did not establish this dependency, we + ;; would win flexibility (a single storage type can store multiple + ;; data types), but we would lose a lot of practical ergonomics + ;; (e.g., we would need Proxy types, calls to length would need to be + ;; disambiguated, etc.). + ;; + ;; While we lose some flexibility, we still retain some. For + ;; instance, we can have multiple storage types for double floats + ;; (think: Lisp arrays, C arrays, GPU arrays, etc.). + (define-class (RandomAccess :f :t (:f -> :t)) + "Establishes that `:f` is a random-access store of elements of type `:t`. The **storage type** `:f` implies the **stored type** `:t`. The storage is expected to be sequential and O(1) in random access reads and writes. + +It is permitted for any of `make`, `unsafe-aref`, or `unsafe-set!` to error." + (make (UFix -> :t -> :f)) + (length (:f -> UFix)) + (readable? (:f -> Boolean)) + (writable? (:f -> Boolean)) + (unsafe-aref (:f -> UFix -> :t)) + (unsafe-set! (:f -> UFix -> :t -> Unit)))) + +;;; Derived Functions +(coalton-toplevel + (declare aref (RandomAccess :f :t => :f -> UFix -> (Optional :t))) + (define (aref storage index) + "Read the element at `index` of the random-access storage `storage`. Return `None` if the read is out-of-bounds or not permitted." + (if (and (readable? storage) + (<= 0 index) + (< index (length storage))) + (Some (unsafe-aref storage index)) + None)) + + (declare set! (RandomAccess :f :t => :f -> UFix -> :t -> (Optional Unit))) + (define (set! storage index value) + "Write the element `value` at `index` of the random-access storage `storage`. Return `None` if the write is out-of-bounds or not permitted." + (if (and (writable? storage) + (<= 0 index) + (< index (length storage))) + (Some (unsafe-set! storage index value)) + None))) + +#+sb-package-locks +(sb-ext:lock-package "COALTON-LIBRARY/RANDOMACCESS") diff --git a/src/doc/generate-documentation.lisp b/src/doc/generate-documentation.lisp index 2c587a544..00d402dab 100644 --- a/src/doc/generate-documentation.lisp +++ b/src/doc/generate-documentation.lisp @@ -125,6 +125,7 @@ coalton-library/list coalton-library/result coalton-library/cell + coalton-library/randomaccess coalton-library/vector coalton-library/slice coalton-library/hashtable From 044e11130e60c0298e4623b1617beaf59f7cbc54 Mon Sep 17 00:00:00 2001 From: Robert Smith Date: Wed, 11 Oct 2023 13:06:13 -0700 Subject: [PATCH 2/3] remove unnecessary constraint --- library/vector.lisp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/vector.lisp b/library/vector.lisp index be5ebd7c6..68a8a4a54 100644 --- a/library/vector.lisp +++ b/library/vector.lisp @@ -66,7 +66,7 @@ (lisp (Vector :a) (n) (cl:make-array n :fill-pointer 0 :adjustable cl:t :element-type cl:t))) - (declare with-initial-element (types:RuntimeRepr :a => UFix -> :a -> Vector :a)) + (declare with-initial-element (UFix -> :a -> Vector :a)) (define (with-initial-element n x) "Create a new vector with `n` elements equal to `x`." (let v = (with-capacity n)) From 236768f1d79a679d63dd5a5567238e2c56b743c7 Mon Sep 17 00:00:00 2001 From: Robert Smith Date: Wed, 11 Oct 2023 13:06:44 -0700 Subject: [PATCH 3/3] instantiate RandomAccess (Vector :t) :t --- library/vector.lisp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/library/vector.lisp b/library/vector.lisp index 68a8a4a54..b39dabff6 100644 --- a/library/vector.lisp +++ b/library/vector.lisp @@ -8,7 +8,8 @@ (#:types #:coalton-library/types) (#:list #:coalton-library/list) (#:cell #:coalton-library/cell) - (#:iter #:coalton-library/iterator)) + (#:iter #:coalton-library/iterator) + (#:ram #:coalton-library/randomaccess)) (:export #:Vector #:new @@ -286,6 +287,20 @@ :initial-value init :from-end cl:t)))) + (define-instance (ram:RandomAccess (Vector :t) :t) + (define (ram:make n x) + (with-initial-element n x)) + (define (ram:length a) + (length a)) + (define (ram:readable? _) + True) + (define (ram:writable? _) + True) + (define (ram:unsafe-aref a n) + (index-unsafe n a)) + (define (ram:unsafe-set! a n x) + (set! n x a))) + (define-instance (Into (List :a) (Vector :a)) (define (into lst) (let ((out (with-capacity (list:length lst)))