56template <
typename Tag>
58 std::declval<value_ref<typename sink_provider_traits<Tag>::context_type>>()))>>
63template <
typename Tag>
91 void (*write)(
void *ctx, microfmt::string_view sv)
noexcept =
nullptr;
96 void (*flush)(
void *ctx)
noexcept =
nullptr;
110 std::enable_if_t<std::is_void_v<typename Traits::context_type>,
int> = 0>
121 template <
typename Tag,
typename Context,
typename Traits = sink_prov
ider_traits<Tag>,
122 std::enable_if_t<!std::is_
void_v<
typename Traits::context_type> &&
123 std::is_convertible_v<Context *,
typename Traits::context_type *>,
125 constexpr sink_provider_ref(Tag, Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
126 : ctx_(&ctx), vtbl_(&s_vtbl<Tag>) {}
130 template <
typename Tag,
typename Context, std::enable_if_t<!std::is_lvalue_reference_v<Context>,
int> = 0>
139 void write(microfmt::string_view sv)
const noexcept {
140 if (vtbl_ !=
nullptr && !sv.empty()) {
141 vtbl_->write(ctx_.get(), sv);
148 [[nodiscard]]
constexpr bool can_flush() const noexcept {
return vtbl_ !=
nullptr && vtbl_->flush !=
nullptr; }
155 vtbl_->flush(ctx_.get());
162 [[nodiscard]]
constexpr explicit operator bool() const noexcept {
return vtbl_ !=
nullptr; }
171 [[nodiscard]]
constexpr sink as_sink() const noexcept RELOCO_LIFETIMEBOUND {
172 return sink{ctx_.get(), vtbl_ !=
nullptr ? vtbl_->write :
nullptr};
176 template <
typename Tag>
static void write_entry(
void *ctx, microfmt::string_view sv)
noexcept {
178 if constexpr (std::is_void_v<context_type>) {
182 auto &typed = *
static_cast<context_type *
>(ctx);
183 sink_provider_traits<Tag>::write(value_ref<context_type>(typed), sv);
187 template <
typename Tag> [[nodiscard]]
static constexpr auto flush_entry() noexcept {
188 using context_type =
typename sink_provider_traits<Tag>::context_type;
189 if constexpr (std::is_void_v<context_type>) {
190 if constexpr (detail::has_stateless_sink_provider_flush<Tag>::value) {
191 return +[](
void *)
noexcept { sink_provider_traits<Tag>::flush(); };
193 return static_cast<void (*)(
void *) noexcept
>(
nullptr);
195 }
else if constexpr (detail::has_sink_provider_flush<Tag>::value) {
196 return +[](
void *ctx)
noexcept {
197 auto &typed = *
static_cast<context_type *
>(ctx);
198 sink_provider_traits<Tag>::flush(value_ref<context_type>(typed));
201 return static_cast<void (*)(
void *) noexcept
>(
nullptr);
205 template <
typename Tag>
static constexpr vtable s_vtbl{&write_entry<Tag>, flush_entry<Tag>()};
207 value_ptr<void> ctx_{};
208 const vtable *vtbl_{
nullptr};
223 static_assert(!std::is_void_v<context_type>,
"sink_provider<Tag> requires a stateful backend; construct "
224 "sink_provider_ref{Tag{}} directly for stateless backends");
245 [[nodiscard]]
constexpr sink as_sink() &
noexcept RELOCO_LIFETIMEBOUND {
247#if defined(__clang__)
248#pragma clang diagnostic push
249#pragma clang diagnostic ignored "-Wreturn-stack-address"
250#pragma clang diagnostic ignored "-Wdangling-gsl"
255#if defined(__clang__)
256#pragma clang diagnostic pop
279 static void write(microfmt::string_view)
noexcept {
303 static void write(value_ref<context_type> ctx, microfmt::string_view sv)
noexcept {
304 const size_t avail = (ctx->pos < ctx->buffer.size()) ? (ctx->buffer.size() - ctx->pos) : 0;
305 const size_t n = std::min(sv.size(), avail);
307 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
308 std::copy_n(sv.data(), n, ctx->buffer.data() + ctx->pos);
309 RELOCO_END_UNSAFE_BUFFER_USAGE;
Type-erased, two-word handle to a sink backend.
Definition sink_provider.hpp:78
constexpr sink_provider_ref(Tag, Context &&)=delete
constexpr bool can_flush() const noexcept
Reports whether the bound backend supports flush.
Definition sink_provider.hpp:148
constexpr sink as_sink() const noexcept RELOCO_LIFETIMEBOUND
Bridges to a plain microfmt::sink, for use with format_to/vformat_to.
Definition sink_provider.hpp:171
constexpr sink_provider_ref() noexcept=default
Constructs an empty (invalid) handle.
void flush() const noexcept
Flushes buffered output. A no-op when can_flush is false.
Definition sink_provider.hpp:153
constexpr sink_provider_ref(Tag, Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
Constructs a handle for a stateful sink tag.
Definition sink_provider.hpp:125
void write(microfmt::string_view sv) const noexcept
Emits a sequence of characters to the underlying sink.
Definition sink_provider.hpp:139
Owning wrapper: holds context_type by value, sharing lifetime with the handle obtained from ref.
Definition sink_provider.hpp:219
constexpr sink_provider(context_type context) noexcept
Constructs the owning wrapper from an already-built context.
Definition sink_provider.hpp:229
typename traits_type::context_type context_type
Definition sink_provider.hpp:222
constexpr sink_provider_ref ref() &noexcept RELOCO_LIFETIMEBOUND
Borrows a sink_provider_ref bound to this wrapper's context.
Definition sink_provider.hpp:238
constexpr sink as_sink() &noexcept RELOCO_LIFETIMEBOUND
Convenience shorthand for ref().as_sink().
Definition sink_provider.hpp:245
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Core formatting primitives, sinks, and customization point.
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
Definition sink_provider.hpp:54
Definition sink_provider.hpp:61
Tag for a stateless sink that discards every write.
Definition sink_provider.hpp:274
Virtual table of sink operations.
Definition sink_provider.hpp:83
static void write(microfmt::string_view) noexcept
Definition sink_provider.hpp:279
void context_type
Definition sink_provider.hpp:277
static void write(value_ref< context_type > ctx, microfmt::string_view sv) noexcept
Definition sink_provider.hpp:303
Static customization point describing a sink backend.
Definition sink_provider.hpp:50
Definition sink_provider.hpp:295
span< char > buffer
Definition sink_provider.hpp:296
Tag for a stateful sink that appends into a fixed-size microfmt::span of character storage,...
Definition sink_provider.hpp:293