DoxigAlpha

feed

Returns the number of bytes consumed by headers. This is always less than or equal to bytes.len.

If the amount returned is less than bytes.len, the parser is in a content state and the first byte of content is located at bytes[result].

Function parameters

Parameters

#
p:*HeadParser
bytes:[]const u8

Type definitions in this namespace

Types

#

Returns the number of bytes consumed by headers.

Functions

#
feed
Returns the number of bytes consumed by headers.

Source

Implementation

#
pub fn feed(p: *HeadParser, bytes: []const u8) usize {
    const vector_len: comptime_int = @max(std.simd.suggestVectorLength(u8) orelse 1, 8);
    var index: usize = 0;

    while (true) {
        switch (p.state) {
            .finished => return index,
            .start => switch (bytes.len - index) {
                0 => return index,
                1 => {
                    switch (bytes[index]) {
                        '\r' => p.state = .seen_r,
                        '\n' => p.state = .seen_n,
                        else => {},
                    }

                    return index + 1;
                },
                2 => {
                    const b16 = int16(bytes[index..][0..2]);
                    const b8 = intShift(u8, b16);

                    switch (b8) {
                        '\r' => p.state = .seen_r,
                        '\n' => p.state = .seen_n,
                        else => {},
                    }

                    switch (b16) {
                        int16("\r\n") => p.state = .seen_rn,
                        int16("\n\n") => p.state = .finished,
                        else => {},
                    }

                    return index + 2;
                },
                3 => {
                    const b24 = int24(bytes[index..][0..3]);
                    const b16 = intShift(u16, b24);
                    const b8 = intShift(u8, b24);

                    switch (b8) {
                        '\r' => p.state = .seen_r,
                        '\n' => p.state = .seen_n,
                        else => {},
                    }

                    switch (b16) {
                        int16("\r\n") => p.state = .seen_rn,
                        int16("\n\n") => p.state = .finished,
                        else => {},
                    }

                    switch (b24) {
                        int24("\r\n\r") => p.state = .seen_rnr,
                        else => {},
                    }

                    return index + 3;
                },
                4...vector_len - 1 => {
                    const b32 = int32(bytes[index..][0..4]);
                    const b24 = intShift(u24, b32);
                    const b16 = intShift(u16, b32);
                    const b8 = intShift(u8, b32);

                    switch (b8) {
                        '\r' => p.state = .seen_r,
                        '\n' => p.state = .seen_n,
                        else => {},
                    }

                    switch (b16) {
                        int16("\r\n") => p.state = .seen_rn,
                        int16("\n\n") => p.state = .finished,
                        else => {},
                    }

                    switch (b24) {
                        int24("\r\n\r") => p.state = .seen_rnr,
                        else => {},
                    }

                    switch (b32) {
                        int32("\r\n\r\n") => p.state = .finished,
                        else => {},
                    }

                    index += 4;
                    continue;
                },
                else => {
                    const Vector = @Vector(vector_len, u8);
                    // const BoolVector = @Vector(vector_len, bool);
                    const BitVector = @Vector(vector_len, u1);
                    const SizeVector = @Vector(vector_len, u8);

                    const chunk = bytes[index..][0..vector_len];
                    const v: Vector = chunk.*;
                    // depends on https://github.com/ziglang/zig/issues/19755
                    // const matches_r: BitVector = @bitCast(v == @as(Vector, @splat('\r')));
                    // const matches_n: BitVector = @bitCast(v == @as(Vector, @splat('\n')));
                    const matches_r: BitVector = @select(u1, v == @as(Vector, @splat('\r')), @as(Vector, @splat(1)), @as(Vector, @splat(0)));
                    const matches_n: BitVector = @select(u1, v == @as(Vector, @splat('\n')), @as(Vector, @splat(1)), @as(Vector, @splat(0)));
                    const matches_or: SizeVector = matches_r | matches_n;

                    const matches = @reduce(.Add, matches_or);
                    switch (matches) {
                        0 => {},
                        1 => switch (chunk[vector_len - 1]) {
                            '\r' => p.state = .seen_r,
                            '\n' => p.state = .seen_n,
                            else => {},
                        },
                        2 => {
                            const b16 = int16(chunk[vector_len - 2 ..][0..2]);
                            const b8 = intShift(u8, b16);

                            switch (b8) {
                                '\r' => p.state = .seen_r,
                                '\n' => p.state = .seen_n,
                                else => {},
                            }

                            switch (b16) {
                                int16("\r\n") => p.state = .seen_rn,
                                int16("\n\n") => p.state = .finished,
                                else => {},
                            }
                        },
                        3 => {
                            const b24 = int24(chunk[vector_len - 3 ..][0..3]);
                            const b16 = intShift(u16, b24);
                            const b8 = intShift(u8, b24);

                            switch (b8) {
                                '\r' => p.state = .seen_r,
                                '\n' => p.state = .seen_n,
                                else => {},
                            }

                            switch (b16) {
                                int16("\r\n") => p.state = .seen_rn,
                                int16("\n\n") => p.state = .finished,
                                else => {},
                            }

                            switch (b24) {
                                int24("\r\n\r") => p.state = .seen_rnr,
                                else => {},
                            }
                        },
                        4...vector_len => {
                            inline for (0..vector_len - 3) |i_usize| {
                                const i = @as(u32, @truncate(i_usize));

                                const b32 = int32(chunk[i..][0..4]);
                                const b16 = intShift(u16, b32);

                                if (b32 == int32("\r\n\r\n")) {
                                    p.state = .finished;
                                    return index + i + 4;
                                } else if (b16 == int16("\n\n")) {
                                    p.state = .finished;
                                    return index + i + 2;
                                }
                            }

                            const b24 = int24(chunk[vector_len - 3 ..][0..3]);
                            const b16 = intShift(u16, b24);
                            const b8 = intShift(u8, b24);

                            switch (b8) {
                                '\r' => p.state = .seen_r,
                                '\n' => p.state = .seen_n,
                                else => {},
                            }

                            switch (b16) {
                                int16("\r\n") => p.state = .seen_rn,
                                int16("\n\n") => p.state = .finished,
                                else => {},
                            }

                            switch (b24) {
                                int24("\r\n\r") => p.state = .seen_rnr,
                                else => {},
                            }
                        },
                        else => unreachable,
                    }

                    index += vector_len;
                    continue;
                },
            },
            .seen_n => switch (bytes.len - index) {
                0 => return index,
                else => {
                    switch (bytes[index]) {
                        '\n' => p.state = .finished,
                        else => p.state = .start,
                    }

                    index += 1;
                    continue;
                },
            },
            .seen_r => switch (bytes.len - index) {
                0 => return index,
                1 => {
                    switch (bytes[index]) {
                        '\n' => p.state = .seen_rn,
                        '\r' => p.state = .seen_r,
                        else => p.state = .start,
                    }

                    return index + 1;
                },
                2 => {
                    const b16 = int16(bytes[index..][0..2]);
                    const b8 = intShift(u8, b16);

                    switch (b8) {
                        '\r' => p.state = .seen_r,
                        '\n' => p.state = .seen_rn,
                        else => p.state = .start,
                    }

                    switch (b16) {
                        int16("\r\n") => p.state = .seen_rn,
                        int16("\n\r") => p.state = .seen_rnr,
                        int16("\n\n") => p.state = .finished,
                        else => {},
                    }

                    return index + 2;
                },
                else => {
                    const b24 = int24(bytes[index..][0..3]);
                    const b16 = intShift(u16, b24);
                    const b8 = intShift(u8, b24);

                    switch (b8) {
                        '\r' => p.state = .seen_r,
                        '\n' => p.state = .seen_n,
                        else => p.state = .start,
                    }

                    switch (b16) {
                        int16("\r\n") => p.state = .seen_rn,
                        int16("\n\n") => p.state = .finished,
                        else => {},
                    }

                    switch (b24) {
                        int24("\n\r\n") => p.state = .finished,
                        else => {},
                    }

                    index += 3;
                    continue;
                },
            },
            .seen_rn => switch (bytes.len - index) {
                0 => return index,
                1 => {
                    switch (bytes[index]) {
                        '\r' => p.state = .seen_rnr,
                        '\n' => p.state = .seen_n,
                        else => p.state = .start,
                    }

                    return index + 1;
                },
                else => {
                    const b16 = int16(bytes[index..][0..2]);
                    const b8 = intShift(u8, b16);

                    switch (b8) {
                        '\r' => p.state = .seen_rnr,
                        '\n' => p.state = .seen_n,
                        else => p.state = .start,
                    }

                    switch (b16) {
                        int16("\r\n") => p.state = .finished,
                        int16("\n\n") => p.state = .finished,
                        else => {},
                    }

                    index += 2;
                    continue;
                },
            },
            .seen_rnr => switch (bytes.len - index) {
                0 => return index,
                else => {
                    switch (bytes[index]) {
                        '\n' => p.state = .finished,
                        else => p.state = .start,
                    }

                    index += 1;
                    continue;
                },
            },
        }

        return index;
    }
}