From f083031a27815b4fcba4402ae5ec82c44d3d1e0d Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 6 Aug 2019 20:04:12 +0200 Subject: [PATCH] Kernel: Add KBufferBuilder, similar to StringBuilder but for KBuffer This class works by eagerly allocating 1MB of virtual memory but only adding physical pages on demand. In other words, when you append to it, its memory usage will increase by 1 page whenever you append across a page boundary (4KB.) --- Kernel/KBufferBuilder.cpp | 66 +++++++++++++++++++++++++++++++++++++++ Kernel/KBufferBuilder.h | 28 +++++++++++++++++ Kernel/Makefile | 1 + 3 files changed, 95 insertions(+) create mode 100644 Kernel/KBufferBuilder.cpp create mode 100644 Kernel/KBufferBuilder.h diff --git a/Kernel/KBufferBuilder.cpp b/Kernel/KBufferBuilder.cpp new file mode 100644 index 00000000000..a214f78e339 --- /dev/null +++ b/Kernel/KBufferBuilder.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +inline bool KBufferBuilder::can_append(size_t size) const +{ + bool has_space = ((m_size + size) < m_buffer.size()); + ASSERT(has_space); + return has_space; +} + +KBuffer KBufferBuilder::build() +{ + m_buffer.set_size(m_size); + return m_buffer; +} + +KBufferBuilder::KBufferBuilder() + : m_buffer(KBuffer::create_with_size(1048576)) +{ +} + +void KBufferBuilder::append(const StringView& str) +{ + if (str.is_empty()) + return; + if (!can_append(str.length())) + return; + memcpy(insertion_ptr(), str.characters_without_null_termination(), str.length()); + m_size += str.length(); +} + +void KBufferBuilder::append(const char* characters, int length) +{ + if (!length) + return; + if (!can_append(length)) + return; + memcpy(insertion_ptr() + m_size, characters, length); + m_size += length; +} + +void KBufferBuilder::append(char ch) +{ + if (!can_append(1)) + return; + insertion_ptr()[0] = ch; + m_size += 1; +} + +void KBufferBuilder::appendvf(const char* fmt, va_list ap) +{ + printf_internal([this](char*&, char ch) { + append(ch); + }, + nullptr, fmt, ap); +} + +void KBufferBuilder::appendf(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + appendvf(fmt, ap); + va_end(ap); +} diff --git a/Kernel/KBufferBuilder.h b/Kernel/KBufferBuilder.h new file mode 100644 index 00000000000..88d6affb71e --- /dev/null +++ b/Kernel/KBufferBuilder.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +class KBufferBuilder { +public: + using OutputType = KBuffer; + + explicit KBufferBuilder(); + ~KBufferBuilder() {} + + void append(const StringView&); + void append(char); + void append(const char*, int); + void appendf(const char*, ...); + void appendvf(const char*, va_list); + + KBuffer build(); + +private: + bool can_append(size_t) const; + u8* insertion_ptr() { return m_buffer.data() + m_size; } + + KBuffer m_buffer; + size_t m_size { 0 }; +}; diff --git a/Kernel/Makefile b/Kernel/Makefile index d81a2008df8..22b8d466f1c 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -36,6 +36,7 @@ KERNEL_OBJS = \ FileSystem/FIFO.o \ Scheduler.o \ DoubleBuffer.o \ + KBufferBuilder.o \ KSyms.o \ KParams.o \ FileSystem/SharedMemory.o \