blaze-builder-0.2.0.0: Efficient construction of bytestrings.

Portabilitytested on GHC only
Stabilityexperimental
MaintainerSimon Meier <iridcode@gmail.com>

Blaze.ByteString.Builder.Write

Contents

Description

This module provides the Write type, which abstracts direct writes to a buffer. Writes form the public interface for lifting direct buffer manipulations to Builders.

Synopsis

Atomic writes to a buffer

data Write Source

A value Write n io denotes the write of n bytes to a buffer. The actual write is executed by calling io with a pointer pf to the first free byte that the write should start with. Note that the caller of io pf must ensure that n bytes are free starting from pf.

For example, the function writeWord8 provided by Blaze.ByteString.Builder.Word creates a Write that writes a single fixed byte to a buffer.

 writeWord8   :: Word8 -> Write
 writeWord8 x  = Write 1 (\pf -> poke pf x)

The benefit of writes is that they abstract low-level manipulations (e.g. poke and copyBytes) of sequences of bytes in a form that that can be completely optimized away in many cases.

For example, the Monoid instance of Write allows to formulate writing a three-tuple of bytes as follows.

 writeThreeWord8   :: (Word8, Word8, Word8) -> Write
 writeThreeWord8 (x,y,z) = 
     writeWord8 x `mappend` writeWord8 y `mappend` writeWord8 z

This expression will be optimized by the compiler to the following efficient Write.

 writeThreeWord8 (x, y, z) = Write 3 $ \pf -> do
     poke pf               x
     poke (pf `plusPtr` 1) y
     poke (pf `plusPtr` 2) z

Writes are atomic. This means that the written data cannot be wrapped over buffer boundaries as it can be done for builders. For writes it holds that either the buffer has enough free space and the write can proceed or a new buffer with a size larger or equal to the number of bytes to write has to be allocated.

Moreover, for a Write, the size of the data to be written must be known before the data can be written. Hence, if this size is data-dependent, the control flow becomes complicated: first, all data must be forced and stored, then the size check happens, and only afterwards the stored data can be written. Therefore, because of cache misses, composing writes with data-dependent size computations may actually be slower than combining the resulting builders. Use benchmarking to make informed decisions.

Constructors

Write !Int (Ptr Word8 -> IO ()) 

Instances

Creating builders from Write abstractions

fromWrite :: Write -> BuilderSource

Create a Builder from a single write w. For good performance, w must feature an outermost Write constructor such that the pattern match can be eliminated during compilation.

Semantically, it holds that

 fromWrite . write = fromWriteSingleton write

However, performance-wise the right-hand side is more efficient due to currently unknown reasons. Use the second form, when defining functions for creating builders from writes of Haskell values.

(Use the standard benchmark in the blaze-html package when investigating this phenomenon.)

fromWriteSingleton :: (a -> Write) -> a -> BuilderSource

Create a Builder constructor from a single Write constructor.

fromWrite1List :: (a -> Write) -> [a] -> BuilderSource

Construct a Builder writing a list of data one element at a time from a Write abstraction.

fromWrite2List :: (a -> Write) -> [a] -> BuilderSource

Construct a Builder writing a list of data two elements at a time from a Write abstraction.

fromWrite4List :: (a -> Write) -> [a] -> BuilderSource

Construct a Builder writing a list of data four elements at a time from a Write abstraction.

fromWrite8List :: (a -> Write) -> [a] -> BuilderSource

Construct a Builder writing a list of data eight elements at a time from a Write abstraction.

fromWrite16List :: (a -> Write) -> [a] -> BuilderSource

Construct a Builder writing a list of data 16 elements at a time from a Write abstraction.