microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
pointer.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
17#include "../microfmt.hpp"
18#include <cstddef>
19#include <cstdint>
20#include <limits>
21#include <string_view>
22#include <type_traits>
23
24namespace microfmt {
25
27enum class ptr_width_mode : uint8_t {
28 native = 0, // 8 hex digits on 32-bit arch, 16 on 64-bit arch
29 compat32, // Always 8 hex digits (32-bit address space, e.g. ARM Cortex-M /
30 // RISC-V 32)
31 compat64 // Always 16 hex digits
32};
33
36 uintptr_t address{0};
37 bool is_null{false};
38 ptr_width_mode width_mode{ptr_width_mode::native};
39};
40
42// low-level formatting: raw character pointers and integer width conversions bounded by the buffer sizes checked here.
43RELOCO_BEGIN_UNSAFE_CODE
44template <typename T>
46[[nodiscard]] constexpr raw_ptr_view raw_ptr(const T *ptr, ptr_width_mode mode = ptr_width_mode::native) noexcept {
47 return raw_ptr_view{reinterpret_cast<uintptr_t>(ptr), ptr == nullptr, mode};
48}
50
53[[nodiscard]] constexpr raw_ptr_view raw_ptr(std::nullptr_t, ptr_width_mode mode = ptr_width_mode::native) noexcept {
54 return raw_ptr_view{0, true, mode};
55}
56
57[[nodiscard]] constexpr raw_ptr_view raw_ptr(uintptr_t addr, ptr_width_mode mode = ptr_width_mode::native) noexcept {
58 return raw_ptr_view{addr, addr == 0, mode};
59}
60
62template <typename T> [[nodiscard]] constexpr raw_ptr_view raw_ptr32(const T *ptr) noexcept {
64}
65
67[[nodiscard]] constexpr raw_ptr_view raw_ptr32(std::nullptr_t) noexcept {
68 return raw_ptr(nullptr, ptr_width_mode::compat32);
69}
70
72[[nodiscard]] constexpr raw_ptr_view raw_ptr32(uintptr_t addr) noexcept {
74}
75
77template <typename T> struct RELOCO_POINTER raw_range_view {
78 const T *begin_ptr{nullptr};
79 const T *end_ptr{nullptr};
80 microfmt::string_view separator{", "};
81 char open_delim{'['};
82 char close_delim{']'};
83
86 [[nodiscard]] constexpr size_t size() const noexcept {
87 if (begin_ptr == nullptr || end_ptr == nullptr || end_ptr < begin_ptr) {
88 return 0;
89 }
90 return static_cast<size_t>(end_ptr - begin_ptr);
91 }
92};
93
96template <typename T> [[nodiscard]] constexpr raw_range_view<T> raw_range(const T *first, const T *last) noexcept {
97 return raw_range_view<T>{first, last};
98}
99
102template <typename T> [[nodiscard]] constexpr raw_range_view<T> raw_range(const T *first, size_t count) noexcept {
103 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
104
105 return raw_range_view<T>{first, first ? first + count : nullptr};
106
107 RELOCO_END_UNSAFE_BUFFER_USAGE;
108}
109
117template <> struct formatter<raw_ptr_view> {
118 static constexpr size_t native_hex_width = sizeof(uintptr_t) * 2;
119
120 bool uppercase_hex{false};
121 bool show_prefix{true};
123 size_t custom_width{0};
124 microfmt::string_view null_representation{"(nil)"};
125
127
128 MICROFMT_API void format(const raw_ptr_view &ptr, const sink &out) const noexcept;
129};
130
131#if MICROFMT_SHARED_PROVIDE_DEFINITIONS
132#include "pointer.ipp"
133#endif
134
140template <typename T> struct formatter<raw_range_view<T>> {
141 char open_c{'['};
142 char close_c{']'};
143 microfmt::string_view forwarded_spec{""};
144
145 constexpr void parse(format_parse_context &ctx) noexcept {
146 auto spec = ctx.spec();
147 if (spec.empty())
148 return;
149
150 size_t i = 0;
151 if (spec[0] == 'b' || spec[0] == 'B') {
152 open_c = '[';
153 close_c = ']';
154 i = 1;
155 } else if (spec[0] == 'c' || spec[0] == 'C') {
156 open_c = '{';
157 close_c = '}';
158 i = 1;
159 } else if (spec[0] == 'n' || spec[0] == 'N') {
160 open_c = '\0';
161 close_c = '\0';
162 i = 1;
163 }
164
165 forwarded_spec = spec.substr(i);
166 }
167
168 void format(const raw_range_view<T> &range, const sink &out) const noexcept {
169 if (open_c != '\0') {
170 out.put(open_c);
171 }
172
173 formatter<T> elem_fmt;
174 format_parse_context elem_ctx(forwarded_spec);
175 elem_fmt.parse(elem_ctx);
176
177 const size_t count = range.size();
178 for (size_t idx = 0; idx < count; ++idx) {
179 if (idx > 0) {
180 out.write(range.separator);
181 }
182 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
183 RELOCO_DEBUG_ASSERT(range.begin_ptr + idx < range.end_ptr, "Index out of range");
184 elem_fmt.format(range.begin_ptr[idx], out);
185 RELOCO_END_UNSAFE_BUFFER_USAGE;
186 }
187
188 if (close_c != '\0') {
189 out.put(close_c);
190 }
191 }
192};
193
194} // namespace microfmt
Definition microfmt.hpp:881
#define MICROFMT_API_CLASS
Definition compat.hpp:181
#define MICROFMT_API
Definition compat.hpp:135
#define MICROFMT_API_CONSTEXPR
Definition compat.hpp:163
Definition assert.hpp:19
ptr_width_mode
Definition pointer.hpp:27
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
constexpr raw_ptr_view raw_ptr32(const T *ptr) noexcept
Definition pointer.hpp:62
RELOCO_BEGIN_UNSAFE_CODE constexpr raw_ptr_view raw_ptr(const T *ptr, ptr_width_mode mode=ptr_width_mode::native) noexcept
Definition pointer.hpp:46
constexpr raw_range_view< T > raw_range(const T *first, const T *last) noexcept
Definition pointer.hpp:96
RELOCO_END_UNSAFE_CODE
Definition remote_object.hpp:132
MICROFMT_API_CONSTEXPR void parse(format_parse_context &ctx) noexcept
MICROFMT_API void format(const raw_ptr_view &ptr, const sink &out) const noexcept
constexpr void parse(format_parse_context &ctx) noexcept
Definition pointer.hpp:145
void format(const raw_range_view< T > &range, const sink &out) const noexcept
Definition pointer.hpp:168
Definition microfmt.hpp:985
Definition pointer.hpp:35
Definition pointer.hpp:77
constexpr size_t size() const noexcept
Definition pointer.hpp:86