intmap.scm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. ;;; Functional name maps
  2. ;;; Copyright (C) 2014-2017,2019 Free Software Foundation, Inc.
  3. ;;;
  4. ;;; This library is free software: you can redistribute it and/or modify
  5. ;;; it under the terms of the GNU Lesser General Public License as
  6. ;;; published by the Free Software Foundation, either version 3 of the
  7. ;;; License, or (at your option) any later version.
  8. ;;;
  9. ;;; This library is distributed in the hope that it will be useful, but
  10. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; Lesser General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU Lesser General Public
  15. ;;; License along with this program. If not, see
  16. ;;; <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;;;
  19. ;;; Some CPS passes need to perform a flow analysis in which every
  20. ;;; program point has an associated map over some set of labels or
  21. ;;; variables. The naive way to implement this is with an array of
  22. ;;; arrays, but this has N^2 complexity, and it really can hurt us.
  23. ;;;
  24. ;;; Instead, this module provides a functional map that can share space
  25. ;;; between program points, reducing the amortized space complexity of
  26. ;;; the representations down to O(n log n). Adding entries to the
  27. ;;; mapping and lookup are O(log n). Intersection and union between
  28. ;;; intmaps that share state are fast, too.
  29. ;;;
  30. ;;; Code:
  31. (define-module (language cps intmap)
  32. #:use-module (srfi srfi-9)
  33. #:use-module (srfi srfi-9 gnu)
  34. #:use-module (ice-9 match)
  35. #:use-module ((ice-9 threads) #:select (current-thread))
  36. #:export (empty-intmap
  37. intmap?
  38. transient-intmap?
  39. persistent-intmap
  40. transient-intmap
  41. intmap-add
  42. intmap-add!
  43. intmap-replace
  44. intmap-replace!
  45. intmap-remove
  46. intmap-ref
  47. intmap-next
  48. intmap-prev
  49. intmap-fold
  50. intmap-fold-right
  51. intmap-union
  52. intmap-intersect))
  53. ;; Persistent sparse intmaps.
  54. (define-syntax-rule (define-inline name val)
  55. (define-syntax name (identifier-syntax val)))
  56. ;; FIXME: This should make an actual atomic reference.
  57. (define-inlinable (make-atomic-reference value)
  58. (list value))
  59. (define-inlinable (get-atomic-reference reference)
  60. (car reference))
  61. (define-inlinable (set-atomic-reference! reference value)
  62. (set-car! reference value))
  63. (define-inline *branch-bits* 5)
  64. (define-inline *branch-size* (ash 1 *branch-bits*))
  65. (define-inline *branch-size-with-edit* (1+ *branch-size*))
  66. (define-inline *edit-index* *branch-size*)
  67. (define-inline *branch-mask* (1- *branch-size*))
  68. (define-record-type <intmap>
  69. (make-intmap min shift root)
  70. intmap?
  71. (min intmap-min)
  72. (shift intmap-shift)
  73. (root intmap-root))
  74. (define-record-type <transient-intmap>
  75. (make-transient-intmap min shift root edit)
  76. transient-intmap?
  77. (min transient-intmap-min set-transient-intmap-min!)
  78. (shift transient-intmap-shift set-transient-intmap-shift!)
  79. (root transient-intmap-root set-transient-intmap-root!)
  80. (edit transient-intmap-edit set-transient-intmap-edit!))
  81. (define *absent* (list 'absent))
  82. (define-inlinable (absent? x)
  83. (eq? x *absent*))
  84. (define-inlinable (present? x)
  85. (not (absent? x)))
  86. (define-inlinable (new-branch edit)
  87. (let ((vec (make-vector *branch-size-with-edit* *absent*)))
  88. (vector-set! vec *edit-index* edit)
  89. vec))
  90. (define-inlinable (clone-branch-with-edit branch edit)
  91. (let ((new (vector-copy branch)))
  92. (vector-set! new *edit-index* edit)
  93. new))
  94. (define (clone-branch-and-set branch i elt)
  95. (let ((new (clone-branch-with-edit branch #f)))
  96. (vector-set! new i elt)
  97. new))
  98. (define-inlinable (assert-readable! root-edit)
  99. (unless (eq? (get-atomic-reference root-edit) (current-thread))
  100. (error "Transient intmap owned by another thread" root-edit)))
  101. (define-inlinable (writable-branch branch root-edit)
  102. (let ((edit (vector-ref branch *edit-index*)))
  103. (if (eq? root-edit edit)
  104. branch
  105. (clone-branch-with-edit branch root-edit))))
  106. (define (branch-empty? branch)
  107. (let lp ((i 0))
  108. (or (= i *branch-size*)
  109. (and (absent? (vector-ref branch i))
  110. (lp (1+ i))))))
  111. (define-inlinable (round-down min shift)
  112. (logand min (lognot (1- (ash 1 shift)))))
  113. (define empty-intmap (make-intmap 0 0 *absent*))
  114. (define (add-level min shift root)
  115. (let* ((shift* (+ shift *branch-bits*))
  116. (min* (round-down min shift*))
  117. (idx (logand (ash (- min min*) (- shift))
  118. *branch-mask*))
  119. (root* (new-branch #f)))
  120. (vector-set! root* idx root)
  121. (make-intmap min* shift* root*)))
  122. (define (make-intmap/prune min shift root)
  123. (if (zero? shift)
  124. (make-intmap min shift root)
  125. (let lp ((i 0) (elt #f))
  126. (cond
  127. ((< i *branch-size*)
  128. (if (present? (vector-ref root i))
  129. (if elt
  130. (make-intmap min shift root)
  131. (lp (1+ i) i))
  132. (lp (1+ i) elt)))
  133. (elt
  134. (let ((shift (- shift *branch-bits*)))
  135. (make-intmap/prune (+ min (ash elt shift))
  136. shift
  137. (vector-ref root elt))))
  138. ;; Shouldn't be reached...
  139. (else empty-intmap)))))
  140. (define (meet-error old new)
  141. (error "Multiple differing values and no meet procedure defined" old new))
  142. (define* (transient-intmap #:optional (source empty-intmap))
  143. (match source
  144. (($ <transient-intmap> min shift root edit)
  145. (assert-readable! edit)
  146. source)
  147. (($ <intmap> min shift root)
  148. (let ((edit (make-atomic-reference (current-thread))))
  149. (make-transient-intmap min shift root edit)))))
  150. (define* (persistent-intmap #:optional (source empty-intmap))
  151. (match source
  152. (($ <transient-intmap> min shift root edit)
  153. (assert-readable! edit)
  154. ;; Make a fresh reference, causing any further operations on this
  155. ;; transient to clone its root afresh.
  156. (set-transient-intmap-edit! source
  157. (make-atomic-reference (current-thread)))
  158. ;; Clear the reference to the current thread, causing our edited
  159. ;; data structures to be persistent again.
  160. (set-atomic-reference! edit #f)
  161. (if min
  162. (make-intmap min shift root)
  163. empty-intmap))
  164. (($ <intmap>)
  165. source)))
  166. (define* (intmap-add! map i val #:optional (meet meet-error))
  167. (define (ensure-branch! root idx)
  168. (let ((edit (vector-ref root *edit-index*))
  169. (v (vector-ref root idx)))
  170. (if (absent? v)
  171. (let ((v (new-branch edit)))
  172. (vector-set! root idx v)
  173. v)
  174. (let ((v* (writable-branch v edit)))
  175. (unless (eq? v v*)
  176. (vector-set! root idx v*))
  177. v*))))
  178. (define (adjoin! i shift root)
  179. (let* ((shift (- shift *branch-bits*))
  180. (idx (logand (ash i (- shift)) *branch-mask*)))
  181. (if (zero? shift)
  182. (let ((node (vector-ref root idx)))
  183. (unless (eq? node val)
  184. (vector-set! root idx (if (present? node) (meet node val) val))))
  185. (adjoin! i shift (ensure-branch! root idx)))))
  186. (match map
  187. (($ <transient-intmap> min shift root edit)
  188. (assert-readable! edit)
  189. (cond
  190. ((< i 0)
  191. ;; The power-of-two spanning trick doesn't work across 0.
  192. (error "Intmaps can only map non-negative integers." i))
  193. ((absent? root)
  194. (set-transient-intmap-min! map i)
  195. (set-transient-intmap-shift! map 0)
  196. (set-transient-intmap-root! map val))
  197. ((and (<= min i) (< i (+ min (ash 1 shift))))
  198. ;; Add element to map; level will not change.
  199. (if (zero? shift)
  200. (unless (eq? root val)
  201. (set-transient-intmap-root! map (meet root val)))
  202. (let ((root* (writable-branch root edit)))
  203. (unless (eq? root root*)
  204. (set-transient-intmap-root! map root*))
  205. (adjoin! (- i min) shift root*))))
  206. (else
  207. (let lp ((min min)
  208. (shift shift)
  209. (root root))
  210. (let* ((shift* (+ shift *branch-bits*))
  211. (min* (round-down min shift*))
  212. (idx (logand (ash (- min min*) (- shift))
  213. *branch-mask*))
  214. (root* (new-branch edit)))
  215. (vector-set! root* idx root)
  216. (cond
  217. ((and (<= min* i) (< i (+ min* (ash 1 shift*))))
  218. (set-transient-intmap-min! map min*)
  219. (set-transient-intmap-shift! map shift*)
  220. (set-transient-intmap-root! map root*)
  221. (adjoin! (- i min*) shift* root*))
  222. (else
  223. (lp min* shift* root*)))))))
  224. map)
  225. (($ <intmap>)
  226. (intmap-add! (transient-intmap map) i val meet))))
  227. (define* (intmap-add map i val #:optional (meet meet-error))
  228. (define (adjoin i shift root)
  229. (if (zero? shift)
  230. (cond
  231. ((eq? root val) root)
  232. ((absent? root) val)
  233. (else (meet root val)))
  234. (let* ((shift (- shift *branch-bits*))
  235. (idx (logand (ash i (- shift)) *branch-mask*)))
  236. (if (absent? root)
  237. (let ((root* (new-branch #f))
  238. (node* (adjoin i shift root)))
  239. (vector-set! root* idx node*)
  240. root*)
  241. (let* ((node (vector-ref root idx))
  242. (node* (adjoin i shift node)))
  243. (if (eq? node node*)
  244. root
  245. (clone-branch-and-set root idx node*)))))))
  246. (match map
  247. (($ <intmap> min shift root)
  248. (cond
  249. ((< i 0)
  250. ;; The power-of-two spanning trick doesn't work across 0.
  251. (error "Intmaps can only map non-negative integers." i))
  252. ((absent? root)
  253. ;; Add first element.
  254. (make-intmap i 0 val))
  255. ((and (<= min i) (< i (+ min (ash 1 shift))))
  256. ;; Add element to map; level will not change.
  257. (let ((old-root root)
  258. (root (adjoin (- i min) shift root)))
  259. (if (eq? root old-root)
  260. map
  261. (make-intmap min shift root))))
  262. ((< i min)
  263. ;; Rebuild the tree by unioning two intmaps.
  264. (intmap-union (intmap-add empty-intmap i val error) map error))
  265. (else
  266. ;; Add a new level and try again.
  267. (intmap-add (add-level min shift root) i val error))))
  268. (($ <transient-intmap>)
  269. (intmap-add (persistent-intmap map) i val meet))))
  270. (define* (intmap-replace! map i val #:optional (meet (lambda (old new) new)))
  271. "Like intmap-add!, but requires that @var{i} was present in the map
  272. already, and always calls the meet procedure."
  273. (define (not-found)
  274. (error "not found" i))
  275. (define (ensure-branch! root idx)
  276. (let ((edit (vector-ref root *edit-index*))
  277. (v (vector-ref root idx)))
  278. (when (absent? v) (not-found))
  279. (let ((v* (writable-branch v edit)))
  280. (unless (eq? v v*)
  281. (vector-set! root idx v*))
  282. v*)))
  283. (define (adjoin! i shift root)
  284. (let* ((shift (- shift *branch-bits*))
  285. (idx (logand (ash i (- shift)) *branch-mask*)))
  286. (if (zero? shift)
  287. (let ((node (vector-ref root idx)))
  288. (when (absent? node) (not-found))
  289. (vector-set! root idx (meet node val)))
  290. (adjoin! i shift (ensure-branch! root idx)))))
  291. (match map
  292. (($ <transient-intmap> min shift root edit)
  293. (assert-readable! edit)
  294. (cond
  295. ((< i 0)
  296. ;; The power-of-two spanning trick doesn't work across 0.
  297. (error "Intmaps can only map non-negative integers." i))
  298. ((and (present? root) (<= min i) (< i (+ min (ash 1 shift))))
  299. (if (zero? shift)
  300. (set-transient-intmap-root! map (meet root val))
  301. (let ((root* (writable-branch root edit)))
  302. (unless (eq? root root*)
  303. (set-transient-intmap-root! map root*))
  304. (adjoin! (- i min) shift root*))))
  305. (else
  306. (not-found)))
  307. map)
  308. (($ <intmap>)
  309. (intmap-add! (transient-intmap map) i val meet))))
  310. (define* (intmap-replace map i val #:optional (meet (lambda (old new) new)))
  311. "Like intmap-add, but requires that @var{i} was present in the map
  312. already, and always calls the meet procedure."
  313. (define (not-found)
  314. (error "not found" i))
  315. (define (adjoin i shift root)
  316. (if (zero? shift)
  317. (if (absent? root)
  318. (not-found)
  319. (meet root val))
  320. (let* ((shift (- shift *branch-bits*))
  321. (idx (logand (ash i (- shift)) *branch-mask*)))
  322. (if (absent? root)
  323. (not-found)
  324. (let* ((node (vector-ref root idx))
  325. (node* (adjoin i shift node)))
  326. (if (eq? node node*)
  327. root
  328. (clone-branch-and-set root idx node*)))))))
  329. (match map
  330. (($ <intmap> min shift root)
  331. (cond
  332. ((< i 0)
  333. ;; The power-of-two spanning trick doesn't work across 0.
  334. (error "Intmaps can only map non-negative integers." i))
  335. ((and (present? root) (<= min i) (< i (+ min (ash 1 shift))))
  336. (let ((old-root root)
  337. (root (adjoin (- i min) shift root)))
  338. (if (eq? root old-root)
  339. map
  340. (make-intmap min shift root))))
  341. (else (not-found))))
  342. (($ <transient-intmap>)
  343. (intmap-replace (persistent-intmap map) i val meet))))
  344. (define (intmap-remove map i)
  345. (define (remove i shift root)
  346. (cond
  347. ((zero? shift) *absent*)
  348. (else
  349. (let* ((shift (- shift *branch-bits*))
  350. (idx (logand (ash i (- shift)) *branch-mask*))
  351. (node (vector-ref root idx)))
  352. (if (absent? node)
  353. root
  354. (let ((node* (remove i shift node)))
  355. (if (eq? node node*)
  356. root
  357. (clone-branch-and-set root idx node*))))))))
  358. (match map
  359. (($ <intmap> min shift root)
  360. (cond
  361. ((absent? root) map)
  362. ((and (<= min i) (< i (+ min (ash 1 shift))))
  363. ;; Add element to map; level will not change.
  364. (let ((root* (remove (- i min) shift root)))
  365. (if (eq? root root*)
  366. map
  367. (if (absent? root*)
  368. empty-intmap
  369. (make-intmap/prune min shift root*)))))
  370. (else map)))
  371. (($ <transient-intmap>)
  372. (intmap-remove (persistent-intmap map) i))))
  373. (define* (intmap-ref map i #:optional (not-found (lambda (i)
  374. (error "not found" i))))
  375. (define (absent) (not-found i))
  376. (define (ref min shift root)
  377. (if (zero? shift)
  378. (if (and min (= i min) (present? root))
  379. root
  380. (absent))
  381. (if (and (<= min i) (< i (+ min (ash 1 shift))))
  382. (let ((i (- i min)))
  383. (let lp ((node root) (shift shift))
  384. (if (present? node)
  385. (if (= shift *branch-bits*)
  386. (let ((node (vector-ref node (logand i *branch-mask*))))
  387. (if (present? node)
  388. node
  389. (absent)))
  390. (let* ((shift (- shift *branch-bits*))
  391. (idx (logand (ash i (- shift))
  392. *branch-mask*)))
  393. (lp (vector-ref node idx) shift)))
  394. (absent))))
  395. (absent))))
  396. (match map
  397. (($ <intmap> min shift root)
  398. (ref min shift root))
  399. (($ <transient-intmap> min shift root edit)
  400. (assert-readable! edit)
  401. (ref min shift root))))
  402. (define* (intmap-next map #:optional i)
  403. (define (visit-branch node shift i)
  404. (let lp ((i i) (idx (logand (ash i (- shift)) *branch-mask*)))
  405. (and (< idx *branch-size*)
  406. (or (visit-node (vector-ref node idx) shift i)
  407. (let ((inc (ash 1 shift)))
  408. (lp (+ (round-down i shift) inc) (1+ idx)))))))
  409. (define (visit-node node shift i)
  410. (and (present? node)
  411. (if (zero? shift)
  412. i
  413. (visit-branch node (- shift *branch-bits*) i))))
  414. (define (next min shift root)
  415. (let ((i (if (and i (< min i))
  416. (- i min)
  417. 0)))
  418. (and (< i (ash 1 shift))
  419. (let ((i (visit-node root shift i)))
  420. (and i (+ min i))))))
  421. (match map
  422. (($ <intmap> min shift root)
  423. (next min shift root))
  424. (($ <transient-intmap> min shift root edit)
  425. (assert-readable! edit)
  426. (next min shift root))))
  427. (define* (intmap-prev map #:optional i)
  428. (define (visit-branch node shift i)
  429. (let lp ((i i) (idx (logand (ash i (- shift)) *branch-mask*)))
  430. (and (<= 0 idx)
  431. (or (visit-node (vector-ref node idx) shift i)
  432. (lp (1- (round-down i shift)) (1- idx))))))
  433. (define (visit-node node shift i)
  434. (and (present? node)
  435. (if (zero? shift)
  436. i
  437. (visit-branch node (- shift *branch-bits*) i))))
  438. (define (prev min shift root)
  439. (let* ((i (if (and i (< i (+ min (ash 1 shift))))
  440. (- i min)
  441. (1- (ash 1 shift)))))
  442. (and (<= 0 i)
  443. (let ((i (visit-node root shift i)))
  444. (and i (+ min i))))))
  445. (match map
  446. (($ <intmap> min shift root)
  447. (prev min shift root))
  448. (($ <transient-intmap> min shift root edit)
  449. (assert-readable! edit)
  450. (prev min shift root))))
  451. (define-syntax-rule (make-intmap-folder forward? seed ...)
  452. (lambda (f map seed ...)
  453. (define (visit-branch node shift min seed ...)
  454. (let ((shift (- shift *branch-bits*)))
  455. (if (zero? shift)
  456. (let lp ((i (if forward? 0 (1- *branch-size*))) (seed seed) ...)
  457. (if (if forward? (< i *branch-size*) (<= 0 i))
  458. (let ((elt (vector-ref node i)))
  459. (call-with-values (lambda ()
  460. (if (present? elt)
  461. (f (+ i min) elt seed ...)
  462. (values seed ...)))
  463. (lambda (seed ...)
  464. (lp (if forward? (1+ i) (1- i)) seed ...))))
  465. (values seed ...)))
  466. (let lp ((i (if forward? 0 (1- *branch-size*))) (seed seed) ...)
  467. (if (if forward? (< i *branch-size*) (<= 0 i))
  468. (let ((elt (vector-ref node i)))
  469. (call-with-values
  470. (lambda ()
  471. (if (present? elt)
  472. (visit-branch elt shift (+ min (ash i shift))
  473. seed ...)
  474. (values seed ...)))
  475. (lambda (seed ...)
  476. (lp (if forward? (1+ i) (1- i)) seed ...))))
  477. (values seed ...))))))
  478. (let fold ((map map))
  479. (match map
  480. (($ <intmap> min shift root)
  481. (cond
  482. ((absent? root) (values seed ...))
  483. ((zero? shift) (f min root seed ...))
  484. (else (visit-branch root shift min seed ...))))
  485. (($ <transient-intmap>)
  486. (fold (persistent-intmap map)))))))
  487. (define intmap-fold
  488. (case-lambda
  489. ((f map)
  490. ((make-intmap-folder #t) f map))
  491. ((f map seed)
  492. ((make-intmap-folder #t seed) f map seed))
  493. ((f map seed0 seed1)
  494. ((make-intmap-folder #t seed0 seed1) f map seed0 seed1))
  495. ((f map seed0 seed1 seed2)
  496. ((make-intmap-folder #t seed0 seed1 seed2) f map seed0 seed1 seed2))))
  497. (define intmap-fold-right
  498. (case-lambda
  499. ((f map)
  500. ((make-intmap-folder #f) f map))
  501. ((f map seed)
  502. ((make-intmap-folder #f seed) f map seed))
  503. ((f map seed0 seed1)
  504. ((make-intmap-folder #f seed0 seed1) f map seed0 seed1))
  505. ((f map seed0 seed1 seed2)
  506. ((make-intmap-folder #f seed0 seed1 seed2) f map seed0 seed1 seed2))))
  507. (define* (intmap-union a b #:optional (meet meet-error))
  508. ;; Union A and B from index I; the result will be fresh.
  509. (define (union-branches/fresh shift a b i fresh)
  510. (let lp ((i 0))
  511. (cond
  512. ((< i *branch-size*)
  513. (let* ((a-child (vector-ref a i))
  514. (b-child (vector-ref b i)))
  515. (vector-set! fresh i (union shift a-child b-child))
  516. (lp (1+ i))))
  517. (else fresh))))
  518. ;; Union A and B from index I; the result may be eq? to A.
  519. (define (union-branches/a shift a b i)
  520. (let lp ((i i))
  521. (cond
  522. ((< i *branch-size*)
  523. (let* ((a-child (vector-ref a i))
  524. (b-child (vector-ref b i)))
  525. (if (eq? a-child b-child)
  526. (lp (1+ i))
  527. (let ((child (union shift a-child b-child)))
  528. (cond
  529. ((eq? a-child child)
  530. (lp (1+ i)))
  531. (else
  532. (let ((result (clone-branch-and-set a i child)))
  533. (union-branches/fresh shift a b (1+ i) result))))))))
  534. (else a))))
  535. ;; Union A and B; the may could be eq? to either.
  536. (define (union-branches shift a b)
  537. (let lp ((i 0))
  538. (cond
  539. ((< i *branch-size*)
  540. (let* ((a-child (vector-ref a i))
  541. (b-child (vector-ref b i)))
  542. (if (eq? a-child b-child)
  543. (lp (1+ i))
  544. (let ((child (union shift a-child b-child)))
  545. (cond
  546. ((eq? a-child child)
  547. (union-branches/a shift a b (1+ i)))
  548. ((eq? b-child child)
  549. (union-branches/a shift b a (1+ i)))
  550. (else
  551. (let ((result (clone-branch-and-set a i child)))
  552. (union-branches/fresh shift a b (1+ i) result))))))))
  553. ;; Seems they are the same but not eq?. Odd.
  554. (else a))))
  555. (define (union shift a-node b-node)
  556. (cond
  557. ((absent? a-node) b-node)
  558. ((absent? b-node) a-node)
  559. ((eq? a-node b-node) a-node)
  560. ((zero? shift) (meet a-node b-node))
  561. (else (union-branches (- shift *branch-bits*) a-node b-node))))
  562. (match (cons a b)
  563. ((($ <intmap> a-min a-shift a-root) . ($ <intmap> b-min b-shift b-root))
  564. (cond
  565. ((not (= b-shift a-shift))
  566. ;; Hoist the map with the lowest shift to meet the one with the
  567. ;; higher shift.
  568. (if (< b-shift a-shift)
  569. (intmap-union a (add-level b-min b-shift b-root) meet)
  570. (intmap-union (add-level a-min a-shift a-root) b meet)))
  571. ((not (= b-min a-min))
  572. ;; Nodes at the same shift but different minimums will cover
  573. ;; disjoint ranges (due to the round-down call on min). Hoist
  574. ;; both until they cover the same range.
  575. (intmap-union (add-level a-min a-shift a-root)
  576. (add-level b-min b-shift b-root)
  577. meet))
  578. (else
  579. ;; At this point, A and B cover the same range.
  580. (let ((root (union a-shift a-root b-root)))
  581. (cond
  582. ((eq? root a-root) a)
  583. ((eq? root b-root) b)
  584. (else (make-intmap a-min a-shift root)))))))))
  585. (define* (intmap-intersect a b #:optional (meet meet-error))
  586. ;; Intersect A and B from index I; the result will be fresh.
  587. (define (intersect-branches/fresh shift a b i fresh)
  588. (let lp ((i 0))
  589. (cond
  590. ((< i *branch-size*)
  591. (let* ((a-child (vector-ref a i))
  592. (b-child (vector-ref b i)))
  593. (vector-set! fresh i (intersect shift a-child b-child))
  594. (lp (1+ i))))
  595. ((branch-empty? fresh) *absent*)
  596. (else fresh))))
  597. ;; Intersect A and B from index I; the result may be eq? to A.
  598. (define (intersect-branches/a shift a b i)
  599. (let lp ((i i))
  600. (cond
  601. ((< i *branch-size*)
  602. (let* ((a-child (vector-ref a i))
  603. (b-child (vector-ref b i)))
  604. (if (eq? a-child b-child)
  605. (lp (1+ i))
  606. (let ((child (intersect shift a-child b-child)))
  607. (cond
  608. ((eq? a-child child)
  609. (lp (1+ i)))
  610. (else
  611. (let ((result (clone-branch-and-set a i child)))
  612. (intersect-branches/fresh shift a b (1+ i) result))))))))
  613. (else a))))
  614. ;; Intersect A and B; the may could be eq? to either.
  615. (define (intersect-branches shift a b)
  616. (let lp ((i 0))
  617. (cond
  618. ((< i *branch-size*)
  619. (let* ((a-child (vector-ref a i))
  620. (b-child (vector-ref b i)))
  621. (if (eq? a-child b-child)
  622. (lp (1+ i))
  623. (let ((child (intersect shift a-child b-child)))
  624. (cond
  625. ((eq? a-child child)
  626. (intersect-branches/a shift a b (1+ i)))
  627. ((eq? b-child child)
  628. (intersect-branches/a shift b a (1+ i)))
  629. (else
  630. (let ((result (clone-branch-and-set a i child)))
  631. (intersect-branches/fresh shift a b (1+ i) result))))))))
  632. ;; Seems they are the same but not eq?. Odd.
  633. (else a))))
  634. (define (intersect shift a-node b-node)
  635. (cond
  636. ((or (absent? a-node) (absent? b-node)) *absent*)
  637. ((eq? a-node b-node) a-node)
  638. ((zero? shift) (meet a-node b-node))
  639. (else (intersect-branches (- shift *branch-bits*) a-node b-node))))
  640. (define (different-mins lo-min lo-shift lo-root hi-min hi-shift hi lo-is-a?)
  641. (cond
  642. ((<= lo-shift hi-shift)
  643. ;; If LO has a lower shift and a lower min, it is disjoint. If
  644. ;; it has the same shift and a different min, it is also
  645. ;; disjoint.
  646. empty-intmap)
  647. (else
  648. (let* ((lo-shift (- lo-shift *branch-bits*))
  649. (lo-idx (ash (- hi-min lo-min) (- lo-shift))))
  650. (if (>= lo-idx *branch-size*)
  651. ;; HI has a lower shift, but it not within LO.
  652. empty-intmap
  653. (let ((lo-root (vector-ref lo-root lo-idx)))
  654. (if (absent? lo-root)
  655. empty-intmap
  656. (let ((lo (make-intmap (+ lo-min (ash lo-idx lo-shift))
  657. lo-shift
  658. lo-root)))
  659. (if lo-is-a?
  660. (intmap-intersect lo hi meet)
  661. (intmap-intersect hi lo meet))))))))))
  662. (define (different-shifts-same-min min hi-shift hi-root lo lo-is-a?)
  663. (let ((hi-root (vector-ref hi-root 0)))
  664. (if (absent? hi-root)
  665. empty-intmap
  666. (let ((hi (make-intmap min
  667. (- hi-shift *branch-bits*)
  668. hi-root)))
  669. (if lo-is-a?
  670. (intmap-intersect lo hi meet)
  671. (intmap-intersect hi lo meet))))))
  672. (match (cons a b)
  673. ((($ <intmap> a-min a-shift a-root) . ($ <intmap> b-min b-shift b-root))
  674. (cond
  675. ((< a-min b-min)
  676. (different-mins a-min a-shift a-root b-min b-shift b #t))
  677. ((< b-min a-min)
  678. (different-mins b-min b-shift b-root a-min a-shift a #f))
  679. ((< a-shift b-shift)
  680. (different-shifts-same-min b-min b-shift b-root a #t))
  681. ((< b-shift a-shift)
  682. (different-shifts-same-min a-min a-shift a-root b #f))
  683. (else
  684. ;; At this point, A and B cover the same range.
  685. (let ((root (intersect a-shift a-root b-root)))
  686. (cond
  687. ((absent? root) empty-intmap)
  688. ((eq? root a-root) a)
  689. ((eq? root b-root) b)
  690. (else (make-intmap/prune a-min a-shift root)))))))))
  691. (define (intmap->alist intmap)
  692. (reverse (intmap-fold acons intmap '())))
  693. (define (intmap-key-ranges intmap)
  694. (call-with-values
  695. (lambda ()
  696. (intmap-fold (lambda (k v start end closed)
  697. (cond
  698. ((not start) (values k k closed))
  699. ((= k (1+ end)) (values start k closed))
  700. (else (values k k (acons start end closed)))))
  701. intmap #f #f '()))
  702. (lambda (start end closed)
  703. (reverse (if start (acons start end closed) closed)))))
  704. (define (range-string ranges)
  705. (string-join (map (match-lambda
  706. ((start . start)
  707. (format #f "~a" start))
  708. ((start . end)
  709. (format #f "~a-~a" start end)))
  710. ranges)
  711. ","))
  712. (define (print-helper port tag intmap)
  713. (let ((ranges (intmap-key-ranges intmap)))
  714. (match ranges
  715. (()
  716. (format port "#<~a>" tag))
  717. (((0 . _) . _)
  718. (format port "#<~a ~a>" tag (range-string ranges)))
  719. (((min . end) . ranges)
  720. (let ((ranges (map (match-lambda
  721. ((start . end) (cons (- start min) (- end min))))
  722. (acons min end ranges))))
  723. (format port "#<~a ~a+~a>" tag min (range-string ranges)))))))
  724. (define (print-intmap intmap port)
  725. (print-helper port "intmap" intmap))
  726. (define (print-transient-intmap intmap port)
  727. (print-helper port "transient-intmap" intmap))
  728. (set-record-type-printer! <intmap> print-intmap)
  729. (set-record-type-printer! <transient-intmap> print-transient-intmap)