有什么方法可以在Common Lisp中将扁平化结构数组分配为C?

时间:2015-03-12 11:27:47

标签: arrays common-lisp

有没有办法在Common Lisp中为平局分配扁平化结构(AOS)?

我的意思是以下C等价物。

typedef struct {
  int x;
  float y;
  double z;
} foo_t;

#define SIZE 1000000

void bar()
{
  foo_t *f = malloc( sizeof( foo_t ) * SIZE );
  do_something_with( f );
}

通常在Common Lisp中,引用结构对象的指针数组用于表示这样的数据结构。

(defstruct foo
  (x 0 :type fixnum)
  (y 0.0 :type single-float)
  (z 0d0 :type double-float))

(let* ((size 1000000)
       (f (make-array size :element-type 'foo
                           :initial-contents (loop repeat size
                                                collect (make-foo)))))
  (do-something-with f))

当结构只有一种类型时,可以使用简单数组以命令式方式获得非常高效的性能,尽管简单数组只接受一种类型作为其元素类型。

; (defstruct vertex
;   (x 0d0 :type double-float)
;   (y 0d0 :type double-float)
;   (z 0d0 :type double-float))

(defun make-vertex-array (n)
  (make-array n :element-type 'double-float :initial-element 0d0))

(defmacro vertex-x (ary i)
  `(aref ,ary (+ (* ,i 3) 0)))

(defmacro vertex-y (ary i)
  `(aref ,ary (+ (* ,i 3) 1)))

(defmacro vertex-z (ary i)
  `(aref ,ary (+ (* ,i 3) 2)))

(let* ((size 1000000)
       (ary (make-vertex-array 100))
  (do-something-with ary))

我想听听有关具有多种元素类型的结构的事情。

2 个答案:

答案 0 :(得分:2)

标准Common Lisp不提供此类功能。我不知道实现高效结构数组的实现,其中结构在数组中分配。实现可能为某些结构实现有效的内存分配,但通常不适用于结构的向量。

这会给垃圾收集器带来挑战。通常,当没有对它的实时引用时,对象是垃圾。如果我们允许在数组内部分配结构,那么如果没有对它的引用并且没有对它的引用(对于数组内部的任何结构),该数组将是垃圾。

可能存在提供类似功能的库(http://cliki.net/data%20formats)。

通常有FFI(外部函数接口)功能可以处理记录数组,或者可以使用FFI构建它们。

答案 1 :(得分:0)

如果我理解正确你想要一个结构作为一个元素类型,有效和巧妙地访问结构的参数?为什么不这样做 - 无论这是否有效'取决于实现,您将无法通过软件给出的优化选项更多地影响它。

(defstruct foo 
  (x 0 :type fixnum)
  (y 0.0 :type single-float)
  (z 0d0 :type single-float))

(defun make-vertex-array (size)
  (make-array size :element-type 'foo :initial-contents (loop repeat size
                                                         collect (make-foo :x 0 :y 0.0 :z 0.0))))

(defparameter *test*
  (make-vertex-array 100))

(defmacro vertex-x (array i)
  `(foo-x (aref ,array ,i)))

(defmacro vertex-y (array i)
  `(foo-y (aref ,array ,i)))

(defmacro vertex-z (array i)
  `(foo-z (aref ,array ,i)))

(setf (vertex-x *test* 5) 4)

(setf (aref *test* 10) (make-foo :x 2 :y 0.0 :z 0.0))

(FORMAT T "~a~%" *test*)
>the array will be printed an you can see the changes  

(type-of *test*)
>(SIMPLE-VECTOR 100)

(type-of (make-array 100 :element-type 'integer))
>(SIMPLE-VECTOR 100)

根据CLHS

  

SIMPLE-VECTOR:没有移位到另一个数组的矢量类型没有   填充指针,不能明确调整,能够容纳元素   任何类型的类型都是simple-vector类型的子类型。

Further

  

任何一维数组都是向量。

现在提高您的效率。我没有做基准,所以我必须坚持使用手册。但似乎SBCL应该进行优化。

SBCL Manual on Efficiency

  

......原始CMUCL手册对于SBCL仍然是95 +%正确......

CMUCL on vectors

  

向量(一维数组)特别有用,因为在   除了明显的阵列式应用程序外,它们也很好   适合代表序列。与列表相比   表示,向量访问更快,并在两者之间占用   并且空间减少了64倍(取决于元素类型。)As   对于任意数组,编译器需要知道向量不是   复杂,所以你应该使用simple-string而不是字符串等。

因此,一些优化正在后台进行。但是,这是否涉及不使用引用并直接在数组中分配结构取决于SBCL,您将无法影响它。