TPDE
Loading...
Searching...
No Matches
VectorWriter.hpp
1// SPDX-FileCopyrightText: 2025 Contributors to TPDE <https://tpde.org>
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3#pragma once
4
5#include <cassert>
6#include <concepts>
7#include <cstddef>
8#include <cstring>
9
10#include "tpde/base.hpp"
11#include "tpde/util/misc.hpp"
12
13namespace tpde::util {
14
15template <typename VecT>
16 requires std::same_as<typename VecT::value_type, u8>
17class VectorWriter {
18 VecT *vector = nullptr;
19 u8 *cur;
20 u8 *end;
21
22public:
23 VectorWriter() noexcept = default;
24 VectorWriter(VecT &vector) noexcept
25 : vector(&vector),
26 cur(vector.data() + vector.size()),
27 end(vector.data() + vector.size()) {}
28 VectorWriter(VecT &vector, size_t off) noexcept
29 : vector(&vector),
30 cur(vector.data() + off),
31 end(vector.data() + vector.size()) {}
32 ~VectorWriter() { flush(); }
33
34 VectorWriter(const VectorWriter &) = delete;
35 VectorWriter(VectorWriter &&other) noexcept { *this = std::move(other); }
36
37 VectorWriter &operator=(const VectorWriter &) = delete;
38 VectorWriter &operator=(VectorWriter &&other) noexcept {
39 flush();
40 vector = other.vector;
41 cur = other.cur;
42 end = other.end;
43 other.vector = nullptr;
44 return *this;
45 }
46
47 void reserve(size_t extra) {
48 assert(end >= cur);
49 if (size_t(end - cur) < extra) [[unlikely]] {
50 size_t off = size();
51 // First try to use the available capacity before growing furiously.
52 if (vector->capacity() >= off + extra) {
53 vector->resize(vector->capacity());
54 assert(cur == vector->data() + off &&
55 "in-capacity resize reallocated?");
56 } else {
57 vector->resize(vector->size() * 2 + extra);
58 }
59 cur = vector->data() + off;
60 end = vector->data() + vector->size();
61 }
62 }
63
64 void flush() noexcept {
65 if (vector && cur != end) {
66 vector->resize(size());
67 end = cur;
68 }
69 }
70
71 size_t size() const noexcept { return cur - vector->data(); }
72 size_t capacity() const noexcept { return vector->size(); }
73
74 u8 *data() noexcept { return vector->data(); }
75
76 void skip_unchecked(size_t size) noexcept {
77 assert(size_t(end - cur) >= size);
78 cur += size;
79 }
80
81 void skip(size_t size) noexcept {
82 reserve(size);
83 skip_unchecked(size);
84 }
85
86 void write_unchecked(std::span<const u8> data) noexcept {
87 assert(size_t(end - cur) >= data.size());
88 std::memcpy(cur, data.data(), data.size());
89 cur += data.size();
90 }
91
92 void write(std::span<const u8> data) noexcept {
93 reserve(data.size());
94 write_unchecked(data);
95 }
96
97 template <std::integral T>
98 void write_unchecked(T t) noexcept {
99 assert(size_t(end - cur) >= sizeof(T));
100 std::memcpy(cur, &t, sizeof(T));
101 cur += sizeof(T);
102 }
103
104 template <std::integral T>
105 void write(T t) noexcept {
106 reserve(sizeof(T));
107 write_unchecked<T>(t);
108 }
109
110 void write_uleb_unchecked(uint64_t value) noexcept {
111 assert(size_t(end - cur) >= uleb_len(value));
112 cur += uleb_write(cur, value);
113 }
114
115 void write_uleb(uint64_t value) noexcept {
116 reserve(10);
117 write_uleb_unchecked(value);
118 }
119
120 void write_sleb_unchecked(int64_t value) noexcept {
121 // TODO: implement and use sleb_len
122 assert(size_t(end - cur) >= 10);
123 cur += sleb_write(cur, value);
124 }
125
126 void write_sleb(int64_t value) noexcept {
127 reserve(10);
128 write_sleb_unchecked(value);
129 }
130};
131
132} // end namespace tpde::util