@@ -7,8 +7,8 @@
7-- Stability : experimental
7-- Stability : experimental
8-- Portability : GHC
8-- Portability : GHC
10−-- An immutable buffer that supports cheap appends.
10+-- An "immutable" buffer that supports cheap appends.
12-- A Buffer is divided into an immutable read-only zone, followed by a
12-- A Buffer is divided into an immutable read-only zone, followed by a
13-- mutable area that we've preallocated, but not yet written to.
13-- mutable area that we've preallocated, but not yet written to.
@@ -19,6 +19,26 @@
20-- Once we run out of space at the end of a Buffer, we do the usual
20-- Once we run out of space at the end of a Buffer, we do the usual
21-- doubling of the buffer size.
21-- doubling of the buffer size.
23+-- The fact of having a mutable buffer really helps with performance,
24+-- but it does have a consequence: if someone misuses the Partial API
25+-- that attoparsec uses by calling the same continuation repeatedly
26+-- (which never makes sense in practice), they could overwrite data.
28+-- Since the API *looks* pure, it should *act* pure, too, so we use
29+-- two generation counters (one mutable, one immutable) to track the
30+-- number of appends to a mutable buffer. If the counters ever get out
31+-- of sync, someone is appending twice to a mutable buffer, so we
32+-- duplicate the entire buffer in order to preserve the immutability
35+-- While we could go a step further and gain protection against API
36+-- abuse on a multicore system, by use of an atomic increment
37+-- instruction to bump the mutable generation counter, that would be
38+-- very expensive, and feels like it would also be in the realm of the
39+-- ridiculous. Clients should never call a continuation more than
40+-- once; we lack a linear type system that could enforce this; and
41+-- there's only so far we should go to accommodate broken uses.
23module Data.Attoparsec.ByteString.Buffer
43module Data.Attoparsec.ByteString.Buffer