From 4c5a685e1e2d020f598ad8d3f8f9ca4f9e221e98 Mon Sep 17 00:00:00 2001
From: treep <zena.treep@gmail.com>
Date: Thu, 16 Sep 2010 16:33:52 +0400
Subject: [PATCH] IO for vectors.

---
 io.lisp      |  110 +++++++++++++++++++++++++++++++++++++++++++++++++---------
 package.lisp |   18 +++++++++
 2 files changed, 111 insertions(+), 17 deletions(-)

diff --git a/io.lisp b/io.lisp
index 5df1619..f4db59e 100644
--- a/io.lisp
+++ b/io.lisp
@@ -3,6 +3,8 @@
 
 (in-package :alexandria)
 
+;;;; basic IO macros
+
 (defmacro with-open-file* ((stream filespec &key direction element-type
                                    if-exists if-does-not-exist external-format)
                            &body body)
@@ -40,7 +42,7 @@ which is only sent to WITH-OPEN-FILE when it's not NIL."
 (defmacro with-output-to-file ((stream-name file-name &rest args
                                             &key (direction nil direction-p)
                                             &allow-other-keys)
-			       &body body)
+                               &body body)
   "Evaluate BODY with STREAM-NAME to an output stream on the file
 FILE-NAME. ARGS is sent as is to the call to OPEN except EXTERNAL-FORMAT,
 which is only sent to WITH-OPEN-FILE when it's not NIL."
@@ -50,6 +52,8 @@ which is only sent to WITH-OPEN-FILE when it's not NIL."
   `(with-open-file* (,stream-name ,file-name :direction :output ,@args)
      ,@body))
 
+;;;; read and write strings from/to files
+
 (defun read-file-into-string (pathname &key (buffer-size 4096) external-format)
   "Return the contents of the file denoted by PATHNAME as a fresh string.
 
@@ -60,10 +64,10 @@ unless it's NIL, which means the system default."
     (let ((*print-pretty* nil))
       (with-output-to-string (datum)
         (let ((buffer (make-array buffer-size :element-type 'character)))
-	  (loop
-	     :for bytes-read = (read-sequence buffer file-stream)
-	     :do (write-sequence buffer datum :start 0 :end bytes-read)
-	     :while (= bytes-read buffer-size)))))))
+          (loop
+             :for bytes-read = (read-sequence buffer file-stream)
+             :do (write-sequence buffer datum :start 0 :end bytes-read)
+             :while (= bytes-read buffer-size)))))))
 
 (defun write-string-into-file (string pathname &key (if-exists :error)
                                                     if-does-not-exist
@@ -77,29 +81,101 @@ unless it's NIL, which means the system default."
                                     :external-format external-format)
     (write-sequence string file-stream)))
 
-(defun read-file-into-byte-vector (pathname)
-  "Read PATHNAME into a freshly allocated (unsigned-byte 8) vector."
-  (with-input-from-file (stream pathname :element-type '(unsigned-byte 8))
+;;;; read files into vectors
+
+(declaim (inline %read-file-into-vector))
+(defun %read-file-into-vector (pathname &key (element-type '(unsigned-byte 8)))
+  "Read PATHNAME into a freshly allocated vector. Element types deined in
+ELEMENT-TYPE. Inlined function."
+  (with-input-from-file (stream pathname :element-type element-type)
     (let ((length (file-length stream)))
       (assert length)
-      (let ((result (make-array length :element-type '(unsigned-byte 8))))
+      (let ((result (make-array length :element-type element-type)))
         (read-sequence result stream)
         result))))
 
-(defun write-byte-vector-into-file (bytes pathname &key (if-exists :error)
-                                                       if-does-not-exist)
-  "Write BYTES to PATHNAME."
-  (check-type bytes (vector (unsigned-byte 8)))
+(defun read-file-into-vector (pathname &key (element-type '(unsigned-byte 8)))
+  "Read PATHNAME into a freshly allocated vector. Element types deined in
+ELEMENT-TYPE."
+  (%read-file-into-vector pathname :element-type element-type))
+
+(macrolet
+    ((define (name bits &optional signed)
+       `(defun ,name (pathname)
+          ,(format nil "Read PATHNAME into a freshly allocated ~A, ~A bits vector."
+                   (if signed "signed" "unsigned")
+                   bits)
+          (%read-file-into-vector pathname 
+                                  :element-type '(,(if signed
+                                                       'signed-byte
+                                                       'unsigned-byte)
+                                                  ,bits)))))
+  (define read-file-into-byte-vector 8)
+  (define read-file-into-u8-vector   8)
+  (define read-file-into-s8-vector   8 t)
+  (define read-file-into-u16-vector  16)
+  (define read-file-into-s16-vector  16 t)
+  (define read-file-into-u32-vector  32)
+  (define read-file-into-s32-vector  32 t)
+  (define read-file-into-u64-vector  64)
+  (define read-file-into-s64-vector  64 t))
+
+;;;; write vectors into files
+
+(declaim (inline %write-vector-into-file))
+(defun %write-vector-into-file (vector pathname &key (if-exists :error)
+                                                     if-does-not-exist
+                                                     (element-type '(unsigned-byte 8)))
+  "Write elements of VECTOR to PATHNAME. Inlined function."
+  ;; FIXME: how to check-type?
   (with-output-to-file (stream pathname :if-exists if-exists
                                :if-does-not-exist if-does-not-exist
-                               :element-type '(unsigned-byte 8))
-    (write-sequence bytes stream)))
+                               :element-type element-type)
+    (write-sequence vector stream)))
+
+(defun write-vector-into-file (vector pathname &key (if-exists :error)
+                                                if-does-not-exist
+                                                (element-type '(unsigned-byte 8)))
+  "Write elements of VECTOR to PATHNAME."
+  (%write-vector-into-file vector pathname
+                           :if-exists if-exists
+                           :if-does-not-exist if-does-not-exist
+                           :element-type element-type))
+
+(macrolet
+    ((define (name bits &optional signed)
+       `(defun ,name (vector pathname &key (if-exists :error) if-does-not-exist)
+          ,(format nil "Writes elements of VECTOR to PATHNAME. VECTOR must be
+an array of (~A ~A) elements."
+                   (if signed 'signed-byte 'unsigned-byte) bits)
+          (check-type vector (vector (,(if signed
+                                           'signed-byte
+                                           'unsigned-byte)
+                                      ,bits)))
+          (%write-vector-into-file vector pathname
+                                   :if-exists if-exists
+                                   :if-does-not-exist if-does-not-exist
+                                   :element-type '(,(if signed
+                                                        'signed-byte
+                                                        'unsigned-byte)
+                                                   ,bits)))))
+  (define write-byte-vector-into-file 8)
+  (define write-u8-vector-into-file   8)
+  (define write-s8-vector-into-file   8 t)
+  (define write-u16-vector-into-file  16)
+  (define write-s16-vector-into-file  16 t)
+  (define write-u32-vector-into-file  32)
+  (define write-s32-vector-into-file  32 t)
+  (define write-u64-vector-into-file  64)
+  (define write-s64-vector-into-file  64 t))
+
+;;;; copying for files and streams
 
 (defun copy-file (from to &key (if-to-exists :supersede)
-			       (element-type '(unsigned-byte 8)) finish-output)
+                               (element-type '(unsigned-byte 8)) finish-output)
   (with-input-from-file (input from :element-type element-type)
     (with-output-to-file (output to :element-type element-type
-				    :if-exists if-to-exists)
+                                 :if-exists if-to-exists)
       (copy-stream input output
                    :element-type element-type
                    :finish-output finish-output))))
diff --git a/package.lisp b/package.lisp
index b5ce17b..910d93e 100644
--- a/package.lisp
+++ b/package.lisp
@@ -225,8 +225,26 @@
    #:with-output-to-file
    #:read-file-into-string
    #:write-string-into-file
+   #:read-file-into-vector
    #:read-file-into-byte-vector
+   #:read-file-into-u8-vector
+   #:read-file-into-s8-vector
+   #:read-file-into-u16-vector
+   #:read-file-into-s16-vector
+   #:read-file-into-u32-vector
+   #:read-file-into-s32-vector
+   #:read-file-into-u64-vector
+   #:read-file-into-s64-vector
+   #:write-vector-into-file
    #:write-byte-vector-into-file
+   #:write-u8-vector-into-file
+   #:write-s8-vector-into-file
+   #:write-u16-vector-into-file
+   #:write-s16-vector-into-file
+   #:write-u32-vector-into-file
+   #:write-s32-vector-into-file
+   #:write-u64-vector-into-file
+   #:write-s64-vector-into-file
    #:copy-stream
    #:copy-file
    ;; new additions collected at the end (subject to removal or further changes)
-- 
1.7.0.2

