Self-delimiting blocks #
To concatenate binary strings into a single binary string, each piece must announce its own end. This file defines the library's single framing operation and its parsers:
delimitframes a payload: each payload bit is doubled (false ↦ [false, false],true ↦ [true, true]) and the block is terminated by the separator[false, true], which no run of doubled bits can produce.unpair?parses one block off the front of the input, returning the payload and the remaining suffix (noneon malformed input). It is named for its role in the pairing codecComplexity.pair(seeComplexitylib.Encoding.Pairing), which ispair x y = delimit x ++ y.undelimitBlock,takeFirstBlock,hasBlock,tagBlock, andundelimitBlocksare the total helper functions machines compute when working with framed data.
This file deliberately has no dependency on the machine or complexity-class layers, so the
machine-input pairing codec (Complexitylib.Encoding.Pairing) can build on it without import
cycles.
Frame a binary string as a self-delimiting block: each payload bit is doubled
(false ↦ [false, false], true ↦ [true, true]) and the block is terminated by the
separator [false, true], which no run of doubled bits can produce.
Instances For
Parse one self-delimiting block off the front of the input. It scans doubled bits until
the first separator [false, true], returning the decoded payload together with the
remaining suffix. Invalid doubled prefixes return none.
Equations
- Complexity.unpair? [] = none
- Complexity.unpair? (false :: true :: y) = some ([], y)
- Complexity.unpair? (false :: false :: z) = Option.map (fun (xy : List Bool × List Bool) => (false :: xy.fst, xy.snd)) (Complexity.unpair? z)
- Complexity.unpair? (true :: true :: z) = Option.map (fun (xy : List Bool × List Bool) => (true :: xy.fst, xy.snd)) (Complexity.unpair? z)
- Complexity.unpair? x✝ = none
Instances For
Strip the framing of a single self-delimiting block, returning its payload. On delimit P
this returns P. Unlike unpair?, this is total: it ignores any data trailing the first block
and maps malformed input to [].
Equations
- Complexity.undelimitBlock (false :: true :: tail) = []
- Complexity.undelimitBlock (false :: false :: rest) = false :: Complexity.undelimitBlock rest
- Complexity.undelimitBlock (true :: head :: rest) = true :: Complexity.undelimitBlock rest
- Complexity.undelimitBlock x✝ = []
Instances For
Does the bitstring begin with a well-formed self-delimiting block?
Equations
- Complexity.hasBlock (false :: true :: tail) = true
- Complexity.hasBlock (false :: false :: rest) = Complexity.hasBlock rest
- Complexity.hasBlock (true :: true :: rest) = Complexity.hasBlock rest
- Complexity.hasBlock x✝ = false
Instances For
Tag a bitstring with a leading true if it begins with a well-formed self-delimiting
block, and return the empty bitstring otherwise. On pair encodings this computes
encode ∘ decode.
Equations
- Complexity.tagBlock l = bif Complexity.hasBlock l then true :: l else []
Instances For
Parse a sequence of self-delimiting blocks, using fuel to bound the number of blocks.
This is the auxiliary, fuel-carrying implementation of undelimitBlocks; since every block
is nonempty, input.length is always enough fuel.
Equations
Instances For
Parse a sequence of self-delimiting blocks off the front of the input.
Since every block is nonempty, input.length bounds the number of blocks, so it always
suffices as fuel for undelimitBlocksAux.
Equations
- Complexity.undelimitBlocks input = Complexity.undelimitBlocksAux input.length input