output - LISP - 字节数组的快速输出

标签 output character common-lisp cons

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

在原始语言中,字符是字节的算术值,因此字符串是字节的数组,字节的值对应的字符的值为字节的ascii码。 “可打印”字节数组必须以 null 结尾。因此,要将字节数组打印为字符串,我必须在打印之前将原始数组的元素映射为字符。处理这个的函数如下:

(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)))  

并将其注入(inject)到生成的代码中。

使用 time 运行示例代码,我发现 princ 部分在执行期间会导致大量 consing,这会减慢速度。当在 make-array... 的地方放置一个静态字符串时,没有减速也没有 consing,所以我猜这就是损坏的部分。

在编译时,我将速度标志设置为 full,字节值在生成的代码中暂时声明为 fixnum。

谁能指出一种更好的方法来将我的字节数组打印为字符串,同时避免过多的 consing?

我可以从一开始就将字节存储为字符,但这会导致语言中将它们视为数字的部分由于需要转换而变慢。

最佳答案

你的代码有问题

您的代码:

(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)))

代码中有几个错误:

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

有一堆编程错误:

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

一个简单的解决方案:

(defun writestring (bytestring)
  (loop for byte across bytestring
        while (plusp byte)
        do (write-char (code-char byte))))

类型声明的版本可以是:

(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))))

代替 (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"

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

  • 做一次
  • 将内容映射到生成的数组中。为此使用 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"

关于output - LISP - 字节数组的快速输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51657881/

相关文章:

Java 十六进制到十进制转换 : Custom Logic

r - 使用循环/其他任何东西来写一串间隔(向量)

lisp - 寻找最大元素的迭代解决方案

lisp - 通用 Lisp : getting an error using readtable-case

common-lisp - 输出提示彼此重叠

haskell - 访问数据构造函数haskell中的类型字段

Java 日历无法正常工作

c++ - 为什么输出的是方框里的问号而不是数字?

Python脚本,没有输出?

ios - 计算一些字符串 iOS 之前的字符