Coverage Report

Created: 2026-02-14 08:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/AK/CircularBuffer.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2022, Lucas Chollet <lucas.chollet@free.fr>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/ByteBuffer.h>
10
#include <AK/Error.h>
11
#include <AK/HashMap.h>
12
#include <AK/Noncopyable.h>
13
#include <AK/Vector.h>
14
15
namespace AK {
16
17
class CircularBuffer {
18
    AK_MAKE_NONCOPYABLE(CircularBuffer);
19
    AK_MAKE_DEFAULT_MOVABLE(CircularBuffer);
20
21
public:
22
    static ErrorOr<CircularBuffer> create_empty(size_t size);
23
    static ErrorOr<CircularBuffer> create_initialized(ByteBuffer);
24
25
317k
    ~CircularBuffer() = default;
26
27
    size_t write(ReadonlyBytes bytes);
28
    Bytes read(Bytes bytes);
29
    ErrorOr<void> discard(size_t discarded_bytes);
30
    ErrorOr<size_t> fill_from_stream(Stream&);
31
    ErrorOr<size_t> flush_to_stream(Stream&);
32
33
    /// Compared to `read()`, this starts reading from an offset that is `distance` bytes
34
    /// before the current write pointer and allows for reading already-read data.
35
    ErrorOr<Bytes> read_with_seekback(Bytes bytes, size_t distance) const;
36
37
    ErrorOr<size_t> copy_from_seekback(size_t distance, size_t length);
38
39
    [[nodiscard]] size_t empty_space() const;
40
    [[nodiscard]] size_t used_space() const;
41
    [[nodiscard]] size_t capacity() const;
42
    [[nodiscard]] size_t seekback_limit() const;
43
44
    Optional<size_t> offset_of(StringView needle, Optional<size_t> from = {}, Optional<size_t> until = {}) const;
45
46
    void clear();
47
48
protected:
49
    CircularBuffer(ByteBuffer);
50
51
    [[nodiscard]] bool is_wrapping_around() const;
52
53
    [[nodiscard]] Bytes next_write_span();
54
    [[nodiscard]] ReadonlyBytes next_read_span(size_t offset = 0) const;
55
    [[nodiscard]] ReadonlyBytes next_seekback_span(size_t distance) const;
56
57
    ByteBuffer m_buffer {};
58
59
    size_t m_reading_head {};
60
    size_t m_used_space {};
61
    size_t m_seekback_limit {};
62
};
63
64
class SearchableCircularBuffer : public CircularBuffer {
65
public:
66
    static ErrorOr<SearchableCircularBuffer> create_empty(size_t size);
67
    static ErrorOr<SearchableCircularBuffer> create_initialized(ByteBuffer);
68
69
    [[nodiscard]] size_t search_limit() const;
70
71
    // These functions update the read pointer, so we need to hash any data that we have processed.
72
    ErrorOr<Bytes> read(Bytes bytes);
73
    ErrorOr<void> discard(size_t discarded_bytes);
74
    ErrorOr<size_t> flush_to_stream(Stream& stream);
75
76
    struct Match {
77
        size_t distance;
78
        size_t length;
79
    };
80
    /// This searches the seekback buffer (between read head and limit) for occurrences where it matches the next `length` bytes from the read buffer.
81
    /// Supplying any hints will only consider those distances, in case existing offsets need to be validated.
82
    /// Note that, since we only start searching at the read head, the length between read head and write head is excluded from the distance.
83
    Optional<Match> find_copy_in_seekback(size_t maximum_length, size_t minimum_length = 2);
84
    Optional<Match> find_copy_in_seekback(ReadonlySpan<size_t> distances, size_t maximum_length, size_t minimum_length = 2) const;
85
86
    // The chunk size for which the hash table holds hashes.
87
    // This is nice for users to know, as picking a minimum match length that is
88
    // equal or greater than this allows us to completely skip a slow memory search.
89
    static constexpr size_t HASH_CHUNK_SIZE = 3;
90
91
private:
92
    // Note: This function has a similar purpose as next_seekback_span, but they differ in their reference point.
93
    //       Seekback operations start counting their distance at the write head, while search operations start counting their distance at the read head.
94
    [[nodiscard]] ReadonlyBytes next_search_span(size_t distance) const;
95
96
    SearchableCircularBuffer(ByteBuffer);
97
98
    size_t m_hash_head {};
99
    HashMap<unsigned, size_t> m_hash_location_map;
100
    HashMap<size_t, size_t> m_location_chain_map;
101
102
    ErrorOr<void> insert_location_hash(ReadonlyBytes value, size_t raw_offset);
103
    ErrorOr<void> hash_new_bytes();
104
};
105
106
}