microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
remote_basic_string.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Jarosław Pelczar <jarek@jpelczar.com>
2//
3// SPDX-License-Identifier: BSD-2-Clause
4
5#pragma once
6
10#include "address_space.hpp"
12
13#include <cstddef>
14#include <cstdint>
15#include <limits>
16
17namespace microfmt {
18
19namespace detail {
20
21template <typename SizeQuery, typename DataQuery> struct basic_string_query_layout {
22 SizeQuery size_query;
23 DataQuery data_query;
24
25 [[nodiscard]] bool read_size(address_space_ref space, uintptr_t object_address, size_t &size) const noexcept {
26 return size_query(space, object_address, size);
27 }
28
29 [[nodiscard]] bool read_data_address(address_space_ref space, uintptr_t object_address, size_t size,
30 uintptr_t &data_address) const noexcept {
31 return data_query(space, object_address, data_address, size);
32 }
33};
34
35template <typename DataQuery> struct size_selected_data_query {
39
40 [[nodiscard]] bool operator()(address_space_ref space, uintptr_t object_address, uintptr_t &data_address,
41 size_t size) const noexcept {
42 if (size <= inline_capacity) {
43 data_address = add_address_offset(object_address, inline_data_offset);
44 return true;
45 }
46 return allocated_data_query(space, object_address, data_address);
47 }
48};
49
50} // namespace detail
51
62template <typename Layout> class RELOCO_POINTER remote_basic_string_view {
63public:
72 constexpr remote_basic_string_view(uintptr_t object_address, address_space_ref space,
73 span<char> scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS,
74 Layout layout, size_t max_limit = 4096) noexcept
75 : object_address_(object_address), space_(space), scratch_(scratch), layout_(layout), max_limit_(max_limit) {}
76
80 template <size_t N>
81 constexpr remote_basic_string_view(uintptr_t object_address, address_space_ref space,
82 char (&scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS)[N],
83 Layout layout, size_t max_limit = 4096) noexcept
84 : object_address_(object_address), space_(space), scratch_(scratch, N), layout_(layout), max_limit_(max_limit) {}
85
86 [[nodiscard]] constexpr uintptr_t object_address() const noexcept { return object_address_; }
87
88 [[nodiscard]] constexpr address_space_ref space() const noexcept { return space_; }
89
90 [[nodiscard]] constexpr span<char> scratch() const noexcept RELOCO_LIFETIMEBOUND { return scratch_; }
91
92 [[nodiscard]] constexpr size_t max_limit() const noexcept { return max_limit_; }
93
94 [[nodiscard]] bool resolve(uintptr_t &data_address, size_t &size) const noexcept {
95 return layout_.read_size(space_, object_address_, size) &&
96 layout_.read_data_address(space_, object_address_, size, data_address);
97 }
98
99private:
100 uintptr_t object_address_{0};
101 address_space_ref space_{};
102 span<char> scratch_{};
103 Layout layout_;
104 size_t max_limit_{4096};
105};
106
110template <typename Layout>
111[[nodiscard]] constexpr auto make_remote_basic_string_view(uintptr_t object_address, address_space_ref space,
112 span<char> scratch, Layout layout,
113 size_t max_limit = 4096) noexcept {
114 return remote_basic_string_view<Layout>(object_address, space, scratch, layout, max_limit);
115}
116
117template <typename Layout, size_t N>
118[[nodiscard]] constexpr auto make_remote_basic_string_view(uintptr_t object_address, address_space_ref space,
119 char (&scratch)[N], Layout layout,
120 size_t max_limit = 4096) noexcept {
121 return remote_basic_string_view<Layout>(object_address, space, scratch, layout, max_limit);
122}
123
134 template <typename SizeReader, typename DataReader>
135 [[nodiscard]] static constexpr auto callback_layout(SizeReader size_reader, DataReader data_reader) noexcept {
136 auto size_query = make_remote_layout_query<size_t>(size_reader);
137 auto data_query = make_remote_layout_query<uintptr_t>(data_reader);
138 return detail::basic_string_query_layout<decltype(size_query), decltype(data_query)>{size_query, data_query};
139 }
140
147 template <typename RemotePtr = uintptr_t, typename RemoteSize = size_t>
148 [[nodiscard]] static constexpr auto pointer_size_layout(ptrdiff_t data_offset, ptrdiff_t size_offset) noexcept {
149 auto size_query = make_remote_offset_query<size_t, RemoteSize>(size_offset);
150 auto data_query = make_remote_offset_query<uintptr_t, RemotePtr>(data_offset);
151 return detail::basic_string_query_layout<decltype(size_query), decltype(data_query)>{size_query, data_query};
152 }
153
160 template <typename RemotePtr = uintptr_t, typename RemoteSize = size_t>
161 [[nodiscard]] static constexpr auto size_selected_layout(ptrdiff_t data_offset, ptrdiff_t size_offset,
162 ptrdiff_t inline_data_offset,
163 size_t inline_capacity) noexcept {
164 auto size_query = make_remote_offset_query<size_t, RemoteSize>(size_offset);
165 auto allocated_data_query = make_remote_offset_query<uintptr_t, RemotePtr>(data_offset);
166 auto data_reader = detail::size_selected_data_query<decltype(allocated_data_query)>{
167 allocated_data_query, inline_data_offset, inline_capacity};
168 auto data_query = make_remote_layout_query<uintptr_t>(data_reader);
169 return detail::basic_string_query_layout<decltype(size_query), decltype(data_query)>{size_query, data_query};
170 }
171};
172
173template <typename Layout> struct formatter<remote_basic_string_view<Layout>> {
174 constexpr void parse(format_parse_context &) noexcept {}
175
176 void format(const remote_basic_string_view<Layout> &view, const sink &out) const noexcept {
177 if (view.object_address() == 0) {
178 out.write("(null)");
179 return;
180 }
181 if (!view.space()) {
182 microfmt::format_to(out, "<invalid-space@{:#x}>", view.object_address());
183 return;
184 }
185
186 uintptr_t data_address = 0;
187 size_t size = 0;
188 if (!view.resolve(data_address, size)) {
189 microfmt::format_to(out, "<fault@{:#x}>", view.object_address());
190 return;
191 }
192 if (size == 0)
193 return;
194 if (data_address == 0) {
195 microfmt::format_to(out, "<fault@{:#x}>", view.object_address());
196 return;
197 }
198
199 const size_t render_size = size < view.max_limit() ? size : view.max_limit();
200 const auto scratch = view.scratch();
201 if (render_size != 0 && scratch.empty()) {
202 microfmt::format_to(out, "<invalid-space@{:#x}>", view.object_address());
203 return;
204 }
205
206 size_t total = 0;
207 while (total < render_size) {
208 const size_t remaining = render_size - total;
209 const size_t chunk_size = remaining < scratch.size() ? remaining : scratch.size();
210 if (data_address > std::numeric_limits<uintptr_t>::max() - total ||
211 !view.space().read_bytes(data_address + total, scratch.data(), chunk_size)) {
212 if (total == 0) {
213 microfmt::format_to(out, "<fault@{:#x}>", data_address);
214 } else {
215 out.write("<fault>");
216 }
217 return;
218 }
219 out.write(microfmt::string_view(scratch.data(), chunk_size));
220 total += chunk_size;
221 }
222
223 if (size > view.max_limit())
224 out.write("...");
225 }
226};
227
228} // namespace microfmt
Type-erased remote address-space access and remote string/object views.
Type-erased, two-word handle to a remote address space.
Definition address_space.hpp:204
Definition microfmt.hpp:881
Length-aware view over a remote C++ string object.
Definition remote_basic_string.hpp:62
constexpr span< char > scratch() const noexcept RELOCO_LIFETIMEBOUND
Definition remote_basic_string.hpp:90
constexpr size_t max_limit() const noexcept
Definition remote_basic_string.hpp:92
constexpr address_space_ref space() const noexcept
Definition remote_basic_string.hpp:88
bool resolve(uintptr_t &data_address, size_t &size) const noexcept
Definition remote_basic_string.hpp:94
constexpr remote_basic_string_view(uintptr_t object_address, address_space_ref space, span< char > scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS, Layout layout, size_t max_limit=4096) noexcept
Constructs a view over a remote string object.
Definition remote_basic_string.hpp:72
constexpr remote_basic_string_view(uintptr_t object_address, address_space_ref space, char(&scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS)[N], Layout layout, size_t max_limit=4096) noexcept
Constructs a view using a fixed C array as scratch storage.
Definition remote_basic_string.hpp:81
constexpr uintptr_t object_address() const noexcept
Definition remote_basic_string.hpp:86
#define MICROFMT_API_CLASS
Definition compat.hpp:181
RELOCO_BEGIN_UNSAFE_CODE constexpr uintptr_t add_address_offset(uintptr_t address, ptrdiff_t offset) noexcept
Definition address_space.hpp:52
Definition assert.hpp:19
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
RELOCO_CONSTEXPR20 void format_to(const sink &out, microfmt::string_view fmt, const Args &...args) noexcept
Definition microfmt.hpp:1766
constexpr auto make_remote_basic_string_view(uintptr_t object_address, address_space_ref space, span< char > scratch, Layout layout, size_t max_limit=4096) noexcept
Creates a length-aware remote string view with template deduction.
Definition remote_basic_string.hpp:111
Reusable callback and typed-offset accessors for remote layouts.
Definition remote_basic_string.hpp:21
bool read_data_address(address_space_ref space, uintptr_t object_address, size_t size, uintptr_t &data_address) const noexcept
Definition remote_basic_string.hpp:29
SizeQuery size_query
Definition remote_basic_string.hpp:22
DataQuery data_query
Definition remote_basic_string.hpp:23
bool read_size(address_space_ref space, uintptr_t object_address, size_t &size) const noexcept
Definition remote_basic_string.hpp:25
Definition remote_basic_string.hpp:35
bool operator()(address_space_ref space, uintptr_t object_address, uintptr_t &data_address, size_t size) const noexcept
Definition remote_basic_string.hpp:40
ptrdiff_t inline_data_offset
Definition remote_basic_string.hpp:37
DataQuery allocated_data_query
Definition remote_basic_string.hpp:36
size_t inline_capacity
Definition remote_basic_string.hpp:38
constexpr void parse(format_parse_context &) noexcept
Definition remote_basic_string.hpp:174
void format(const remote_basic_string_view< Layout > &view, const sink &out) const noexcept
Definition remote_basic_string.hpp:176
Definition microfmt.hpp:985
Factories for common remote C++ string object layouts.
Definition remote_basic_string.hpp:127
static constexpr auto pointer_size_layout(ptrdiff_t data_offset, ptrdiff_t size_offset) noexcept
Creates a layout whose object always stores a data pointer and size.
Definition remote_basic_string.hpp:148
static constexpr auto size_selected_layout(ptrdiff_t data_offset, ptrdiff_t size_offset, ptrdiff_t inline_data_offset, size_t inline_capacity) noexcept
Creates a layout selected by the decoded string length.
Definition remote_basic_string.hpp:161
static constexpr auto callback_layout(SizeReader size_reader, DataReader data_reader) noexcept
Creates a layout from explicit size and data-address readers.
Definition remote_basic_string.hpp:135