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/SmallVector.hpp"
12#include "tpde/util/misc.hpp"
13
14namespace tpde::util {
15
16class VectorWriter {
17 SmallVectorBase<u8> *vector = nullptr;
18 u8 *cur;
19 u8 *end;
20
21public:
22 VectorWriter() noexcept = default;
23 VectorWriter(SmallVectorBase<u8> &vector) noexcept
24 : vector(&vector),
25 cur(vector.data() + vector.size()),
26 end(vector.data() + vector.size()) {}
27 VectorWriter(SmallVectorBase<u8> &vector, size_t off) noexcept
28 : vector(&vector),
29 cur(vector.data() + off),
30 end(vector.data() + vector.size()) {}
31 ~VectorWriter() { flush(); }
32
33 VectorWriter(const VectorWriter &) = delete;
34 VectorWriter(VectorWriter &&other) noexcept { *this = std::move(other); }
35
36 VectorWriter &operator=(const VectorWriter &) = delete;
37 VectorWriter &operator=(VectorWriter &&other) noexcept {
38 flush();
39 vector = other.vector;
40 cur = other.cur;
41 end = other.end;
42 other.vector = nullptr;
43 return *this;
44 }
45
46 void reserve(size_t extra) {
47 assert(end >= cur);
48 if (size_t(end - cur) < extra) [[unlikely]] {
49 size_t off = size();
50 if (vector->capacity() < off + extra) {
51 // This will grow exponentially.
52 vector->reserve(off + extra);
53 }
54 vector->resize_uninitialized(vector->capacity());
55 cur = vector->data() + off;
56 end = vector->data() + vector->size();
57 }
58 }
59
60 void flush() noexcept {
61 if (vector && cur != end) {
62 vector->resize(size());
63 end = cur;
64 }
65 }
66
67 size_t size() const noexcept { return cur - vector->data(); }
68 size_t capacity() const noexcept { return vector->size(); }
69
70 u8 *data() noexcept { return vector->data(); }
71
72 void skip_unchecked(size_t size) noexcept {
73 assert(size_t(end - cur) >= size);
74 cur += size;
75 }
76
77 void skip(size_t size) noexcept {
78 reserve(size);
79 skip_unchecked(size);
80 }
81
82 void unskip(size_t n) noexcept {
83 assert(n <= size());
84 cur -= n;
85 }
86
87 void zero_unchecked(size_t n) noexcept {
88 assert(size_t(end - cur) >= n);
89 TPDE_NOALIAS(this, cur);
90 std::memset(cur, 0, n);
91 cur += n;
92 }
93
94 void zero(size_t n) noexcept {
95 reserve(n);
96 zero_unchecked(n);
97 }
98
99 void write_unchecked(std::span<const u8> data) noexcept {
100 assert(size_t(end - cur) >= data.size());
101 TPDE_NOALIAS(this, cur);
102 std::memcpy(cur, data.data(), data.size());
103 cur += data.size();
104 }
105
106 void write(std::span<const u8> data) noexcept {
107 reserve(data.size());
108 write_unchecked(data);
109 }
110
111 template <std::integral T>
112 void write_unchecked(T t) noexcept {
113 assert(size_t(end - cur) >= sizeof(T));
114 TPDE_NOALIAS(this, cur);
115 std::memcpy(cur, &t, sizeof(T));
116 cur += sizeof(T);
117 }
118
119 template <std::integral T>
120 void write(T t) noexcept {
121 reserve(sizeof(T));
122 write_unchecked<T>(t);
123 }
124
125 void write_uleb_unchecked(uint64_t value) noexcept {
126 assert(size_t(end - cur) >= uleb_len(value));
127 cur += uleb_write(cur, value);
128 }
129
130 void write_uleb(uint64_t value) noexcept {
131 reserve(10);
132 write_uleb_unchecked(value);
133 }
134
135 void write_sleb_unchecked(int64_t value) noexcept {
136 // TODO: implement and use sleb_len
137 assert(size_t(end - cur) >= 10);
138 cur += sleb_write(cur, value);
139 }
140
141 void write_sleb(int64_t value) noexcept {
142 reserve(10);
143 write_sleb_unchecked(value);
144 }
145};
146
147} // end namespace tpde::util