microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
remote_vector.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 "remote_container.hpp"
12#include "remote_object.hpp"
13
14namespace microfmt {
15
22template <typename Tag> struct remote_vector_traits;
23
24namespace detail {
25
26template <typename Tag> struct remote_vector_dispatch {
28 using context_type = typename traits_type::context_type;
29
30 static bool format(value_ref<const context_type> context, uintptr_t container_addr, const container_options &opts,
31 address_space_ref space, span<std::byte> scratch, const sink &out) noexcept {
32 size_t size = 0;
33 if (!traits_type::get_size(context, container_addr, space, scratch, size)) {
34 out.write(opts.open_bracket);
35 out.write(opts.close_bracket);
36 return true;
37 }
38
39 out.write(opts.open_bracket);
40 const size_t print_count = size < opts.max_print ? size : opts.max_print;
41 for (size_t index = 0; index < print_count; ++index) {
42 if (index > 0)
43 out.write(opts.entry_separator);
44
45 uintptr_t element_addr = 0;
46 if (!traits_type::get_element_address(context, container_addr, space, scratch, index, element_addr) ||
47 !traits_type::format_element(context, space, scratch, element_addr, out)) {
48 out.write("<fault>");
49 break;
50 }
51 }
52
53 if (size > opts.max_print) {
54 out.write(opts.entry_separator);
55 out.write("...");
56 }
57 out.write(opts.close_bracket);
58 return true;
59 }
60};
61
62template <typename T, typename RemotePtr, typename RemoteSize> struct vector_layout_tag {};
63template <typename T> struct carray_layout_tag {};
64
65template <typename T>
66bool format_remote_vector_element(address_space_ref space, span<std::byte> scratch, uintptr_t element_addr,
67 const sink &out) noexcept {
69 remote_object_view view(element_addr, space, type_tag<T>{}, scratch);
70 formatter<remote_object_view>().format(view, out);
71 } else {
72 scratch_allocator allocator(scratch);
73 T *value = allocator.allocate<T>();
74 if (!value || !space.read_bytes(element_addr, value, sizeof(T)))
75 return false;
76 formatter<T>().format(*value, out);
77 }
78 return true;
79}
80
81} // namespace detail
82
84
85template <typename Tag>
86[[nodiscard]] constexpr remote_vector<Tag>
87make_remote_vector(uintptr_t container_addr, typename remote_vector_traits<Tag>::context_type context) noexcept {
88 return remote_vector<Tag>(container_addr, std::move(context));
89}
90
91template <typename T, typename RemotePtr, typename RemoteSize>
92struct remote_vector_traits<detail::vector_layout_tag<T, RemotePtr, RemoteSize>> {
93 using pointer_query = decltype(make_remote_offset_query<uintptr_t, RemotePtr>(0));
94 using size_query = decltype(make_remote_offset_query<size_t, RemoteSize>(0));
95
102
103 static bool get_size(value_ref<const context_type> context, uintptr_t container_addr, address_space_ref space,
104 span<std::byte>, size_t &out_size) noexcept {
105 return context->size(space, container_addr, out_size);
106 }
107
108 static bool get_capacity(value_ref<const context_type> context, uintptr_t container_addr, address_space_ref space,
109 span<std::byte>, size_t &out_capacity) noexcept {
110 return context->has_capacity && context->capacity(space, container_addr, out_capacity);
111 }
112
113 static bool get_element_address(value_ref<const context_type> context, uintptr_t container_addr,
114 address_space_ref space, span<std::byte>, size_t index,
115 uintptr_t &out_element_addr) noexcept {
116 uintptr_t data_address = 0;
117 if (!context->data(space, container_addr, data_address))
118 return false;
119 out_element_addr = data_address + index * sizeof(T);
120 return true;
121 }
122
123 static bool format_element(value_ref<const context_type>, address_space_ref space, span<std::byte> scratch,
124 uintptr_t element_addr, const sink &out) noexcept {
125 return detail::format_remote_vector_element<T>(space, scratch, element_addr, out);
126 }
127};
128
129template <typename T> struct remote_vector_traits<detail::carray_layout_tag<T>> {
130 struct context_type {
131 size_t count;
132 };
133
134 static bool get_size(value_ref<const context_type> context, uintptr_t, address_space_ref, span<std::byte>,
135 size_t &out_size) noexcept {
136 out_size = context->count;
137 return true;
138 }
139
140 static bool get_element_address(value_ref<const context_type> context, uintptr_t container_addr, address_space_ref,
141 span<std::byte>, size_t index, uintptr_t &out_element_addr) noexcept {
142 if (index >= context->count)
143 return false;
144 out_element_addr = container_addr + index * sizeof(T);
145 return true;
146 }
147
148 static bool format_element(value_ref<const context_type>, address_space_ref space, span<std::byte> scratch,
149 uintptr_t element_addr, const sink &out) noexcept {
150 return detail::format_remote_vector_element<T>(space, scratch, element_addr, out);
151 }
152};
153
157template <typename T, typename RemotePtr = uintptr_t, typename RemoteSize = size_t>
158[[nodiscard]] constexpr auto make_remote_vector(uintptr_t container_addr, ptrdiff_t data_offset, ptrdiff_t size_offset,
159 ptrdiff_t capacity_offset = -1) noexcept {
161 using traits = remote_vector_traits<tag>;
162 typename traits::context_type context{make_remote_offset_query<uintptr_t, RemotePtr>(data_offset),
163 make_remote_offset_query<size_t, RemoteSize>(size_offset),
164 make_remote_offset_query<size_t, RemoteSize>(capacity_offset),
165 capacity_offset >= 0};
166 return remote_vector<tag>(container_addr, std::move(context));
167}
168
172template <typename T> [[nodiscard]] constexpr auto make_remote_carray(uintptr_t array_addr, size_t count) noexcept {
174 return remote_vector<tag>(array_addr, typename remote_vector_traits<tag>::context_type{count});
175}
176
177} // namespace microfmt
Type-erased, two-word handle to a remote address space.
Definition address_space.hpp:204
Owning typed container bound to a compile-time traits dispatcher.
Definition remote_container.hpp:102
Definition remote_object.hpp:231
Zero-allocation bump allocator for scratch buffers.
Definition scratch_allocator.hpp:27
bool format_remote_vector_element(address_space_ref space, span< std::byte > scratch, uintptr_t element_addr, const sink &out) noexcept
Definition remote_vector.hpp:66
Definition assert.hpp:19
constexpr remote_vector< Tag > make_remote_vector(uintptr_t container_addr, typename remote_vector_traits< Tag >::context_type context) noexcept
Definition remote_vector.hpp:87
constexpr auto make_remote_carray(uintptr_t array_addr, size_t count) noexcept
Creates a vector inspector for a fixed-size remote C array.
Definition remote_vector.hpp:172
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
Type-erased views and contexts for formatting remote containers.
Reusable callback and typed-offset accessors for remote layouts.
Remote object dumping, layout macros, and string pointer wrappers with 32-bit compatibility support.
Configuration options for formatting container views.
Definition remote_container.hpp:25
Definition remote_vector.hpp:63
Definition remote_vector.hpp:26
typename traits_type::context_type context_type
Definition remote_vector.hpp:28
static bool format(value_ref< const context_type > context, uintptr_t container_addr, const container_options &opts, address_space_ref space, span< std::byte > scratch, const sink &out) noexcept
Definition remote_vector.hpp:30
Definition remote_vector.hpp:62
Definition microfmt.hpp:985
Traits customization point for remote object metadata.
Definition remote_object.hpp:217
static bool get_size(value_ref< const context_type > context, uintptr_t, address_space_ref, span< std::byte >, size_t &out_size) noexcept
Definition remote_vector.hpp:134
static bool format_element(value_ref< const context_type >, address_space_ref space, span< std::byte > scratch, uintptr_t element_addr, const sink &out) noexcept
Definition remote_vector.hpp:148
static bool get_element_address(value_ref< const context_type > context, uintptr_t container_addr, address_space_ref, span< std::byte >, size_t index, uintptr_t &out_element_addr) noexcept
Definition remote_vector.hpp:140
static bool get_capacity(value_ref< const context_type > context, uintptr_t container_addr, address_space_ref space, span< std::byte >, size_t &out_capacity) noexcept
Definition remote_vector.hpp:108
decltype(make_remote_offset_query< size_t, RemoteSize >(0)) size_query
Definition remote_vector.hpp:94
decltype(make_remote_offset_query< uintptr_t, RemotePtr >(0)) pointer_query
Definition remote_vector.hpp:93
static bool get_size(value_ref< const context_type > context, uintptr_t container_addr, address_space_ref space, span< std::byte >, size_t &out_size) noexcept
Definition remote_vector.hpp:103
static bool format_element(value_ref< const context_type >, address_space_ref space, span< std::byte > scratch, uintptr_t element_addr, const sink &out) noexcept
Definition remote_vector.hpp:123
static bool get_element_address(value_ref< const context_type > context, uintptr_t container_addr, address_space_ref space, span< std::byte >, size_t index, uintptr_t &out_element_addr) noexcept
Definition remote_vector.hpp:113
Static customization point for a remote vector implementation.
Definition remote_vector.hpp:22
Definition remote_object.hpp:229