LISP - 字节数组的快速输出

Noo*_*oob 2 character common-lisp cons output

我正在为LISP中的一种语言编写一个编译器,总体目标是让编译器从原始语言生成LISP代码.试图测量生成的代码的性能,我发现它严重缺乏打印字符串.

在原始语言中,字符是字节算术值,因此字符串是字节数组,字节的值对应于其值为字节的ascii代码的字符."可打印"字节数组必须以空值终止.因此,要将字节数组作为字符串打印,我必须在打印之前将原始数组的元素映射到字符中.处理此问题的函数如下:

(defun writeString (X &AUX (NPOS 0) (i 0))
  (declare (type (simple-VECTOR fixnum *) x))
  (declare (type fixnum NPOS i))
  (SETF NPOS (POSITION 0 X))
  (IF (NOT NPOS)
    (SETF NPOS (LENGTH X)))
  (princ (MAKE-ARRAY NPOS
                     :INITIAL-CONTENTS (map 'vector
                                            #'code-char
                                            (SUBSEQ X 0 NPOS))
                     :ELEMENT-TYPE 'base-char)))  
Run Code Online (Sandbox Code Playgroud)

并将其注入生成的代码中.

运行示例代码时time,我发现该princ部件在执行期间导致大量耗费,这会减慢速度.当放置make-array...静态字符串时,没有减速并且没有消耗,所以我猜这是损坏的部分.

在编译时,我已经在速度上设置了标志,现在在生成的代码中将字节值声明为fixnum.

任何人都可以指出我更好的方法来打印我的字节数组作为字符串,同时避免过多的消耗吗?

我可以将字节存储为get-go中的字符,但这会导致语言的部分因为需要转换而将它们视为数字较慢.

Rai*_*wig 6

代码中的问题

你的代码:

(defun writeString (X &AUX (NPOS 0) (i 0))
  (declare (type (simple-VECTOR fixnum *) x))
  (declare (type fixnum NPOS i))
  (SETF NPOS (POSITION 0 X))
  (IF (NOT NPOS)
    (SETF NPOS (LENGTH X)))
  (princ (MAKE-ARRAY NPOS
                     :INITIAL-CONTENTS (map 'vector
                                            #'code-char
                                            (SUBSEQ X 0 NPOS))
                     :ELEMENT-TYPE 'base-char)))
Run Code Online (Sandbox Code Playgroud)

代码中有几个错误:

  • i 未使用
  • 第一个类型声明是语法无效的
  • NPOS的声明是错误的.您将其定义为FIXNUM,但它可以是NIL.

有一堆编程错误:

  • 如果您想要的只是输出字符,则无需分配任何数组.
  • 即使你想生成一个数组,也可以做一次
  • X不是字符串的好名字

简单的解决方案:

(defun writestring (bytestring)
  (loop for byte across bytestring
        while (plusp byte)
        do (write-char (code-char byte))))
Run Code Online (Sandbox Code Playgroud)

声明的类型可以是:

(defun writestring (bytestring)
  (declare (vector bytestring))
  (loop for byte of-type (integer 0 255) across bytestring
        while (plusp byte)
        do (write-char (code-char byte))))
Run Code Online (Sandbox Code Playgroud)

相反,(integer 0 255)人们也可以使用(unsigned-byte 8).

关于生成向量:

让我们看看你是如何尝试创建数组的:

使用另一个数组中的内容创建一个包含make-array的数组.为什么不告诉MAP生成正确的数组?

CL-USER 46 > (map '(vector base-char) #'code-char #(102 111 111 98 97 114))
"foobar"
Run Code Online (Sandbox Code Playgroud)

现在,如果您想出于某种原因分配数组:

  • 做一次
  • 将内容映射到生成的数组中.使用map-into了点.它将以较短的序列停止.

例:

CL-USER 48 > (let ((bytestring #(102 111 111 98 97 114 0 100 100 100)))
               (map-into (make-array (or (position 0 bytestring)
                                         (length bytestring))
                                     :element-type 'base-char)
                         #'code-char
                         bytestring))
"foobar"
Run Code Online (Sandbox Code Playgroud)