liblinux++

A hosted C++ runtime without any libc.
git clone git://henryandlizzy.uk/liblinux++
Log | Files | Refs

commit e73acf0554f059c01739e12aa2a18301943a3d6b
parent a962c85ccf6076e754363a6ea207ef20e3172b6a
Author: Henry Wilson <henry@henryandlizzy.uk>
Date:   Fri, 26 Dec 2025 20:03:31 +0000

writer: demo equivalent of std::ostringstream

Diffstat:
MTupfile | 2+-
Mlinux.hpp | 21+++++++++++++++++++--
Awriter.cpp | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/Tupfile b/Tupfile @@ -1,4 +1,4 @@ -CXXFLAGS = -g -Os -fno-exceptions -fno-asynchronous-unwind-tables -fno-builtin -fno-pic -fno-pie -fno-stack-protector -fdiagnostics-color=always +CXXFLAGS = -g -Os -fno-exceptions -fno-rtti -fno-asynchronous-unwind-tables -fno-builtin -fno-pic -fno-pie -fno-stack-protector -fdiagnostics-color=always LDFLAGS = --gc-sections : foreach *.cpp |> clang++ --target=aarch64 $(CXXFLAGS) -c -o %o %f |> obj/%B.aarch64.o {objs-aarch64} diff --git a/linux.hpp b/linux.hpp @@ -46,7 +46,7 @@ struct span { span() = default; inline span(T* p, size_t n) - : data{p} + : ptr{p} , len{n} {} @@ -54,8 +54,25 @@ struct span inline span(T (&arr)[N]) : span{arr, N} {} + + T* data() const noexcept + { + return ptr; + } + size_t size() const noexcept + { + return len; + } + T* begin() const noexcept + { + return data(); + } + T* end() const noexcept + { + return begin() + size(); + } private: - T* data = nullptr; + T* ptr = nullptr; size_t len = 0; }; diff --git a/writer.cpp b/writer.cpp @@ -0,0 +1,81 @@ +#include "linux.hpp" + +struct writer +{ + virtual void write(span<char const>) = 0; +protected: + ~writer() = default; +}; + +struct fd_writer : writer +{ + fd_writer(file f) : out{f} {} + + void write(span<char const> data) override + { + if (*::write(out, data) != data.size()) + __builtin_trap(); + } +private: + file out; +}; + +template <typename T> +struct vector +{ + void push_back(T c) + { + if (used * sizeof(T) >= capacity) + { + size_t const old_cap = capacity; + size_t const new_cap = capacity ? capacity * 2 : 0x1000; + T* new_buf = (T*)*mmap(nullptr, new_cap, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, {}, 0); + for (size_t i = 0; i < used; ++i) + new_buf[i] = buf[i]; + capacity = new_cap; + if (buf) + *munmap(buf, old_cap); + buf = new_buf; + } + + buf[used++] = c; + } + + T const* data() const { return buf; } + T* data() { return buf; } + size_t size() const { return used; } +private: + T* buf = nullptr; + size_t capacity = 0, used = 0; +}; + +struct buf_writer : writer +{ + buf_writer() noexcept = default; + + void write(span<char const> data) override + { + for (char c : data) + buffer.push_back(c); + } + span<char const> get() const noexcept + { + return {buffer.data(), buffer.size()}; + } +private: + vector<char> buffer; +}; + +int main() +{ + buf_writer x; + writer* w = &x; + for (int i = 0; i < 240; ++i) + { + w->write("Hello, "); + w->write("World! Wow what a lovely day!\n"); + } + fd_writer cout{stdout}; + w = &cout; + w->write(x.get()); +}