;;; Copyright (c) 2023 Jeremy Steward ;;; All rights reserved. ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions are met: ;;; ;;; 1. Redistributions of source code must retain the above copyright notice, ;;; this list of conditions and the following disclaimer. ;;; ;;; 2. Redistributions in binary form must reproduce the above copyright notice, ;;; this list of conditions and the following disclaimer in the documentation ;;; and/or other materials provided with the distribution. ;;; ;;; 3. Neither the name of the copyright holder nor the names of its ;;; contributors may be used to endorse or promote products derived from this ;;; software without specific prior written permission. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ;;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ;;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ;;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ;;; CONSEQUENTIAL DAMAGES INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ;;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ;;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ;;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ;;; POSSIBILITY OF SUCH DAMAGE. (cond-expand (chicken-5 (declare (safe-globals) (specialize)))) (define-library (generalized-arrays storage) (import (scheme base) (scheme case-lambda) (srfi 4) (srfi 128) (srfi 133) (srfi 143) (only (srfi 160 u8) u8? u8vector-copy u8vector-copy!) (only (srfi 160 u16) u16? u16vector-copy u16vector-copy!) (only (srfi 160 u32) u32? u32vector-copy u32vector-copy!) (only (srfi 160 u64) u64? u64vector-copy u64vector-copy!) (only (srfi 160 s8) s8? s8vector-copy s8vector-copy!) (only (srfi 160 s16) s16? s16vector-copy s16vector-copy!) (only (srfi 160 s32) s32? s32vector-copy s32vector-copy!) (only (srfi 160 s64) s64? s64vector-copy s64vector-copy!) (only (srfi 160 f32) f32? f32vector-copy f32vector-copy!) (only (srfi 160 f64) f64? f64vector-copy f64vector-copy!) (only (srfi 160 c64) make-c64vector c64? c64vector? c64vector-length c64vector-ref c64vector-set! c64vector-copy c64vector-copy!) (only (srfi.160 c128) make-c128vector c128? c128vector? c128vector-length c128vector-ref c128vector-set! c128vector-copy c128vector-copy!) (transducers vectors)) (cond-expand (chicken-5 (import (only (chicken base) void)) (import-syntax (srfi 253)) (import-syntax (chicken type))) (else (import (srfi 253)) (define unspecified-value (list '*UNSPECIFIED*)) (define (void) unspecified-value))) (include-library-declarations "src/generalized-arrays.storage.exports.scm") (begin ;; Predicate to check for a non-negative (zero or greater) fixnum (define (non-negative-fixnum? x) (and (fixnum? x) (fx>=? x 0))) ;; A storage class is a type-class object that covers types that can "store" values. ;; ;; Specifically, storage classes refer to contiguous containers that can be ;; accessed randomly. They are meant to exist as the backend data storage ;; for generalized-arrays. (define-record-type ;; Constructs a storage class. (make-storage-class short-id constructor ref set length copy copy! transducible comparator default-element) ;; Predicate for testing if an object is a storage class. storage-class? ;; A short ID for the storage class. ;; ;; This identifier exists to be a unique short-code for a storage class' ;; type or kind. For example, a vector-storage-class (which uses a Scheme ;; vector as the underlying storage type) would have a short ID that is ;; the symbol 'v. (short-id storage-class-short-id) ;; A procedure of the form (make-storage size #!optional fill) which ;; constructs a new storage object of the implementing storage class. (constructor storage-class-constructor) ;; A procedure of the form (storage-ref storage index) which gets an ;; individual element at `index` from the `storage` object. (ref storage-class-ref) ;; A procedure of the form (storage-set! storage index value) which sets ;; `value` to the element at `index` in `storage` object. (set storage-class-set) ;; A procedure of the form (storage-length storage) which gets the number ;; of total elements in the `storage` object. (length storage-class-length) ;; A procedure of the form (storage-copy storage) which creates a direct ;; copy of the `storage` object and returns it. (copy storage-class-copy) ;; A procedure of the form (storage-copy storage) which creates a direct ;; copy of the `storage` object and returns it. (copy! storage-class-copy!) ;; A transducible type-class over the storage object kind. ;; ;; See the documentation of transducible type-classes in the transducers ;; library for more details. (transducible storage-class-transducible) ;; A SRFI-128 comparator for storage objects of the storage class. (comparator storage-class-comparator) ;; A value which represents the default element of the storage object. ;; ;; This is used when producing a default storage object, or filling ;; individual elements with a default value when filtered. (default-element storage-class-default-element)) ;;; Invokers ;; ;; The following procedures are for invoking stored procedures in the ;; argument storage-classes. The naming is slightly different than just ;; plain-invoking the storage-class procedures themselves. In fact, these ;; are all named `storage-object` to differentiate them from storage-class ;; procedures. ;; ;; Functionally speaking these shouldn't be any different from calling the ;; storage-class procedures directly but may offer a cleaner interface. ;; Constructs a storage object of the provided storage-class with `n` ;; elements defaulting to the provided `fill` value. If `fill` is not ;; provided, the storage-class' default element will be used instead. (define make-storage-object (case-lambda ((storage-class n fill) (let ((constructor (storage-class-constructor storage-class))) (constructor n fill))) ((storage-class n) (let ((fill (storage-class-default-element storage-class))) (make-storage-object storage-class n fill))))) ;; Gets the `i`th element contained inside the storage object `obj`. (define-checked (storage-object-ref (storage-class storage-class?) obj (i non-negative-fixnum?)) (let ((comparator (storage-class-comparator storage-class))) (comparator-check-type comparator obj) (let ((storage-ref (storage-class-ref storage-class))) (storage-ref obj i)))) ;; Sets the `i`th element contained inside the storage object `obj` to ;; `value`. (define-checked (storage-object-set! (storage-class storage-class?) obj (i non-negative-fixnum?) value) (let ((comparator (storage-class-comparator storage-class))) (comparator-check-type comparator obj) (let ((storage-set! (storage-class-set storage-class))) (storage-set! obj i value)))) ;; Gets the length (number of elements contained within) an `obj` of class ;; `storage-class`. (define-checked (storage-object-length (storage-class storage-class?) obj) (let ((comparator (storage-class-comparator storage-class))) (comparator-check-type comparator obj) (let ((storage-length (storage-class-length storage-class))) (storage-length obj)))) (define-checked (storage-object-copy-impl! (storage-class storage-class?) to at from start end) (let ((comparator (storage-class-comparator storage-class))) (comparator-check-type comparator to) (comparator-check-type comparator from) (let ((storage-copy! (storage-class-copy! storage-class))) (storage-copy! to at from start end)))) ;; Copies the elements in the `[start end)` range from storage object ;; `from` to storage object `to`, starting at index `at`. (define storage-object-copy! (case-lambda ((storage-class to at from start end) (storage-object-copy-impl! storage-class to at from start end)) ((storage-class to at from start) (let ((end (storage-object-length storage-class from))) (storage-object-copy-impl! storage-class to at from start end))) ((storage-class to at from) (storage-object-copy! storage-class to at from 0)))) (define storage-object-copy (case-lambda-checked ((storage-class object start) (storage-object-copy storage-class object start ((storage-class-length storage-class) object))) ((storage-class object) (storage-object-copy storage-class object 0 ((storage-class-length storage-class) object))) (((storage-class storage-class?) object (start non-negative-fixnum?) (end non-negative-fixnum?)) (comparator-check-type (storage-class-comparator storage-class) object) (let ((storage-copy (storage-class-copy storage-class))) (storage-copy object start end))))) ;;; Standard storage classes (define vector-storage-class (make-storage-class 'v make-vector vector-ref vector-set! vector-length vector-copy vector-copy! vector-transducible (make-vector-comparator (make-default-comparator) vector? vector-length vector-ref) (void))) (define (make-fixnum-comparator type-test?) (make-comparator type-test? fx=? fx