<div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">From: wren ng thornton &lt;<a href="mailto:wren@freegeek.org">wren@freegeek.org</a>&gt;<br>
On 3/21/11 4:40 PM, Brandon Moore wrote:<br>
&gt; Is there an efficient way to iterate over the bytes of a ByteString?<br>
<br>
The code I&#39;ve been using (rather similar to your unsafe map) is:<br>
<br>
     import qualified Data.ByteString.Internal as BSI<br>
     import qualified Foreign.ForeignPtr       as FFI<br>
<br>
     foldIO :: (a -&gt; Word8 -&gt; IO a) -&gt; a -&gt; ByteString -&gt; IO a<br>
     foldIO f z0 (<a href="http://BSI.PS" target="_blank">BSI.PS</a> fp off len) =<br>
         FFI.withForeignPtr fp $ \p0 -&gt; do<br>
             let q = p0 `plusPtr` (off+len)<br>
             let go z p<br>
                     | z `seq` p `seq` False = undefined<br>
                     | p == q    = return z<br>
                     | otherwise = do<br>
                         w  &lt;- peek p<br>
                         z&#39; &lt;- f z w<br>
                         go z&#39; (p `plusPtr` 1)<br>
             go z0 (p0 `plusPtr` off)<br>
     {-# INLINE foldIO #-}<br>
<br>
Some things to note:<br>
<br>
* It&#39;s a left fold rather than a right fold, just like foldM, except<br>
that we can&#39;t generalize it to work for all monads. (We could do a right<br>
fold just as easily by starting with p0`plusPtr`(off+len) and counting<br>
down to p0`plusPtr`off if desired.)<br>
<br>
* Because we&#39;re just keeping the head pointer, we can increment it as we<br>
go instead of using peekElemOff. This improves the performance by only<br>
performing one addition per loop (the p++) instead of two (ix++ and<br>
*(p+ix)), and by requiring one less register (for ix).<br></blockquote><div><br></div><div>Out of curiosity, do you have measurements that demonstrate improved performance from this?  When I did some tests with a similar problem, there was no noticeable difference between the two approaches.  In my case I also needed the element index though, so it was a slightly different problem.</div>
<div><br></div><div>For the OP, note that &#39;plusPtr&#39; doesn&#39;t do pointer arithmetic, it increments a ptr by n bytes.  This works for ByteStrings, but if you&#39;re generalizing to arbitrary storables you may prefer to use &#39;advancePtr&#39;, from Foreign.Marshal.Array.</div>
<div><br></div><div>John L.</div></div>