;;; -*- Mode: LISP; Syntax: Common-lisp; Package: XLIB; Base: 10; Lowercase: Yes -*-

;;; This file contains definitions for the BUFFER object for Common-Lisp X
;;; windows version 11

;;;
;;;			 TEXAS INSTRUMENTS INCORPORATED
;;;				  P.O. BOX 2909
;;;			       AUSTIN, TEXAS 78769
;;;
;;; Copyright (C) 1987 Texas Instruments Incorporated.
;;;
;;; Permission is granted to any individual or institution to use, copy, modify,
;;; and distribute this software, provided that this complete copyright and
;;; permission notice is maintained, intact, in all copies and supporting
;;; documentation.
;;;
;;; Texas Instruments Incorporated provides this software "as is" without
;;; express or implied warranty.
;;;

;; A few notes:
;;
;;  1. The BUFFER implements a two-way buffered byte / half-word
;;     / word stream.  Hooks are left for implementing this with a
;;     shared memory buffer, or with effenciency hooks to the network
;;     code.
;;
;;  2. The BUFFER object uses overlapping displaced arrays for
;;     inserting and removing bytes half-words and words.
;;
;;  3. The BYTE component of these arrays is written to a STREAM
;;     associated with the BUFFER.  The stream has its own buffer.
;;     This may be made more efficient by using the Zetalisp
;;     :Send-Output-Buffer operation.
;;
;;  4. The BUFFER object is INCLUDED in the DISPLAY object.
;;     This was done to reduce access time when sending requests,
;;     while maintaing some code modularity.
;;     Several buffer functions are duplicated (with-buffer,
;;     buffer-force-output, close-buffer) to keep the naming
;;     conventions consistent.
;;
;;  5. A nother layer of software is built on top of this for generating
;;     both client and server interface routines, given a specification
;;     of the protocol. (see the INTERFACE file)
;;
;;  6. Care is taken to leave the buffer pointer (buffer-bbuf) set to
;;     a point after a complete request.  This is to ensure that a partial
;;     request won't be left after aborts (e.g. control-abort on a lispm).

(in-package :xlib)

(defconstant +requestsize+ 160) ;; Max request size (excluding variable length requests)

;;; This is here instead of in bufmac so that with-display can be
;;; compiled without macros and bufmac being loaded.

(defmacro with-buffer ((buffer &key timeout inline)
		       &body body &environment env)
  ;; This macro is for use in a multi-process environment.  It provides
  ;; exclusive access to the local buffer object for request generation and
  ;; reply processing.
  `(macrolet ((with-buffer ((buffer &key timeout) &body body)
		;; Speedup hack for lexically nested with-buffers
		`(progn
		   (progn ,buffer ,@(and timeout `(,timeout)) nil)
		   ,@body)))
     ,(if (and (null inline) (macroexpand '(use-closures) env))
	  `(flet ((.with-buffer-body. () ,@body))
	     (declare (dynamic-extent #'.with-buffer-body.))
	     (with-buffer-function ,buffer ,timeout #'.with-buffer-body.))
	(let ((buf (if (or (symbolp buffer) (constantp buffer))
		       buffer
		     '.buffer.)))
	  `(let (,@(unless (eq buf buffer) `((,buf ,buffer))))
	     ,@(unless (eq buf buffer) `((declare (type buffer ,buf))))
	     ,(declare-bufmac)
	     (when (buffer-dead ,buf)
	       (x-error 'closed-display :display ,buf))
	     (holding-lock ((buffer-lock ,buf) ,buf "CLX Display Lock"
			    ,@(and timeout `(:timeout ,timeout)))
	       ,@body))))))

(defun with-buffer-function (buffer timeout function)
  (declare (type display buffer)
	   (type (or null number) timeout)
	   (type function function)
	   (dynamic-extent function))
  (with-buffer (buffer :timeout timeout :inline t)
    (funcall function)))

;;; The following are here instead of in bufmac so that event-case can
;;; be compiled without macros and bufmac being loaded.

(defmacro read-card8 (byte-index)
  `(aref-card8 buffer-bbuf (index+ buffer-boffset ,byte-index)))

(defmacro read-int8 (byte-index)
  `(aref-int8 buffer-bbuf (index+ buffer-boffset ,byte-index)))

(defmacro read-card16 (byte-index)
  `(aref-card16 buffer-bbuf (index+ buffer-boffset ,byte-index)))

(defmacro read-int16 (byte-index)
  `(aref-int16 buffer-bbuf (index+ buffer-boffset ,byte-index)))

(defmacro read-card32 (byte-index)
  `(aref-card32 buffer-bbuf (index+ buffer-boffset ,byte-index)))

(defmacro read-int32 (byte-index)
  `(aref-int32 buffer-bbuf (index+ buffer-boffset ,byte-index)))

(defmacro read-card29 (byte-index)
  `(aref-card29 buffer-bbuf (index+ buffer-boffset ,byte-index)))

(defmacro event-code (reply-buffer)
  ;; The reply-buffer structure is used for events.
  ;; The size slot is used for the event code.
  `(reply-size ,reply-buffer))

(defmacro reading-event ((event &rest options) &body body)
  (declare (arglist (buffer &key sizes) &body body))
  ;; BODY may contain calls to (READ32 &optional index) etc.
  ;; These calls will read from the input buffer at byte
  ;; offset INDEX.  If INDEX is not supplied, then the next
  ;; word, half-word or byte is returned.
  `(with-buffer-input (,event ,@options) ,@body))

(defmacro with-buffer-input ((reply-buffer &key display (sizes '(8 16 32)) index)
			     &body body)
  (unless (listp sizes) (setq sizes (list sizes)))
  ;; 160 is a special hack for client-message-events
  (when (set-difference sizes '(0 8 16 32 160 256))
    (error "Illegal sizes in ~a" sizes))
  `(let ((%reply-buffer ,reply-buffer)
	 ,@(and display `((%buffer ,display))))
     (declare (type reply-buffer %reply-buffer)
	      ,@(and display '((type display %buffer))))
     ,(declare-bufmac)
     ,@(and display '(%buffer))
     (let* ((buffer-boffset (the array-index ,(or index 0)))
	    (buffer-bbuf (reply-ibuf8 %reply-buffer)))
       (declare (type array-index buffer-boffset)
		(type buffer-bytes buffer-bbuf)
		(ignorable buffer-boffset buffer-bbuf))
       ,@body)))

(defun make-buffer (output-size constructor &rest options)
  (declare (dynamic-extent options))
  ;; Output-Size is the output-buffer size in bytes.
  (let ((byte-output (make-array output-size :element-type 'card8
				 :initial-element 0)))
    (apply constructor
	   :size output-size
	   :obuf8 byte-output
	   options)))

(defun make-reply-buffer (size)
  ;; Size is the buffer size in bytes
  (let ((byte-input (make-array size :element-type 'card8
				:initial-element 0)))
    (make-reply-buffer-internal
      :size size
      :ibuf8 byte-input)))

(defun buffer-ensure-size (buffer size)
  (declare (type buffer buffer)
	   (type array-index size))
  (when (index> size (buffer-size buffer))
    (with-buffer (buffer)
      (buffer-flush buffer)
      (let* ((new-buffer-size (index-ash 1 (integer-length (index1- size))))
	     (new-buffer (make-array new-buffer-size :element-type 'card8
				     :initial-element 0)))
	(setf (buffer-obuf8 buffer) new-buffer)))))

(defun buffer-pad-request (buffer pad)
  (declare (type buffer buffer)
	   (type array-index pad))
  (unless (index-zerop pad)
    (when (index> (index+ (buffer-boffset buffer) pad)
		  (buffer-size buffer))
      (buffer-flush buffer))
    (incf (buffer-boffset buffer) pad)
    (unless (index-zerop (index-mod (buffer-boffset buffer) 4))
      (buffer-flush buffer))))

(declaim (inline buffer-new-request-number))

(defun buffer-new-request-number (buffer)
  (declare (type buffer buffer))
  (setf (buffer-request-number buffer)
	(ldb (byte 16 0) (1+ (buffer-request-number buffer)))))

(defun with-buffer-request-function (display gc-force request-function)
  (declare (type display display)
	   (type (or null gcontext) gc-force))
  (declare (type function request-function)
	   (dynamic-extent request-function))
  (with-buffer (display :inline t)
    (multiple-value-prog1
      (progn
	(when gc-force (force-gcontext-changes-internal gc-force))
	(without-aborts (funcall request-function display)))
      (display-invoke-after-function display))))

(defun with-buffer-request-function-nolock (display gc-force request-function)
  (declare (type display display)
	   (type (or null gcontext) gc-force))
  (declare (type function request-function)
	   (dynamic-extent request-function))
  (multiple-value-prog1
    (progn
      (when gc-force (force-gcontext-changes-internal gc-force))
      (without-aborts (funcall request-function display)))
    (display-invoke-after-function display)))

(defstruct (pending-command (:copier nil) (:predicate nil))
  (sequence 0 :type card16)
  (reply-buffer nil :type (or null reply-buffer))
  (process nil)
  (next nil :type (or null pending-command)))

(defun with-buffer-request-and-reply-function
       (display multiple-reply request-function reply-function)
  (declare (type display display)
	   (type generalized-boolean multiple-reply))
  (declare (type function request-function reply-function)
	   (dynamic-extent request-function reply-function))
  (let ((pending-command nil)
	(reply-buffer nil))
    (declare (type (or null pending-command) pending-command)
	     (type (or null reply-buffer) reply-buffer))
    (unwind-protect
	(progn
	  (with-buffer (display :inline t)
	    (setq pending-command (start-pending-command display))
	    (without-aborts (funcall request-function display))
	    (buffer-force-output display)
	    (display-invoke-after-function display))
	  (cond (multiple-reply
		 (loop
		   (setq reply-buffer (read-reply display pending-command))
		   (when (funcall reply-function display reply-buffer) (return nil))
		   (deallocate-reply-buffer (shiftf reply-buffer nil))))
		(t
		 (setq reply-buffer (read-reply display pending-command))
		 (funcall reply-function display reply-buffer))))
      (when reply-buffer (deallocate-reply-buffer reply-buffer))
      (when pending-command (stop-pending-command display pending-command)))))

;;
;; Buffer stream operations
;;

(defun buffer-write (vector buffer start end)
  ;; Write out VECTOR from START to END into BUFFER
  ;; Internal function, MUST BE CALLED FROM WITHIN WITH-BUFFER
  (declare (type buffer buffer)
	   (type array-index start end))
  (when (buffer-dead buffer)
    (x-error 'closed-display :display buffer))
  (wrap-buf-output (buffer)
    (funcall (buffer-write-function buffer) vector buffer start end))
  nil)

(defun buffer-flush (buffer)
  ;; Write the buffer contents to the server stream - doesn't force-output the stream
  ;; Internal function, MUST BE CALLED FROM WITHIN WITH-BUFFER
  (declare (type buffer buffer))
  (unless (buffer-flush-inhibit buffer)
    (let ((boffset (buffer-boffset buffer)))
      (declare (type array-index boffset))
      (when (index-plusp boffset)
	(buffer-write (buffer-obuf8 buffer) buffer 0 boffset)
	(setf (buffer-boffset buffer) 0)
	(setf (buffer-last-request buffer) nil))))
  nil)

(defmacro with-buffer-flush-inhibited ((buffer) &body body)
  (let ((buf (if (or (symbolp buffer) (constantp buffer)) buffer '.buffer.)))
    `(let* (,@(and (not (eq buf buffer)) `((,buf ,buffer)))
	    (.saved-buffer-flush-inhibit. (buffer-flush-inhibit ,buf)))
       (unwind-protect
	   (progn
	     (setf (buffer-flush-inhibit ,buf) t)
	     ,@body)
	 (setf (buffer-flush-inhibit ,buf) .saved-buffer-flush-inhibit.)))))

(defun buffer-force-output (buffer)
  ;; Output is normally buffered, this forces any buffered output to the server.
  (declare (type buffer buffer))
  (when (buffer-dead buffer)
    (x-error 'closed-display :display buffer))
  (buffer-flush buffer)
  (wrap-buf-output (buffer)
    (without-aborts
      (funcall (buffer-force-output-function buffer) buffer)))
  nil)

(defun close-buffer (buffer &key abort)
  ;; Close the host connection in BUFFER
  (declare (type buffer buffer))
  (unless (null (buffer-output-stream buffer))
    (wrap-buf-output (buffer)
      (funcall (buffer-close-function buffer) buffer :abort abort))
    (setf (buffer-dead buffer) t)
    ;; Zap pointers to the streams, to ensure they're GC'd
    (setf (buffer-output-stream buffer) nil)
    (setf (buffer-input-stream buffer) nil)
    )
  nil)

(defun buffer-input  (buffer vector start end &optional timeout)
  ;; Read into VECTOR from the buffer stream
  ;; Timeout, when non-nil, is in seconds
  ;; Returns non-nil if EOF encountered
  ;; Returns :TIMEOUT when timeout exceeded
  (declare (type buffer buffer)
	   (type vector vector)
	   (type array-index start end)
	   (type (or null number) timeout))
  (declare (clx-values eof-p))
  (when (buffer-dead buffer)
    (x-error 'closed-display :display buffer))
  (unless (= start end)
    (let ((result
	    (wrap-buf-input (buffer)
	      (funcall (buffer-input-function buffer)
		       buffer vector start end timeout))))
      (unless (or (null result) (eq result :timeout))
	(close-buffer buffer))
      result)))

(defun buffer-input-wait  (buffer timeout)
  ;; Timeout, when non-nil, is in seconds
  ;; Returns non-nil if EOF encountered
  ;; Returns :TIMEOUT when timeout exceeded
  (declare (type buffer buffer)
	   (type (or null number) timeout))
  (declare (clx-values timeout))
  (when (buffer-dead buffer)
    (x-error 'closed-display :display buffer))
  (let ((result
	  (wrap-buf-input (buffer)
	    (funcall (buffer-input-wait-function buffer)
		     buffer timeout))))
    (unless (or (null result) (eq result :timeout))
      (close-buffer buffer))
    result))

(defun buffer-listen (buffer)
  ;; Returns T if there is input available for the buffer. This should never
  ;; block, so it can be called from the scheduler.
  (declare (type buffer buffer))
  (declare (clx-values input-available))
  (or (not (null (buffer-dead buffer)))
      (wrap-buf-input (buffer)
	(funcall (buffer-listen-function buffer) buffer))))

;;; Reading sequences of strings

;;; a list of pascal-strings with card8 lengths, no padding in between
;;; can't use read-sequence-char
(defun read-sequence-string (buffer-bbuf length nitems result-type
			     &optional (buffer-boffset 0))
  (declare (type buffer-bytes buffer-bbuf)
	   (type array-index length nitems buffer-boffset))
  length
  (with-vector (buffer-bbuf buffer-bytes)
    (let ((result (make-sequence result-type nitems)))
      (do* ((index 0 (index+ index 1 string-length))
	    (count 0 (index1+ count))
	    (string-length 0)
	    (string ""))
	   ((index>= count nitems)
	    result)
	(declare (type array-index index count string-length)
		 (type string string))
	(setq string-length (read-card8 index)
	      string (make-sequence 'string string-length))
	(do ((i (index1+ index) (index1+ i))
	     (j 0 (index1+ j)))
	    ((index>= j string-length)
	     (setf (elt result count) string))
	  (declare (type array-index i j))
	  (setf (aref string j) (card8->char (read-card8 i))))))))

;;; Reading sequences of chars

(defun read-sequence-char (reply-buffer result-type nitems &optional transform data
			   (start 0) (index 0))
  (declare (type reply-buffer reply-buffer)
	   (type t result-type) ;; CL type
	   (type array-index nitems start index)
	   (type (or null sequence) data))
  (declare (type (or null (function (character) t)) transform)
	   (dynamic-extent transform))
  (if transform
      (flet ((card8->char->transform (v)
	       (declare (type card8 v))
	       (funcall transform (card8->char v))))
	(declare (dynamic-extent #'card8->char->transform))
	(read-sequence-card8
	  reply-buffer result-type nitems #'card8->char->transform
	  data start index))
    (read-sequence-card8
      reply-buffer result-type nitems #'card8->char
      data start index)))

;;; Reading sequences of card8's

(defun read-list-card8 (reply-buffer nitems data start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type list data))
  (with-buffer-input (reply-buffer :sizes (8) :index index)
    (do* ((j nitems (index- j 1))
	  (lst (nthcdr start data)  (cdr lst))
	  (index 0 (index+ index 1)))
	 ((index-zerop j))
      (declare (type array-index j index)
	       (list lst))
      (setf (car lst) (read-card8 index)))))

(defun read-list-card8-with-transform (reply-buffer nitems data transform start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type list data))
  (declare (type (function (card8) t) transform)
	   (dynamic-extent transform))
  (with-buffer-input (reply-buffer :sizes (8) :index index)
    (do* ((j nitems (index- j 1))
	  (lst (nthcdr start data) (cdr lst))
	  (index 0 (index+ index 1)))
	 ((index-zerop j))
      (declare (type array-index j index)
	       (list lst))
      (setf (car lst) (funcall transform (read-card8 index))))))

(defun read-simple-array-card8 (reply-buffer nitems data start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type (simple-array card8 (*)) data))
  (with-vector (data (simple-array card8 (*)))
    (with-buffer-input (reply-buffer :sizes (8))
      (buffer-replace data buffer-bbuf start (index+ start nitems) index))))

(defun read-simple-array-card8-with-transform (reply-buffer nitems data transform start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type (simple-array card8 (*)) data))
  (declare (type (function (card8) card8) transform)
	   (dynamic-extent transform))
  (with-vector (data (simple-array card8 (*)))
    (with-buffer-input (reply-buffer :sizes (8) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 1)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (the card8 (funcall transform (read-card8 index))))))))

(defun read-vector-card8 (reply-buffer nitems data start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type vector data)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (with-vector (data vector)
    (with-buffer-input (reply-buffer :sizes (8) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 1)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (read-card8 index))))))

(defun read-vector-card8-with-transform (reply-buffer nitems data transform start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type vector data)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (declare (type (function (card8) t) transform)
	   (dynamic-extent transform))
  (with-vector (data vector)
    (with-buffer-input (reply-buffer :sizes (8) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 1)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (funcall transform (read-card8 index)))))))

(defun read-sequence-card8 (reply-buffer result-type nitems &optional transform data
			    (start 0) (index 0))
  (declare (type reply-buffer reply-buffer)
	   (type t result-type) ;; CL type
	   (type array-index nitems start index)
	   (type (or null sequence) data))
  (declare (type (or null (function (card8) t)) transform)
	   (dynamic-extent transform))
  (let ((result (or data (make-sequence result-type nitems))))
    (typecase result
      (list
	(if transform
	    (read-list-card8-with-transform
	      reply-buffer nitems result transform start index)
	  (read-list-card8 reply-buffer nitems result start index)))
      ((simple-array card8 (*))
       (if transform
	   (read-simple-array-card8-with-transform
	     reply-buffer nitems result transform start index)
	 (read-simple-array-card8 reply-buffer nitems result start index)))
      (t
	(if transform
	    (read-vector-card8-with-transform
	      reply-buffer nitems result transform start index)
	  (read-vector-card8 reply-buffer nitems result start index))))
    result))

;;; For now, perhaps performance it isn't worth doing better?

(defun read-sequence-int8 (reply-buffer result-type nitems &optional transform data
			   (start 0) (index 0))
  (declare (type reply-buffer reply-buffer)
	   (type t result-type) ;; CL type
	   (type array-index nitems start index)
	   (type (or null sequence) data))
  (declare (type (or null (function (int8) t)) transform)
	   (dynamic-extent transform))
  (if transform
      (flet ((card8->int8->transform (v)
	       (declare (type card8 v))
	       (funcall transform (card8->int8 v))))
	(declare (dynamic-extent #'card8->int8->transform))
	(read-sequence-card8
	  reply-buffer result-type nitems #'card8->int8->transform
	  data start index))
    (read-sequence-card8
      reply-buffer result-type nitems #'card8->int8
      data start index)))

;;; Reading sequences of card16's

(defun read-list-card16 (reply-buffer nitems data start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type list data))
  (with-buffer-input (reply-buffer :sizes (16) :index index)
    (do* ((j nitems (index- j 1))
	  (lst (nthcdr start data) (cdr lst))
	  (index 0 (index+ index 2)))
	 ((index-zerop j))
      (declare (type array-index j index)
	       (list lst))
      (setf (car lst) (read-card16 index)))))

(defun read-list-card16-with-transform (reply-buffer nitems data transform start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type list data))
  (declare (type (function (card16) t) transform)
	   (dynamic-extent transform))
  (with-buffer-input (reply-buffer :sizes (16) :index index)
    (do* ((j nitems (index- j 1))
	  (lst (nthcdr start data) (cdr lst))
	  (index 0 (index+ index 2)))
	 ((index-zerop j))
      (declare (type array-index j index)
	       (list lst))
      (setf (car lst) (funcall transform (read-card16 index))))))


(defun read-simple-array-card16 (reply-buffer nitems data start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type (simple-array card16 (*)) data))
  (with-vector (data (simple-array card16 (*)))
    (with-buffer-input (reply-buffer :sizes (16) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 2)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (the card16 (read-card16 index)))))))

(defun read-simple-array-card16-with-transform (reply-buffer nitems data transform start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type (simple-array card16 (*)) data))
  (declare (type (function (card16) card16) transform)
	   (dynamic-extent transform))
  (with-vector (data (simple-array card16 (*)))
    (with-buffer-input (reply-buffer :sizes (16) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 2)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (the card16 (funcall transform (read-card16 index))))))))

(defun read-vector-card16 (reply-buffer nitems data start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type vector data)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (with-vector (data vector)
    (with-buffer-input (reply-buffer :sizes (16) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 2)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (read-card16 index))))))

(defun read-vector-card16-with-transform (reply-buffer nitems data transform start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type vector data)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (declare (type (function (card16) t) transform)
	   (dynamic-extent transform))
  (with-vector (data vector)
    (with-buffer-input (reply-buffer :sizes (16) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 2)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (funcall transform (read-card16 index)))))))

(defun read-sequence-card16 (reply-buffer result-type nitems &optional transform data
			     (start 0) (index 0))
  (declare (type reply-buffer reply-buffer)
	   (type t result-type) ;; CL type
	   (type array-index nitems start index)
	   (type (or null sequence) data))
  (declare (type (or null (function (card16) t)) transform)
	   (dynamic-extent transform))
  (let ((result (or data (make-sequence result-type nitems))))
    (typecase result
      (list
	(if transform
	    (read-list-card16-with-transform reply-buffer nitems result transform start index)
	  (read-list-card16 reply-buffer nitems result start index)))
      ((simple-array card16 (*))
       (if transform
	   (read-simple-array-card16-with-transform
	     reply-buffer nitems result transform start index)
	 (read-simple-array-card16 reply-buffer nitems result start index)))
      (t
	(if transform
	    (read-vector-card16-with-transform
	      reply-buffer nitems result transform start index)
	  (read-vector-card16 reply-buffer nitems result start index))))
    result))

;;; For now, perhaps performance it isn't worth doing better?

(defun read-sequence-int16 (reply-buffer result-type nitems &optional transform data
			    (start 0) (index 0))
  (declare (type reply-buffer reply-buffer)
	   (type t result-type) ;; CL type
	   (type array-index nitems start index)
	   (type (or null sequence) data))
  (declare (type (or null (function (int16) t)) transform)
	   (dynamic-extent transform))
  (if transform
      (flet ((card16->int16->transform (v)
	       (declare (type card16 v))
	       (funcall transform (card16->int16 v))))
	(declare (dynamic-extent #'card16->int16->transform))
	(read-sequence-card16
	  reply-buffer result-type nitems #'card16->int16->transform
	  data start index))
    (read-sequence-card16
      reply-buffer result-type nitems #'card16->int16
      data start index)))

;;; Reading sequences of card32's

(defun read-list-card32 (reply-buffer nitems data start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type list data))
  (with-buffer-input (reply-buffer :sizes (32) :index index)
    (do* ((j nitems (index- j 1))
	  (lst (nthcdr start data) (cdr lst))
	  (index 0 (index+ index 4)))
	 ((index-zerop j))
      (declare (type array-index j index)
	       (list lst))
      (setf (car lst) (read-card32 index)))))

(defun read-list-card32-with-transform (reply-buffer nitems data transform start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type list data))
  (declare (type (function (card32) t) transform)
	   (dynamic-extent transform))
  (with-buffer-input (reply-buffer :sizes (32) :index index)
    (do* ((j nitems (index- j 1))
	  (lst (nthcdr start data) (cdr lst))
	  (index 0 (index+ index 4)))
	 ((index-zerop j))
      (declare (type array-index j index)
	       (list lst))
      (setf (car lst) (funcall transform (read-card32 index))))))

(defun read-simple-array-card32 (reply-buffer nitems data start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type (simple-array card32 (*)) data))
  (with-vector (data (simple-array card32 (*)))
    (with-buffer-input (reply-buffer :sizes (32) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 4)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (the card32 (read-card32 index)))))))

(defun read-simple-array-card32-with-transform (reply-buffer nitems data transform start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type (simple-array card32 (*)) data))
  (declare (type (function (card32) card32) transform)
	   (dynamic-extent transform))
  (with-vector (data (simple-array card32 (*)))
    (with-buffer-input (reply-buffer :sizes (32) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 4)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (the card32 (funcall transform (read-card32 index))))))))

(defun read-vector-card32 (reply-buffer nitems data start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type vector data)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (with-vector (data vector)
    (with-buffer-input (reply-buffer :sizes (32) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 4)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (read-card32 index))))))

(defun read-vector-card32-with-transform (reply-buffer nitems data transform start index)
  (declare (type reply-buffer reply-buffer)
	   (type array-index nitems start index)
	   (type vector data)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (declare (type (function (card32) t) transform)
	   (dynamic-extent transform))
  (with-vector (data vector)
    (with-buffer-input (reply-buffer :sizes (32) :index index)
      (do* ((j start (index+ j 1))
	    (end (index+ start nitems))
	    (index 0 (index+ index 4)))
	   ((index>= j end))
	(declare (type array-index j end index))
	(setf (aref data j) (funcall transform (read-card32 index)))))))

(defun read-sequence-card32 (reply-buffer result-type nitems &optional transform data
			     (start 0) (index 0))
  (declare (type reply-buffer reply-buffer)
	   (type t result-type) ;; CL type
	   (type array-index nitems start index)
	   (type (or null sequence) data))
  (declare (type (or null (function (card32) t)) transform)
	   (dynamic-extent transform))
  (let ((result (or data (make-sequence result-type nitems))))
    (typecase result
      (list
	(if transform
	    (read-list-card32-with-transform reply-buffer nitems result transform start index)
	  (read-list-card32 reply-buffer nitems result start index)))
      ((simple-array card32 (*))
       (if transform
	   (read-simple-array-card32-with-transform
	     reply-buffer nitems result transform start index)
	 (read-simple-array-card32 reply-buffer nitems result start index)))
      (t
	(if transform
	    (read-vector-card32-with-transform
	      reply-buffer nitems result transform start index)
	  (read-vector-card32 reply-buffer nitems result start index))))
    result))

;;; For now, perhaps performance it isn't worth doing better?

(defun read-sequence-int32 (reply-buffer result-type nitems &optional transform data
			    (start 0) (index 0))
  (declare (type reply-buffer reply-buffer)
	   (type t result-type) ;; CL type
	   (type array-index nitems start index)
	   (type (or null sequence) data))
  (declare (type (or null (function (int32) t)) transform)
	   (dynamic-extent transform))
  (if transform
      (flet ((card32->int32->transform (v)
	       (declare (type card32 v))
	       (funcall transform (card32->int32 v))))
	(declare (dynamic-extent #'card32->int32->transform))
	(read-sequence-card32
	  reply-buffer result-type nitems #'card32->int32->transform
	  data start index))
    (read-sequence-card32
      reply-buffer result-type nitems #'card32->int32
      data start index)))

;;; Writing sequences of chars

(defun write-sequence-char
       (buffer boffset data &optional (start 0) (end (length data)) transform)
  (declare (type buffer buffer)
	   (type sequence data)
	   (type array-index boffset start end))
  (declare (type (or null (function (t) character)) transform)
	   (dynamic-extent transform))
  (if transform
      (flet ((transform->char->card8 (x)
	       (char->card8 (the character (funcall transform x)))))
	(declare (dynamic-extent #'transform->char->card8))
	(write-sequence-card8
	  buffer boffset data start end #'transform->char->card8))
    (write-sequence-card8 buffer boffset data start end #'char->card8)))

;;; Writing sequences of card8's

(defun write-list-card8 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (writing-buffer-chunks card8
			 ((lst (nthcdr start data)))
			 ((type list lst))
    (dotimes (j chunk)
      (declare (type array-index j))
      (write-card8 j (pop lst))
      ))
  nil)

(defun write-list-card8-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (declare (type (function (t) card8) transform)
	   (dynamic-extent transform))
  (writing-buffer-chunks card8
			 ((lst (nthcdr start data)))
			 ((type list lst))
    (dotimes (j chunk)
      (declare (type array-index j))
      (write-card8 j (funcall transform (pop lst)))))
  nil)

;;; Should really write directly from data, instead of into the buffer first
(defun write-simple-array-card8 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type (simple-array card8 (*)) data)
	   (type array-index boffset start end))
  (with-vector (data (simple-array card8 (*)))
    (writing-buffer-chunks card8
			   ((index start (index+ index chunk)))
			   ((type array-index index))
      (buffer-replace buffer-bbuf data
		      buffer-boffset
		      (index+ buffer-boffset chunk)
		      index)))
  nil)

(defun write-simple-array-card8-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type (simple-array card8 (*)) data)
	   (type array-index boffset start end))
  (declare (type (function (card8) card8) transform)
	   (dynamic-extent transform))
  (with-vector (data (simple-array card8 (*)))
    (writing-buffer-chunks card8
			   ((index start))
			   ((type array-index index))
      (dotimes (j chunk)
	(declare (type array-index j))
	(write-card8 j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-vector-card8 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (with-vector (data vector)
    (writing-buffer-chunks card8
			   ((index start))
			   ((type array-index index))
      (dotimes (j chunk)
	(declare (type array-index j))
	(write-card8 j (aref data index))
	(setq index (index+ index 1)))))
  nil)

(defun write-vector-card8-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end))
  (declare (type (function (t) card8) transform)
	   (dynamic-extent transform))
  (with-vector (data vector)
    (writing-buffer-chunks card8
			   ((index start))
			   ((type array-index index))
      (dotimes (j chunk)
	(declare (type array-index j))
	(write-card8 j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-sequence-card8
       (buffer boffset data &optional (start 0) (end (length data)) transform)
  (declare (type buffer buffer)
	   (type sequence data)
	   (type array-index boffset start end))
  (declare (type (or null (function (t) card8)) transform)
	   (dynamic-extent transform))
  (typecase data
    (list
      (if transform
	  (write-list-card8-with-transform buffer boffset data start end transform)
	  (write-list-card8 buffer boffset data start end)))
    ((simple-array card8 (*))
     (if transform
	 (write-simple-array-card8-with-transform buffer boffset data start end transform)
	 (write-simple-array-card8 buffer boffset data start end)))
    (t
      (if transform
	  (write-vector-card8-with-transform buffer boffset data start end transform)
	  (write-vector-card8 buffer boffset data start end)))))

;;; For now, perhaps performance it isn't worth doing better?

(defun write-sequence-int8
       (buffer boffset data &optional (start 0) (end (length data)) transform)
  (declare (type buffer buffer)
	   (type sequence data)
	   (type array-index boffset start end))
  (declare (type (or null (function (t) int8)) transform)
	   (dynamic-extent transform))
  (if transform
      (flet ((transform->int8->card8 (x)
	       (int8->card8 (the int8 (funcall transform x)))))
	(declare (dynamic-extent #'transform->int8->card8))
	(write-sequence-card8
	  buffer boffset data start end #'transform->int8->card8))
      (write-sequence-card8 buffer boffset data start end #'int8->card8)))

;;; Writing sequences of card16's

(defun write-list-card16 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (writing-buffer-chunks card16
			 ((lst (nthcdr start data)))
			 ((type list lst))
    ;; Depends upon the chunks being an even multiple of card16's big
    (do ((j 0 (index+ j 2)))
	((index>= j chunk))
      (declare (type array-index j))
      (write-card16 j (pop lst))))
  nil)

(defun write-list-card16-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (declare (type (function (t) card16) transform)
	   (dynamic-extent transform))
  (writing-buffer-chunks card16
			 ((lst (nthcdr start data)))
			 ((type list lst))
    ;; Depends upon the chunks being an even multiple of card16's big
    (do ((j 0 (index+ j 2)))
	((index>= j chunk))
      (declare (type array-index j))
      (write-card16 j (funcall transform (pop lst)))))
  nil)

(defun write-simple-array-card16 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type (simple-array card16 (*)) data)
	   (type array-index boffset start end))
  (with-vector (data (simple-array card16 (*)))
    (writing-buffer-chunks card16
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of card16's big
      (do ((j 0 (index+ j 2)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-card16 j (aref data index))
	(setq index (index+ index 1)))
      ;; overlapping case
      (let ((length (floor chunk 2)))
	(buffer-replace buffer-wbuf data
			buffer-woffset
			(index+ buffer-woffset length)
			index)
	(setq index (index+ index length)))))
  nil)

(defun write-simple-array-card16-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type (simple-array card16 (*)) data)
	   (type array-index boffset start end))
  (declare (type (function (card16) card16) transform)
	   (dynamic-extent transform))
  (with-vector (data (simple-array card16 (*)))
    (writing-buffer-chunks card16
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of card16's big
      (do ((j 0 (index+ j 2)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-card16 j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-vector-card16 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (with-vector (data vector)
    (writing-buffer-chunks card16
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of card16's big
      (do ((j 0 (index+ j 2)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-card16 j (aref data index))
	(setq index (index+ index 1)))
      ;; overlapping case
      (let ((length (floor chunk 2)))
	(buffer-replace buffer-wbuf data
			buffer-woffset
			(index+ buffer-woffset length)
			index)
	(setq index (index+ index length)))))
  nil)

(defun write-vector-card16-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (declare (type (function (t) card16) transform)
	   (dynamic-extent transform))
  (with-vector (data vector)
    (writing-buffer-chunks card16
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of card16's big
      (do ((j 0 (index+ j 2)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-card16 j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-sequence-card16
       (buffer boffset data &optional (start 0) (end (length data)) transform)
  (declare (type buffer buffer)
	   (type sequence data)
	   (type array-index boffset start end))
  (declare (type (or null (function (t) card16)) transform)
	   (dynamic-extent transform))
  (typecase data
    (list
      (if transform
	  (write-list-card16-with-transform buffer boffset data start end transform)
	  (write-list-card16 buffer boffset data start end)))
    ((simple-array card16 (*))
     (if transform
	 (write-simple-array-card16-with-transform buffer boffset data start end transform)
	 (write-simple-array-card16 buffer boffset data start end)))
    (t
      (if transform
	  (write-vector-card16-with-transform buffer boffset data start end transform)
	  (write-vector-card16 buffer boffset data start end)))))

;;; Writing sequences of int16's

(defun write-list-int16 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (writing-buffer-chunks int16
			 ((lst (nthcdr start data)))
			 ((type list lst))
    ;; Depends upon the chunks being an even multiple of int16's big
    (do ((j 0 (index+ j 2)))
	((index>= j chunk))
      (declare (type array-index j))
      (write-int16 j (pop lst))))
  nil)

(defun write-list-int16-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (declare (type (function (t) int16) transform)
	   (dynamic-extent transform))
  (writing-buffer-chunks int16
			 ((lst (nthcdr start data)))
			 ((type list lst))
    ;; Depends upon the chunks being an even multiple of int16's big
    (do ((j 0 (index+ j 2)))
	((index>= j chunk))
      (declare (type array-index j))
      (write-int16 j (funcall transform (pop lst)))))
  nil)

(defun write-simple-array-int16 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type (simple-array int16 (*)) data)
	   (type array-index boffset start end))
  (with-vector (data (simple-array int16 (*)))
    (writing-buffer-chunks int16
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of int16's big
      (do ((j 0 (index+ j 2)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-int16 j (aref data index))
	(setq index (index+ index 1)))
      ;; overlapping case
      (let ((length (floor chunk 2)))
	(buffer-replace buffer-wbuf data
			buffer-woffset
			(index+ buffer-woffset length)
			index)
	(setq index (index+ index length)))))
  nil)

(defun write-simple-array-int16-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type (simple-array int16 (*)) data)
	   (type array-index boffset start end))
  (declare (type (function (int16) int16) transform)
	   (dynamic-extent transform))
  (with-vector (data (simple-array int16 (*)))
    (writing-buffer-chunks int16
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of int16's big
      (do ((j 0 (index+ j 2)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-int16 j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-vector-int16 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (with-vector (data vector)
    (writing-buffer-chunks int16
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of int16's big
      (do ((j 0 (index+ j 2)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-int16 j (aref data index))
	(setq index (index+ index 1)))
      ;; overlapping case
      (let ((length (floor chunk 2)))
	(buffer-replace buffer-wbuf data
			buffer-woffset
			(index+ buffer-woffset length)
			index)
	(setq index (index+ index length)))))
  nil)

(defun write-vector-int16-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (declare (type (function (t) int16) transform)
	   (dynamic-extent transform))
  (with-vector (data vector)
    (writing-buffer-chunks int16
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of int16's big
      (do ((j 0 (index+ j 2)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-int16 j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-sequence-int16
       (buffer boffset data &optional (start 0) (end (length data)) transform)
  (declare (type buffer buffer)
	   (type sequence data)
	   (type array-index boffset start end))
  (declare (type (or null (function (t) int16)) transform)
	   (dynamic-extent transform))
  (typecase data
    (list
      (if transform
	  (write-list-int16-with-transform buffer boffset data start end transform)
	  (write-list-int16 buffer boffset data start end)))
    ((simple-array int16 (*))
     (if transform
	 (write-simple-array-int16-with-transform buffer boffset data start end transform)
	 (write-simple-array-int16 buffer boffset data start end)))
    (t
      (if transform
	  (write-vector-int16-with-transform buffer boffset data start end transform)
	  (write-vector-int16 buffer boffset data start end)))))

;;; Writing sequences of card32's

(defun write-list-card32 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (writing-buffer-chunks card32
			 ((lst (nthcdr start data)))
			 ((type list lst))
    ;; Depends upon the chunks being an even multiple of card32's big
    (do ((j 0 (index+ j 4)))
	((index>= j chunk))
      (declare (type array-index j))
      (write-card32 j (pop lst))))
  nil)

(defun write-list-card32-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (declare (type (function (t) card32) transform)
	   (dynamic-extent transform))
  (writing-buffer-chunks card32
			 ((lst (nthcdr start data)))
			 ((type list lst))
    ;; Depends upon the chunks being an even multiple of card32's big
    (do ((j 0 (index+ j 4)))
	((index>= j chunk))
      (declare (type array-index j))
      (write-card32 j (funcall transform (pop lst)))))
  nil)

(defun write-simple-array-card32 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type (simple-array card32 (*)) data)
	   (type array-index boffset start end))
  (with-vector (data (simple-array card32 (*)))
    (writing-buffer-chunks card32
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of card32's big
      (do ((j 0 (index+ j 4)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-card32 j (aref data index))
	(setq index (index+ index 1)))
      ;; overlapping case
      (let ((length (floor chunk 4)))
	(buffer-replace buffer-lbuf data
			buffer-loffset
			(index+ buffer-loffset length)
			index)
	(setq index (index+ index length)))))
  nil)

(defun write-simple-array-card32-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type (simple-array card32 (*)) data)
	   (type array-index boffset start end))
  (declare (type (function (card32) card32) transform)
	   (dynamic-extent transform))
  (with-vector (data (simple-array card32 (*)))
    (writing-buffer-chunks card32
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of card32's big
      (do ((j 0 (index+ j 4)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-card32 j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-vector-card32 (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (with-vector (data vector)
    (writing-buffer-chunks card32
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of card32's big
      (do ((j 0 (index+ j 4)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-card32 j (aref data index))
	(setq index (index+ index 1)))
      ;; overlapping case
      (let ((length (floor chunk 4)))
	(buffer-replace buffer-lbuf data
			buffer-loffset
			(index+ buffer-loffset length)
			index)
	(setq index (index+ index length)))))
  nil)

(defun write-vector-card32-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (declare (type (function (t) card32) transform)
	   (dynamic-extent transform))
  (with-vector (data vector)
    (writing-buffer-chunks card32
			   ((index start))
			   ((type array-index index))
      ;; Depends upon the chunks being an even multiple of card32's big
      (do ((j 0 (index+ j 4)))
	  ((index>= j chunk))
	(declare (type array-index j))
	(write-card32 j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-sequence-card32
       (buffer boffset data &optional (start 0) (end (length data)) transform)
  (declare (type buffer buffer)
	   (type sequence data)
	   (type array-index boffset start end))
  (declare (type (or null (function (t) card32)) transform)
	   (dynamic-extent transform))
  (typecase data
    (list
      (if transform
	  (write-list-card32-with-transform buffer boffset data start end transform)
	  (write-list-card32 buffer boffset data start end)))
    ((simple-array card32 (*))
     (if transform
	 (write-simple-array-card32-with-transform buffer boffset data start end transform)
	 (write-simple-array-card32 buffer boffset data start end)))
    (t
      (if transform
	  (write-vector-card32-with-transform buffer boffset data start end transform)
	  (write-vector-card32 buffer boffset data start end)))))

;;; For now, perhaps performance it isn't worth doing better?

(defun write-sequence-int32
       (buffer boffset data &optional (start 0) (end (length data)) transform)
  (declare (type buffer buffer)
	   (type sequence data)
	   (type array-index boffset start end))
  (declare (type (or null (function (t) int32)) transform)
	   (dynamic-extent transform))
  (if transform
      (flet ((transform->int32->card32 (x)
	       (int32->card32 (the int32 (funcall transform x)))))
	(declare (dynamic-extent #'transform->int32->card32))
	(write-sequence-card32
	  buffer boffset data start end #'transform->int32->card32))
    (write-sequence-card32 buffer boffset data start end #'int32->card32)))

(defun read-bitvector256 (buffer-bbuf boffset data)
  (declare (type buffer-bytes buffer-bbuf)
	   (type array-index boffset)
	   (type (or null (simple-bit-vector 256)) data))
  (let ((result (or data (make-array 256 :element-type 'bit :initial-element 0))))
    (declare (type (simple-bit-vector 256) result))
    (do ((i (index+ boffset 1) (index+ i 1)) ;; Skip first byte
	 (j 8 (index+ j 8)))
	((index>= j 256))
      (declare (type array-index i j))
      (do ((byte (aref-card8 buffer-bbuf i) (index-ash byte -1))
	   (k j (index+ k 1)))
	  ((zerop byte)
	   (when data ;; Clear uninitialized bits in data
	     (do ((end (index+ j 8)))
		 ((index= k end))
	       (declare (type array-index end))
	       (setf (aref result k) 0)
	       (index-incf k))))
	(declare (type array-index k)
		 (type card8 byte))
	(setf (aref result k) (the bit (logand byte 1)))))
    result))

(defun write-bitvector256 (buffer boffset map)
  (declare (type buffer buffer)
	   (type array-index boffset)
	   (type (simple-array bit (*)) map))
  (with-buffer-output (buffer :index boffset :sizes 8)
    (do* ((i (index+ buffer-boffset 1) (index+ i 1))	; Skip first byte
	  (j 8 (index+ j 8)))
	 ((index>= j 256))
      (declare (type array-index i j))
      (do ((byte 0)
	   (bit (index+ j 7) (index- bit 1)))
	  ((index< bit j)
	   (aset-card8 byte buffer-bbuf i))
	(declare (type array-index bit)
		 (type card8 byte))
	(setq byte (the card8 (logior (the card8 (ash byte 1)) (aref map bit))))))))

;;; Writing sequences of char2b's

(defun write-list-char2b (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (writing-buffer-chunks card16
			 ((lst (nthcdr start data)))
			 ((type list lst))
    (do ((j 0 (index+ j 2)))
	((index>= j (1- chunk)) (setf chunk j))
      (declare (type array-index j))
      (write-char2b j (pop lst))))
  nil)

(defun write-list-char2b-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type list data)
	   (type array-index boffset start end))
  (declare (type (function (t) card16) transform)
	   (dynamic-extent transform))
  (writing-buffer-chunks card16
			 ((lst (nthcdr start data)))
			 ((type list lst))
    (do ((j 0 (index+ j 2)))
	((index>= j (1- chunk)) (setf chunk j))
      (declare (type array-index j))
      (write-char2b j (funcall transform (pop lst)))))
  nil)

(defun write-simple-array-char2b (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type (simple-array card16 (*)) data)
	   (type array-index boffset start end))
  (with-vector (data (simple-array card16 (*)))
    (writing-buffer-chunks card16
			   ((index start))
			   ((type array-index index))
      (do ((j 0 (index+ j 2)))
	  ((index>= j (1- chunk)) (setf chunk j))
	(declare (type array-index j))
	(write-char2b j (aref data index))
	(setq index (index+ index 1)))))
  nil)

(defun write-simple-array-char2b-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type (simple-array card16 (*)) data)
	   (type array-index boffset start end))
  (declare (type (function (card16) card16) transform)
	   (dynamic-extent transform))
  (with-vector (data (simple-array card16 (*)))
    (writing-buffer-chunks card16
			   ((index start))
			   ((type array-index index))
      (do ((j 0 (index+ j 2)))
	  ((index>= j (1- chunk)) (setf chunk j))
	(declare (type array-index j))
	(write-char2b j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-vector-char2b (buffer boffset data start end)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (with-vector (data vector)
    (writing-buffer-chunks card16
			   ((index start))
			   ((type array-index index))
      (do ((j 0 (index+ j 2)))
	  ((index>= j (1- chunk)) (setf chunk j))
	(declare (type array-index j))
	(write-char2b j (aref data index))
	(setq index (index+ index 1)))))
  nil)

(defun write-vector-char2b-with-transform (buffer boffset data start end transform)
  (declare (type buffer buffer)
	   (type vector data)
	   (type array-index boffset start end)
	   (optimize #+cmu(ext:inhibit-warnings 3)))
  (declare (type (function (t) card16) transform)
	   (dynamic-extent transform))
  (with-vector (data vector)
    (writing-buffer-chunks card16
			   ((index start))
			   ((type array-index index))
      (do ((j 0 (index+ j 2)))
	  ((index>= j (1- chunk)) (setf chunk j))
	(declare (type array-index j))
	(write-char2b j (funcall transform (aref data index)))
	(setq index (index+ index 1)))))
  nil)

(defun write-sequence-char2b
       (buffer boffset data &optional (start 0) (end (length data)) transform)
  (declare (type buffer buffer)
	   (type sequence data)
	   (type array-index boffset start end))
  (declare (type (or null (function (t) card16)) transform)
	   (dynamic-extent transform))
  (typecase data
    (list
      (if transform
	  (write-list-char2b-with-transform buffer boffset data start end transform)
	  (write-list-char2b buffer boffset data start end)))
    ((simple-array card16 (*))
     (if transform
	 (write-simple-array-char2b-with-transform buffer boffset data start end transform)
	 (write-simple-array-char2b buffer boffset data start end)))
    (t
      (if transform
	  (write-vector-char2b-with-transform buffer boffset data start end transform)
	  (write-vector-char2b buffer boffset data start end)))))

