Hi Edi,
Instead of creating a class for each external format in order to optimize STREAM-READ-CHAR, we can just take all decision making code out from STREAM-READ-CHAR to (SETF FLEXI-STREAM-EXTERNAL-FORMAT).
Example of how it may be implemented in the bottom of the letter (only character encoding handling is refactored for this demonstration, newline encoding is leaved unchanged).
I've tested it on clisp 2.41 on my Windows machine.
Function FOO from the testbench code you posted to
http://thread.gmane.org/gmane.lisp.steel-bank.general/1400/ handles ntoskrnl.exe file with different flexi-streams versions as follows:
8.0 - 151 sec 9.0 - 40 sec 8.0 with my changes - 79 sec (note, only character encoding handling was optimized here)
Regards, -Anton
(defclass flexi-input-stream (flexi-stream fundamental-binary-input-stream
fundamental-character-input-stream) ( .... (get-char-code-func :initform nil)) ... )
(defmethod stream-read-char ((stream flexi-input-stream)) ... ;(let ((char-code (get-char-code))) (let ((char-code (funcall (slot-value stream 'get-char-code-func) stream))) ... )
#-:lispworks (defmethod initialize-instance :after ((flexi-stream flexi-input-stream) &rest initargs) (setf (slot-value flexi-stream 'get-char-code-func) (create-char-reader flexi-stream (external-format-name (flexi-stream-external-format flexi-stream)))))
(defmethod (setf flexi-stream-external-format) :after (new-value (stream flexi-input-stream)) (setf (slot-value stream 'get-char-code-func) (create-char-reader stream (external-format-name new-value))))
(defun create-char-reader (stream external-format-name) (format t "create-char-reader, stream: ~A, external-format-name: ~A~%" stream external-format-name) (cond ((ascii-name-p external-format-name) #'(lambda (stream) (read-char-8-bit stream +ascii-table+))) ((koi8-r-name-p external-format-name) #'(lambda (stream)(read-char-8-bit stream +koi8-r-table+))) ((iso-8859-name-p external-format-name) (let ((table (cdr (assoc external-format-name +iso-8859-tables+ :test #'eq)))) #'(lambda (stream)(read-char-8-bit stream table)))) ((code-page-name-p external-format-name) (let ((table (cdr (assoc (external-format-id external-format) +code-page-tables+)))) #'(lambda (stream) (read-char-8-bit stream table)))) (t (case external-format-name (:utf-8 #'read-char-utf-8) (:utf-16 #'read-char-utf-16) (:utf-32 #'read-char-utf-32)))))