12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- (define-module (ice-9 copy-tree)
- #:use-module (ice-9 match)
- #:use-module (srfi srfi-11)
- #:replace (copy-tree))
- (define (make-race obj)
- (define (make-race advance-tortoise? tortoise-path hare-tail)
- (define (advance! hare)
- (let ((tail (list hare)))
- (set-cdr! hare-tail tail)
- (set! hare-tail tail))
- (when (eq? hare (car tortoise-path))
- (scm-error 'wrong-type-arg "copy-tree"
- "Expected non-circular data structure: ~S" (list hare) #f))
- (when advance-tortoise?
- (set! tortoise-path (cdr tortoise-path)))
- (set! advance-tortoise? (not advance-tortoise?)))
- (define (split!)
- (make-race advance-tortoise? tortoise-path hare-tail))
- (values advance! split!))
- (let ((path (cons obj '())))
- (make-race #f path path)))
- (define (copy-tree obj)
- "Recursively copy the data tree that is bound to @var{obj}, and return a\n"
- "the new data structure. @code{copy-tree} recurses down the\n"
- "contents of both pairs and vectors (since both cons cells and vector\n"
- "cells may point to arbitrary objects), and stops recursing when it hits\n"
- "any other object."
- (define (trace? x) (or (pair? x) (vector? x)))
- (define (visit obj advance! split!)
- (define (visit-head obj)
- (if (trace? obj)
- (let-values (((advance! split!) (split!)))
- (advance! obj)
- (visit obj advance! split!))
- obj))
- (define (visit-tail obj)
- (when (trace? obj) (advance! obj))
- (visit obj advance! split!))
- (cond
- ((pair? obj)
- (let* ((head (visit-head (car obj)))
- (tail (visit-tail (cdr obj))))
- (cons head tail)))
- ((vector? obj)
- (let* ((len (vector-length obj))
- (v (make-vector len)))
- (let lp ((i 0))
- (when (< i len)
- (vector-set! v i (visit-head (vector-ref obj i)))
- (lp (1+ i))))
- v))
- (else
- obj)))
- (let-values (((advance! split!) (make-race obj)))
- (visit obj advance! split!)))
|