vectors.scm 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. ;;; Vectors
  2. ;;; Copyright (C) 2024 Igalia, S.L.
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; Vectors.
  18. ;;;
  19. ;;; Code:
  20. (library (hoot vectors)
  21. (export vector
  22. make-vector
  23. vector?
  24. vector-length
  25. vector-ref
  26. vector-set!
  27. vector-copy
  28. vector-copy!
  29. vector-fill!
  30. vector->list
  31. list->vector
  32. vector-concatenate
  33. vector-append
  34. vector-for-each
  35. vector-map
  36. vector-sort!
  37. vector-binary-search)
  38. (import (only (hoot primitives)
  39. %vector? %make-vector %vector
  40. %vector-length %vector-ref %vector-set!)
  41. (hoot apply)
  42. (hoot errors)
  43. (hoot inline-wasm)
  44. (hoot lists)
  45. (hoot match)
  46. (hoot numbers)
  47. (hoot pairs)
  48. (hoot syntax)
  49. (hoot values))
  50. (define (%generic-vector . args) (list->vector args))
  51. (define-syntax vector
  52. (lambda (stx)
  53. (syntax-case stx ()
  54. ((_ . x) #'(%vector . x))
  55. (f (identifier? #'f) #'%generic-vector))))
  56. (define* (make-vector n #:optional init) (%make-vector n init))
  57. (define (vector? x) (%vector? x))
  58. (define (vector-length x) (%vector-length x))
  59. (define (vector-ref x i) (%vector-ref x i))
  60. (define (vector-set! x i v) (%vector-set! x i v))
  61. (define* (vector-copy v #:optional (start 0) (end (vector-length v)))
  62. (check-type v vector? 'vector-copy)
  63. (check-range start 0 (vector-length v) 'vector-copy)
  64. (check-range end start (vector-length v) 'vector-copy)
  65. (%inline-wasm
  66. '(func (param $src (ref $vector)) (param $start i32) (param $end i32)
  67. (result (ref eq))
  68. (local $i0 i32)
  69. (local $v0 (ref $raw-scmvector))
  70. (local.set $i0 (i32.sub (local.get $end)
  71. (local.get $start)))
  72. (local.set $v0 (array.new $raw-scmvector (ref.i31 (i32.const 0))
  73. (local.get $i0)))
  74. (array.copy $raw-scmvector $raw-scmvector
  75. (local.get $v0) (i32.const 0)
  76. (struct.get $vector $vals (local.get $src))
  77. (local.get $start) (local.get $i0))
  78. (struct.new $mutable-vector (i32.const 0) (local.get $v0)))
  79. v start end))
  80. (define* (vector-copy! to at from #:optional (start 0) (end (vector-length from)))
  81. (check-type to vector? 'vector-copy!)
  82. (check-range at 0 (vector-length to) 'vector-copy!)
  83. (check-type from vector? 'vector-copy!)
  84. (check-range start 0 (vector-length from) 'vector-copy!)
  85. (check-range end start (vector-length from) 'vector-copy!)
  86. (%inline-wasm
  87. '(func (param $to (ref $mutable-vector)) (param $at i32)
  88. (param $from (ref $vector)) (param $start i32) (param $end i32)
  89. (array.copy $raw-scmvector $raw-scmvector
  90. (struct.get $mutable-vector $vals (local.get $to))
  91. (local.get $at)
  92. (struct.get $vector $vals (local.get $from))
  93. (local.get $start)
  94. (i32.sub (local.get $end) (local.get $start))))
  95. to at from start end))
  96. (define* (vector-fill! v fill #:optional (start 0) (end (vector-length v)))
  97. ;; FIXME: check for mutability
  98. (check-type v vector? 'vector-fill!)
  99. (check-range start 0 (vector-length v) 'vector-fill!)
  100. (check-range end start (vector-length v) 'vector-fill!)
  101. (%inline-wasm
  102. '(func (param $dst (ref $mutable-vector)) (param $fill (ref eq))
  103. (param $start i32) (param $end i32)
  104. (array.fill $raw-scmvector
  105. (struct.get $mutable-vector $vals (local.get $dst))
  106. (local.get $start)
  107. (local.get $fill)
  108. (i32.sub (local.get $end) (local.get $start))))
  109. v fill start end))
  110. (define* (vector->list v #:optional (start 0) (end (vector-length v)))
  111. (let lp ((i start))
  112. (if (< i end)
  113. (cons (vector-ref v i) (lp (1+ i)))
  114. '())))
  115. (define (list->vector elts)
  116. (define (length l)
  117. (let lp ((len 0) (l l))
  118. (if (null? l) len (lp (1+ len) (cdr l)))))
  119. (let* ((len (length elts))
  120. (v (make-vector len #f)))
  121. (let lp ((i 0) (elts elts))
  122. (match elts
  123. (() v)
  124. ((elt . elts)
  125. (vector-set! v i elt)
  126. (lp (1+ i) elts))))))
  127. (define (vector-concatenate v*)
  128. (match v*
  129. (() #())
  130. ((v) v)
  131. (v*
  132. (let* ((len (fold (lambda (v len) (+ (vector-length v) len)) 0 v*))
  133. (flattened (make-vector len 0)))
  134. (let lp ((v* v*) (cur 0))
  135. (match v*
  136. (() flattened)
  137. ((v . v*)
  138. (vector-copy! flattened cur v)
  139. (lp v* (+ cur (vector-length v))))))))))
  140. (define (vector-append . vectors)
  141. (vector-concatenate vectors))
  142. (define (vector-for-each f v . v*)
  143. (apply for-each f (vector->list v) (map vector->list v*)))
  144. (define (vector-map f v . v*)
  145. (list->vector (apply map f (vector->list v) (map vector->list v*))))
  146. (define* (vector-sort! v less? #:optional (start 0) (end (vector-length v)))
  147. (define (partition start end)
  148. ;; TODO: Using last element as pivot for simplicity. Choose a
  149. ;; different pivot to avoid worst-case scenarios for sorted or
  150. ;; nearly sorted vectors.
  151. (let* ((pivot-idx (1- end))
  152. (pivot (vector-ref v pivot-idx)))
  153. (let lp ((i start) (j start))
  154. (if (< j pivot-idx)
  155. (let ((item (vector-ref v j)))
  156. (if (less? pivot item)
  157. (lp i (1+ j))
  158. (let ((other (vector-ref v i)))
  159. (vector-set! v j other)
  160. (vector-set! v i item)
  161. (lp (1+ i) (1+ j)))))
  162. (let ((other (vector-ref v i)))
  163. (vector-set! v i pivot)
  164. (vector-set! v pivot-idx other)
  165. i)))))
  166. (define (quicksort start end)
  167. (when (< start end)
  168. (let ((i (partition start end)))
  169. (quicksort start i)
  170. (quicksort (1+ i) end))))
  171. (check-size end (vector-length v) 'vector-sort!)
  172. (check-size start (1- end) 'vector-sort!)
  173. (quicksort start end)
  174. (values))
  175. (define* (vector-binary-search v x compare #:optional (start 0) (end (vector-length v)))
  176. (and (< start end)
  177. (let* ((i (+ start (quotient (- end start) 2)))
  178. (diff (compare (vector-ref v i) x)))
  179. (cond
  180. ((zero? diff) i)
  181. ((positive? diff) (vector-binary-search v x compare start i))
  182. (else (vector-binary-search v x compare (1+ i) end)))))))