From mvilleneuve at common-lisp.net Thu Jan 4 09:03:37 2007 From: mvilleneuve at common-lisp.net (mvilleneuve) Date: Thu, 4 Jan 2007 04:03:37 -0500 (EST) Subject: [zlib-cvs] CVS zlib/src Message-ID: <20070104090337.43E8B59001@common-lisp.net> Update of /project/zlib/cvsroot/zlib/src In directory clnet:/tmp/cvs-serv7863/src Modified Files: zlib.lisp Log Message: Optimize distance and length computations thanks to Pascal Bourguignon's decision-tree macro --- /project/zlib/cvsroot/zlib/src/zlib.lisp 2004/09/21 21:27:16 1.1.1.1 +++ /project/zlib/cvsroot/zlib/src/zlib.lisp 2007/01/04 09:03:37 1.2 @@ -1,7 +1,7 @@ ;;; ZLIB ;;; ;;; Copyright (C) 2001-2004 Harald Musum (musum at pvv.org) -;;; Copyright (C) 2004 Matthieu Villeneuve (matthieu.villeneuve at free.fr) +;;; Copyright (C) 2004-2006 Matthieu Villeneuve (matthieu.villeneuve at free.fr) ;;; ;;; The authors grant you the rights to distribute ;;; and use this software as governed by the terms @@ -314,64 +314,127 @@ do (setf (aref result i) (ldb (byte 1 i) code)) finally (return result))) -;; FIXME. It should be possible to do this smarter + +;;; DECISION-TREE macro +;;; Thanks to Pascal Bourguignon + +(eval-when (:compile-toplevel :load-toplevel :execute) + + (defun infix-to-tree (sequence) + (labels ((itt (items start end) + (cond + ((= start end) nil) + ((= (1+ start) end) (list (aref items start))) + (t (let ((pivot (truncate (/ (+ start end) 2)))) + (list (aref items pivot) + (itt items start pivot) + (itt items (1+ pivot) end))))))) + (let ((vect (coerce sequence 'vector))) + (itt vect 0 (length vect))))) + + (defun map-tree-postfix (fun tree) + (if (null tree) + nil + (funcall fun + (first tree) + (map-tree-postfix fun (second tree)) + (map-tree-postfix fun (third tree)))))) + +(defmacro decision-tree (expression &rest clauses) + " +CLAUSES: Each clause is of the forms: + (less|:less . ) ; must be the first clause if present. + ( . ) +DO: Evaluate the expression, which must be a real, + and generate a binary decision tree to select the + of the clause whose limit is <= the expression and + the next clause limit is > the expression. +" + (let ((vexpr (gensym)) + (less (when (and (symbolp (first (first clauses))) + (string-equal 'less (first (first clauses)))) + (pop clauses))) + (clauses (sort (coerce clauses 'vector) (function <) + :key (function car)))) + `(let ((,vexpr ,expression)) + ,(map-tree-postfix + (let ((index -1)) + (flet ((gen-case () + (incf index) + (if (zerop index) + `(progn ,@(cdr less)) + `(progn ,@(cdr (aref clauses (1- index))))))) + (lambda (node left right) + (if (and (null left) (null right)) + `(if (< ,vexpr ,(car node)) + ,(gen-case) + ,(gen-case)) + `(if (< ,vexpr ,(car node)) + ,left + ,(if (null right) + (gen-case) + right)))))) + (infix-to-tree clauses))))) + (defun distance-code (distance) "Return the distance-code for a given DISTANCE" - (cond ((< distance 5) (1- distance)) - ((<= 5 distance 6) 4) - ((<= 7 distance 8) 5) - ((<= 9 distance 12) 6) - ((<= 13 distance 16) 7) - ((<= 17 distance 24) 8) - ((<= 25 distance 32) 9) - ((<= 33 distance 48) 10) - ((<= 49 distance 64) 11) - ((<= 65 distance 96) 12) - ((<= 97 distance 128) 13) - ((<= 129 distance 192) 14) - ((<= 193 distance 256) 15) - ((<= 257 distance 384) 16) - ((<= 385 distance 512) 17) - ((<= 513 distance 768) 18) - ((<= 769 distance 1024) 19) - ((<= 1025 distance 1536) 20) - ((<= 1537 distance 2048) 21) - ((<= 2049 distance 3072) 22) - ((<= 3073 distance 4096) 23) - ((<= 4097 distance 6144) 24) - ((<= 6145 distance 8192) 25) - ((<= 8193 distance 12288) 26) - ((<= 12289 distance 16384) 27) - ((<= 16385 distance 24576) 28) - ((<= 24577 distance 32768) 29) - (t (error "A distance larger than 32768 is illegal")))) + (decision-tree distance + (less (1- distance)) + (5 4) + (7 5) + (9 6) + (13 7) + (17 8) + (25 9) + (33 10) + (49 11) + (65 12) + (97 13) + (129 14) + (193 15) + (257 16) + (385 17) + (513 18) + (769 19) + (1025 20) + (1537 21) + (2049 22) + (3073 23) + (4097 24) + (6145 25) + (8193 26) + (12289 27) + (16385 28) + (24577 29) + (32769 (error "A distance larger than 32768 is illegal")))) + -;; FIXME. It should be possible to do this smarter (defun length-code (length) "Return the length-code for a given LENGTH" - (cond ((<= length 10) (+ 254 length)) - ((<= 11 length 12) 265) - ((<= 13 length 14) 266) - ((<= 15 length 16) 267) - ((<= 17 length 18) 268) - ((<= 19 length 22) 269) - ((<= 23 length 26) 270) - ((<= 27 length 30) 271) - ((<= 31 length 34) 272) - ((<= 35 length 42) 273) - ((<= 43 length 50) 274) - ((<= 51 length 58) 275) - ((<= 59 length 66) 276) - ((<= 67 length 82) 277) - ((<= 83 length 98) 278) - ((<= 99 length 114) 279) - ((<= 115 length 130) 280) - ((<= 131 length 162) 281) - ((<= 163 length 194) 282) - ((<= 195 length 226) 283) - ((<= 227 length 257) 284) - ((= length 258) 285) - (t (error "A length larger than 258 is illegal")))) + (decision-tree length + (less (+ 254 length)) + (11 265) + (13 266) + (15 267) + (17 268) + (19 269) + (23 270) + (27 271) + (31 272) + (35 273) + (43 274) + (51 275) + (59 276) + (67 277) + (83 278) + (99 279) + (115 280) + (131 281) + (163 282) + (195 283) + (227 284) + (258 285) + (259 (error "A length larger than 258 is illegal")))) (defun distance-code-bits (code) "Return a list with 5 elements that are the binary representation of CODE."