Serenity Operating System
at master 187 lines 5.2 kB view raw
1/* 2 * Copyright (c) 2022, Lucas Chollet <lucas.chollet@free.fr> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/CircularBuffer.h> 8#include <AK/MemMem.h> 9 10namespace AK { 11 12CircularBuffer::CircularBuffer(ByteBuffer buffer) 13 : m_buffer(move(buffer)) 14{ 15} 16 17ErrorOr<CircularBuffer> CircularBuffer::create_empty(size_t size) 18{ 19 auto temporary_buffer = TRY(ByteBuffer::create_uninitialized(size)); 20 21 CircularBuffer circular_buffer { move(temporary_buffer) }; 22 23 return circular_buffer; 24} 25 26ErrorOr<CircularBuffer> CircularBuffer::create_initialized(ByteBuffer buffer) 27{ 28 CircularBuffer circular_buffer { move(buffer) }; 29 30 circular_buffer.m_used_space = circular_buffer.m_buffer.size(); 31 32 return circular_buffer; 33} 34 35size_t CircularBuffer::empty_space() const 36{ 37 return capacity() - m_used_space; 38} 39 40size_t CircularBuffer::used_space() const 41{ 42 return m_used_space; 43} 44 45size_t CircularBuffer::capacity() const 46{ 47 return m_buffer.size(); 48} 49 50bool CircularBuffer::is_wrapping_around() const 51{ 52 return capacity() <= m_reading_head + m_used_space; 53} 54 55Optional<size_t> CircularBuffer::offset_of(StringView needle, Optional<size_t> from, Optional<size_t> until) const 56{ 57 auto const read_from = from.value_or(0); 58 auto const read_until = until.value_or(m_used_space); 59 VERIFY(read_from <= read_until); 60 61 Array<ReadonlyBytes, 2> spans {}; 62 spans[0] = next_read_span(); 63 auto const original_span_0_size = spans[0].size(); 64 65 if (read_from > 0) 66 spans[0] = spans[0].slice(min(spans[0].size(), read_from)); 67 68 if (spans[0].size() + read_from > read_until) 69 spans[0] = spans[0].trim(read_until - read_from); 70 else if (is_wrapping_around()) 71 spans[1] = m_buffer.span().slice(max(original_span_0_size, read_from) - original_span_0_size, min(read_until, m_used_space) - original_span_0_size); 72 73 auto maybe_found = AK::memmem(spans.begin(), spans.end(), needle.bytes()); 74 if (maybe_found.has_value()) 75 *maybe_found += read_from; 76 77 return maybe_found; 78} 79 80void CircularBuffer::clear() 81{ 82 m_reading_head = 0; 83 m_used_space = 0; 84 m_seekback_limit = 0; 85} 86 87Bytes CircularBuffer::next_write_span() 88{ 89 if (is_wrapping_around()) 90 return m_buffer.span().slice(m_reading_head + m_used_space - capacity(), capacity() - m_used_space); 91 return m_buffer.span().slice(m_reading_head + m_used_space, capacity() - (m_reading_head + m_used_space)); 92} 93 94ReadonlyBytes CircularBuffer::next_read_span() const 95{ 96 return m_buffer.span().slice(m_reading_head, min(capacity() - m_reading_head, m_used_space)); 97} 98 99ReadonlyBytes CircularBuffer::next_read_span_with_seekback(size_t distance) const 100{ 101 VERIFY(m_seekback_limit <= capacity()); 102 VERIFY(distance <= m_seekback_limit); 103 104 // Note: We are adding the capacity once here to ensure that we can wrap around the negative space by using modulo. 105 auto read_offset = (capacity() + m_reading_head + m_used_space - distance) % capacity(); 106 107 return m_buffer.span().slice(read_offset, min(capacity() - read_offset, m_seekback_limit)); 108} 109 110size_t CircularBuffer::write(ReadonlyBytes bytes) 111{ 112 auto remaining = bytes.size(); 113 114 while (remaining > 0) { 115 auto const next_span = next_write_span(); 116 if (next_span.size() == 0) 117 break; 118 119 auto const written_bytes = bytes.slice(bytes.size() - remaining).copy_trimmed_to(next_span); 120 121 m_used_space += written_bytes; 122 123 m_seekback_limit += written_bytes; 124 if (m_seekback_limit > capacity()) 125 m_seekback_limit = capacity(); 126 127 remaining -= written_bytes; 128 } 129 130 return bytes.size() - remaining; 131} 132 133Bytes CircularBuffer::read(Bytes bytes) 134{ 135 auto remaining = bytes.size(); 136 137 while (remaining > 0) { 138 auto const next_span = next_read_span(); 139 if (next_span.size() == 0) 140 break; 141 142 auto written_bytes = next_span.copy_trimmed_to(bytes.slice(bytes.size() - remaining)); 143 144 m_used_space -= written_bytes; 145 m_reading_head += written_bytes; 146 147 if (m_reading_head >= capacity()) 148 m_reading_head -= capacity(); 149 150 remaining -= written_bytes; 151 } 152 153 return bytes.trim(bytes.size() - remaining); 154} 155 156ErrorOr<Bytes> CircularBuffer::read_with_seekback(Bytes bytes, size_t distance) 157{ 158 if (distance > m_seekback_limit) 159 return Error::from_string_literal("Tried a seekback read beyond the seekback limit"); 160 161 auto remaining = bytes.size(); 162 163 while (remaining > 0) { 164 auto const next_span = next_read_span_with_seekback(distance); 165 if (next_span.size() == 0) 166 break; 167 168 auto written_bytes = next_span.copy_trimmed_to(bytes.slice(bytes.size() - remaining)); 169 170 distance -= written_bytes; 171 remaining -= written_bytes; 172 } 173 174 return bytes.trim(bytes.size() - remaining); 175} 176 177ErrorOr<void> CircularBuffer::discard(size_t discarding_size) 178{ 179 if (m_used_space < discarding_size) 180 return Error::from_string_literal("Can not discard more data than what the buffer contains"); 181 m_used_space -= discarding_size; 182 m_reading_head = (m_reading_head + discarding_size) % capacity(); 183 184 return {}; 185} 186 187}