microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
remote_hash_table.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_hash_table_traits;
23
24namespace detail {
25
26template <typename Tag> struct remote_hash_table_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 out.write(opts.open_bracket);
33
34 size_t bucket_count = 0;
35 if (!traits_type::get_bucket_count(context, container_addr, space, scratch, bucket_count)) {
36 out.write(opts.close_bracket);
37 return true;
38 }
39
40 size_t print_count = 0;
41 bool stop = false; // set when the print limit is hit or an entry faults
42 for (size_t bucket = 0; bucket < bucket_count && !stop; ++bucket) {
43 uintptr_t current_node = 0;
44 if (!traits_type::get_bucket_head(context, container_addr, space, scratch, bucket, current_node))
45 continue;
46
47 while (current_node != 0) {
48 if (print_count >= opts.max_print) {
49 if (print_count > 0)
50 out.write(opts.entry_separator);
51 out.write("...");
52 stop = true;
53 break;
54 }
55 if (print_count > 0)
56 out.write(opts.entry_separator);
57
58 if (!traits_type::format_entry(context, space, scratch, current_node, opts, out)) {
59 out.write("<fault>");
60 stop = true;
61 break;
62 }
63 ++print_count;
64
65 uintptr_t next_node = 0;
66 if (!traits_type::get_next_node(context, space, scratch, current_node, next_node))
67 break;
68 current_node = next_node;
69 }
70 }
71
72 out.write(opts.close_bracket);
73 return true;
74 }
75};
76
77template <typename Key, typename Value, typename RemotePtr, typename RemoteSize> struct hash_table_layout_tag {};
78
79} // namespace detail
80
82
83template <typename Tag>
84[[nodiscard]] constexpr remote_hash_table<Tag>
85make_remote_hash_table(uintptr_t container_addr,
86 typename remote_hash_table_traits<Tag>::context_type context) noexcept {
87 return remote_hash_table<Tag>(container_addr, std::move(context));
88}
89
90template <typename Key, typename Value, typename RemotePtr, typename RemoteSize>
91struct remote_hash_table_traits<detail::hash_table_layout_tag<Key, Value, RemotePtr, RemoteSize>> {
92 using pointer_query = decltype(make_remote_offset_query<uintptr_t, RemotePtr>(0));
93 using size_query = decltype(make_remote_offset_query<size_t, RemoteSize>(0));
94
102
103 static bool get_bucket_count(value_ref<const context_type> context, uintptr_t container_addr, address_space_ref space,
104 span<std::byte>, size_t &out_count) noexcept {
105 return context->bucket_count(space, container_addr, out_count);
106 }
107
108 static bool get_bucket_head(value_ref<const context_type> context, uintptr_t container_addr, address_space_ref space,
109 span<std::byte>, size_t bucket_index, uintptr_t &out_node_addr) noexcept {
110 uintptr_t buckets_address = 0;
111 if (!context->buckets(space, container_addr, buckets_address))
112 return false;
113 const auto bucket =
114 make_remote_offset_query<uintptr_t, RemotePtr>(static_cast<ptrdiff_t>(bucket_index * sizeof(RemotePtr)));
115 return bucket(space, buckets_address, out_node_addr);
116 }
117
118 static bool get_next_node(value_ref<const context_type> context, address_space_ref space, span<std::byte>,
119 uintptr_t node_addr, uintptr_t &out_next_addr) noexcept {
120 return context->next(space, node_addr, out_next_addr);
121 }
122
123 static bool format_entry(value_ref<const context_type> context, address_space_ref space, span<std::byte> scratch,
124 uintptr_t node_addr, const container_options &opts, const sink &out) noexcept {
125 if (opts.print_key) {
126 const uintptr_t key_addr = detail::add_address_offset(node_addr, context->key_offset);
128 remote_object_view view(key_addr, space, type_tag<Key>{}, scratch);
129 formatter<remote_object_view>().format(view, out);
130 } else {
131 scratch_allocator allocator(scratch);
132 Key *key = allocator.allocate<Key>();
133 if (!key || !space.read_bytes(key_addr, key, sizeof(Key)))
134 return false;
135 formatter<Key>().format(*key, out);
136 }
137 out.write(opts.kv_separator);
138 }
139
140 if (opts.print_value) {
141 const uintptr_t value_addr = detail::add_address_offset(node_addr, context->value_offset);
143 remote_object_view view(value_addr, space, type_tag<Value>{}, scratch);
144 formatter<remote_object_view>().format(view, out);
145 } else {
146 scratch_allocator allocator(scratch);
147 Value *value = allocator.allocate<Value>();
148 if (!value || !space.read_bytes(value_addr, value, sizeof(Value)))
149 return false;
150 formatter<Value>().format(*value, out);
151 }
152 }
153 return true;
154 }
155};
156
160template <typename Key, typename Value, typename RemotePtr = uintptr_t, typename RemoteSize = size_t>
161[[nodiscard]] constexpr auto make_remote_hash_table(uintptr_t container_addr, ptrdiff_t buckets_ptr_offset,
162 ptrdiff_t bucket_count_offset, ptrdiff_t node_next_offset,
163 ptrdiff_t node_key_offset, ptrdiff_t node_value_offset) noexcept {
165 using traits = remote_hash_table_traits<tag>;
166 typename traits::context_type context{make_remote_offset_query<uintptr_t, RemotePtr>(buckets_ptr_offset),
167 make_remote_offset_query<size_t, RemoteSize>(bucket_count_offset),
168 make_remote_offset_query<uintptr_t, RemotePtr>(node_next_offset),
169 node_key_offset, node_value_offset};
170 return remote_hash_table<tag>(container_addr, std::move(context));
171}
172
173} // 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
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
constexpr remote_hash_table< Tag > make_remote_hash_table(uintptr_t container_addr, typename remote_hash_table_traits< Tag >::context_type context) noexcept
Definition remote_hash_table.hpp:85
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
enum RELOCO_FLAG_ENUM stop
Definition i2c.hpp:35
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_hash_table.hpp:77
Definition remote_hash_table.hpp:26
typename traits_type::context_type context_type
Definition remote_hash_table.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_hash_table.hpp:30
Definition microfmt.hpp:985
static bool get_bucket_head(value_ref< const context_type > context, uintptr_t container_addr, address_space_ref space, span< std::byte >, size_t bucket_index, uintptr_t &out_node_addr) noexcept
Definition remote_hash_table.hpp:108
static bool format_entry(value_ref< const context_type > context, address_space_ref space, span< std::byte > scratch, uintptr_t node_addr, const container_options &opts, const sink &out) noexcept
Definition remote_hash_table.hpp:123
static bool get_next_node(value_ref< const context_type > context, address_space_ref space, span< std::byte >, uintptr_t node_addr, uintptr_t &out_next_addr) noexcept
Definition remote_hash_table.hpp:118
static bool get_bucket_count(value_ref< const context_type > context, uintptr_t container_addr, address_space_ref space, span< std::byte >, size_t &out_count) noexcept
Definition remote_hash_table.hpp:103
decltype(make_remote_offset_query< uintptr_t, RemotePtr >(0)) pointer_query
Definition remote_hash_table.hpp:92
decltype(make_remote_offset_query< size_t, RemoteSize >(0)) size_query
Definition remote_hash_table.hpp:93
Static customization point for a remote chained hash table.
Definition remote_hash_table.hpp:22
Traits customization point for remote object metadata.
Definition remote_object.hpp:217
Definition remote_object.hpp:229