[Openmcl-devel] byte-strings
Gary Byers
gb at clozure.com
Fri Aug 20 20:00:50 PDT 2004
On Fri, 20 Aug 2004, Ben wrote:
> hi,
>
> i'm writing an application which wants to treat strings as byte arrays
> for the purposes of FFI. more specifically, i'd like to be able to
> quickly copy the contents of strings in and out of foreign character
> arrays. i don't really care about what the character representation
> is, i'm happy treating everyting as bits.
>
> under CMUCL and Franz i can directly pass strings to memcpy, which
> does the trick. this works even with 16-bit strings in Franz,
> provided i pass in the correct byte-length. under Lispworks there is
> a function "fli:replace-foreign-array" which i'm hoping will do the
> trick for me.
>
> of course there is nothing stopping me from doing (using UFFI)
>
> (defun copy-buf (str buf len src-offset 0 buf-offset 0))
> (declare (optimize (speed 3) (safety 0))
> (type string str)
> (type array-char buf)
> (type fixnum len src-offset buf-offset)
> (dynamic-extent str buf len))
> (typecase str
> (simple-string
> (loop for i fixnum from 0 below len
> do
> (setf (deref-array buf '(:array :char) (+ i buf-offset))
> (char-code (schar str (+ i src-offset))))))
> (string
> (loop for i fixnum from 0 below len
> do
> (setf (deref-array buf '(:array :char) (+ i buf-offset))
> (char-code (char str (+ i src-offset))))))))
>
> but i find memcpy is much, much faster. is there any way to get at
> the underlying bits of a string? e.g. is "with-cstr" using memcpy,
> and can i pass it a buffer to stuff the string into?
>
WITH-CSTR uses something called CCL::%COPY-IVECTOR-TO-PTR, which takes
5 arguments:
(ccl::%COPY-IVECTOR-TO-PTR source ; an "ivector"
source-byte-offset ; not bounds-checked
dest ; a MACPTR
dest-byte-offset ; no checking here ..
nbytes) ; ... or here either
An "IVECTOR" is basically any (SIMPLE-ARRAY <type> (*)), where
<type> is something for which (UPGRADED-ARRAY-ELEMENT-TYPE <type>) is
other than T. (E.g., a SIMPLE-STRING, a bit vector, a vector of
signed/unsigned bytes, a vector of some float type, etc.) There are
other, implementation-level things that are also ivectors.
Note that a non-SIMPLE-STRING is -not- an ivector, but it's displaced
to one (see below.)
CCL::%COPY-IVECTOR-TO-PTR's written in assembler; it could be faster
in some cases (using DOUBLE-FLOATs or AltiVec to move larger chunks
of congruently-aligned stuff around), but in practice it's pretty fast.
To copy the bytes in a SIMPLE-STRING to foreign memory:
(ccl::%copy-ivector-to-ptr "ABC" 0 p 0 3)
If a string isn't a SIMPLE-STRING, it's (perhaps transitively) displaced
to one. CCL::ARRAY-DATA-AND-OFFSET returns two values:
(0) the underlying (SIMPLE-ARRAY * (*))
(1) the cumulative displacement
Calling CCL::ARRAY-DATA-AND-OFFSET on something that -is- a
(SIMPLE-ARRAY * (*)) returns that argument and 0.
> thanks in advance, B
If you look at WITH-CSTR (I hadn't done so in a long time ...), you'll
see a lot of code that's a little too general wrapped around a call to
CCL::%COPY-IVECTOR-TO-PTR. (Hmmm ... if you look at it as long as I
just did, you'll also see that CCL::DEREFERENCE-BASE-STRING should
just be returning the length of its argument as a third value, not
(+ offset length) as it's been doing.)
More information about the Openmcl-devel
mailing list