5

I'm working on optimizing some Emacs Lisp code that I've written. Part of this code needs to move elements from one vector to another. Currently, I have this code:

(defun copy-elements (source source-begin source-end
                      destination destination-begin)
  "Copy elements from SOURCE to DESTINATION.

We start at SOURCE[SOURCE-BEGIN], and the last element copied is
SOURCE[SOURCE-END - 1].

These elements are copied beginning at DESTINATION[DESTINATION-BEGIN].
This means DESTINATION must have enough space.

This method returns DESTINATION, and does not modify SOURCE.

If SOURCE and DESTINATION are the same, overlapping could cause issues."
  (dotimes (i (- source-end source-begin))
    (setf (seq-elt destination (+ i destination-begin))
          (seq-elt source (+ source-begin i))))
  destination)

This works fine:

ELISP> (let ((v1 [1 2 3]) (v2 [4 5 6])) (copy-elements v1 0 1 v2 2) (list v1 v2))
([1 2 3]
 [4 5 1])

But it's not as efficient as it could be. Even though we know we're working on consecutive elements, we move each one separately.

Is there a way to move or copy these elements? I don't need to share structure, so copying them would be perfectly fine if that's more efficient.

In fns.c, the function copy-sequence uses the C function memcpy to move things around vectors, but I don't see a way to do that myself.

What can I do to speed up moving consecutive elements from one vector to another?

Drew
  • 75,699
  • 9
  • 109
  • 225
zck
  • 8,984
  • 2
  • 31
  • 65
  • 4
    The `seq.el` API is generalised over all sequence types so will always be less efficient than vector-specific operations, so prefer `aref` and `aset` over `setf`-ing `seq-elt`. In idiomatic Elisp, there is usually no need for `memcpy`-like operations. Instead, you can efficiently create a copy of a subvector using the built-in function `substring`, or efficiently join subvectors using the built-in function `vconcat`. – Basil Jan 29 '20 at 08:40
  • 5
    `substring` with a vector argument is pretty hidden in the documentation if you're trying to learn about vectors. They're both array types, but even so... that's pretty obtuse even by lisp standards. – phils Jan 29 '20 at 09:14
  • @Basil Please add [that](https://emacs.stackexchange.com/questions/55180/how-do-i-efficiently-copy-or-move-elements-from-one-vector-to-another#comment86265_55180) as an answer. – Tobias Jan 29 '20 at 15:26

1 Answers1

2

I don't think there's such a thing and using memcpy on incompatible types is risky, so I went for the dumb solution in my last emulator project:

(defun chip8--memcpy (dest dest-offset src src-offset n)
  (dotimes (i n)
    (aset dest (+ dest-offset i) (aref src (+ src-offset i)))))

It works fine because copying memory isn't the bottleneck in my program, drawing pixels is.

wasamasa
  • 21,803
  • 1
  • 65
  • 97