
(define (make-d-vector type len key)
  (make-stob type (cells->bytes len) key))

(define make-b-vector make-stob)

(define (address-after-header stob)
  (assert (stob? stob))
  (stob-descriptor->address stob))

(define (address-at-header stob)
  (addr- (address-after-header stob) (cells->a-units 1)))

(define (stob-length-in-bytes stob)
  (header-length-in-bytes (stob-header stob)))

(define (address-after-stob stob)
  (addr+ (address-after-header stob)
         (bytes->a-units (stob-length-in-bytes stob))))

; Accessing memory via stob descriptors

(define (stob-ref stob index)
  (fetch (addr+ (address-after-header stob) (cells->a-units index))))

(define (stob-set! stob index value)
  (store! (addr+ (address-after-header stob) (cells->a-units index))
          value))

(define (stob-header stob)
  (stob-ref stob -1))

(define (stob-header-set! stob header)
  (stob-set! stob -1 header))

(define (stob-type obj)
  (header-type (stob-header obj)))

(define (stob-of-type? obj type)
  (and (stob? obj)
       (= (stob-type obj) type)))

; Immutability

(define (immutable? thing)
  (or (not (stob? thing))
      (immutable-header? (stob-header thing))))

(define (make-immutable! thing)
  (if (not (immutable? thing))
      (stob-header-set! thing (make-header-immutable (stob-header thing)))))

; D-vectors (vectors of descriptors)

(define (d-vector? obj)
  (and (stob? obj)
       (< (header-type (stob-header obj)) least-b-vector-type)))

; The type in these routines is used only for internal error checking.

(define (d-vector-length x)
  (assert (d-vector? x))
  (header-length-in-cells (stob-header x)))

(define (d-vector-ref x index)
  (assert (valid-index? index (d-vector-length x)))
  (stob-ref x index))

(define (d-vector-set! x index val)
  (assert (valid-index? index (d-vector-length x)))
  (stob-set! x index val))

; B-vector = vector of bytes.

(define (b-vector? obj)
  (and (stob? obj)
       (>= (header-type (stob-header obj))
	   least-b-vector-type)))

(define (b-vector-length x)
  (assert (b-vector? x))
  (header-length-in-bytes (stob-header x)))

(define (b-vector-ref b-vector index)
  (assert (valid-index? index (b-vector-length b-vector)))
  (fetch-byte (addr+ (address-after-header b-vector) index)))

(define (b-vector-set! b-vector index value)
  (assert (valid-index? index (b-vector-length b-vector)))
  (store-byte! (addr+ (address-after-header b-vector) index) value))

; Various utilities

(define (copy-stob old-stob key)
  (assert (stob? old-stob))
  (let ((new (make-stob (enum stob code-vector)
			(header-length-in-bytes (stob-header old-stob))
			key)))
    (stob-header-set! new (stob-header old-stob))
    (copy-cells! (address-after-header old-stob)
		 (address-after-header new)
		 (bytes->cells (stob-length-in-bytes old-stob)))
    new))

(define (copy-cells! from to count)
  (let ((end (addr+ from (cells->a-units count))))
    (do ((from from (addr1+ from))
         (to to (addr1+ to)))
        ((>= from end))
      (store! to (fetch from)))))

(define (stob-equal? stob1 stob2)    ;CMPC3 loop or "strncmp"
  (let ((z1 (stob-header stob1))
        (z2 (stob-header stob2)))
    (and (= (make-header-immutable z1)
	    (make-header-immutable z2))
         (let ((z (header-length-in-cells z1)))
           (let loop ((i 0))
             (cond ((>= i z) #t)
                   ((= (stob-ref stob1 i)
                        (stob-ref stob2 i))
                    (loop (+ i 1)))
                   (else #f)))))))

(define (valid-index? index len)
  (and (>= index 0) (< index len)))


