akreon-convex
Typed convex modeling, conic canonicalization, and primal-dual optimization in C++26.
Loading...
Searching...
No Matches
fixed_buffer_writer.hpp
Go to the documentation of this file.
1/*
2 * Copyright © 2025-2026 Akreon LLC
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6#pragma once
7
8#include <array>
9#include <cstddef>
10#include <cstdio>
11
12#include "akreon/linalg/assert.hpp"
13#include "akreon/linalg/linalg.hpp"
14
15namespace convex::debug {
16
24 char* out{};
25 std::size_t cap{};
26 std::size_t pos{};
27 bool truncated{};
28
29 constexpr std::size_t size() const { return pos; }
30 constexpr bool ok() const { return !truncated; }
31 constexpr const char* c_str() const { return out; }
32
33 void init() {
34 if (out != nullptr && cap > 0) out[0] = '\0';
35 }
36
37 bool append(const char* text) {
38 return format("%s", text == nullptr ? "" : text);
39 }
40
41 template <typename... Args>
42 bool format(const char* fmt, Args... args) {
43 AK_ASSERT(out != nullptr && "FixedBufferWriter requires non-null output");
44 if (out == nullptr || cap == 0) return false;
45 if (pos >= cap) {
46 out[cap - 1] = '\0';
47 truncated = true;
48 return false;
49 }
50
51 const int bytes = std::snprintf(out + pos, cap - pos, fmt, args...);
52 if (bytes < 0) {
53 out[0] = '\0';
54 pos = 0;
55 truncated = true;
56 return false;
57 }
58
59 const auto n = static_cast<std::size_t>(bytes);
60 if (n >= cap - pos) {
61 pos = cap - 1;
62 out[pos] = '\0';
63 truncated = true;
64 return false;
65 }
66
67 pos += n;
68 return true;
69 }
70};
71
72template <std::size_t N>
73inline FixedBufferWriter make_writer(char (&out)[N]) {
74 FixedBufferWriter w{out, N, 0, false};
75 w.init();
76 return w;
77}
78
79template <linalg::Field T, std::size_t N>
80inline bool append_array_slice(FixedBufferWriter& w, const std::array<T, N>& v,
81 std::size_t size) {
82 if (!w.append("[")) return false;
83 const std::size_t used = (size < N) ? size : N;
84 for (std::size_t i = 0; i < used; ++i) {
85 if (!w.format((i + 1 == used) ? "%g" : "%g, ", static_cast<double>(v[i])))
86 return false;
87 }
88 return w.append("]");
89}
90
91template <linalg::VectorContainer Vec>
92inline bool append_vector(FixedBufferWriter& w, const Vec& v) {
93 if (!w.append("[")) return false;
94 constexpr std::size_t N = linalg::vector_dim_v<Vec>;
95 for (std::size_t i = 0; i < N; ++i) {
96 if (!w.format((i + 1 == N) ? "%g" : "%g, ", static_cast<double>(v(i))))
97 return false;
98 }
99 return w.append("]");
100}
101
102template <linalg::MatrixContainer Mat>
103inline bool append_matrix(FixedBufferWriter& w, const Mat& M) {
104 if (!w.append("[")) return false;
105 constexpr std::size_t Rows = linalg::mat_rows_v<Mat>;
106 constexpr std::size_t Cols = linalg::mat_cols_v<Mat>;
107 for (std::size_t i = 0; i < Rows; ++i) {
108 if (!w.append("[")) return false;
109 for (std::size_t j = 0; j < Cols; ++j) {
110 if (!w.format((j + 1 == Cols) ? "%g" : "%g, ",
111 static_cast<double>(M(i, j))))
112 return false;
113 }
114 if (!w.append((i + 1 == Rows) ? "]" : "],")) return false;
115 }
116 return w.append("]");
117}
118
119template <linalg::VectorContainer Vec>
120inline std::size_t vector_to_cstr(const Vec& v, char* out,
121 std::size_t out_size) {
122 FixedBufferWriter w{out, out_size, 0, false};
123 w.init();
124 append_vector(w, v);
125 return w.size();
126}
127
128template <linalg::MatrixContainer Mat>
129inline std::size_t matrix_to_cstr(const Mat& M, char* out,
130 std::size_t out_size) {
131 FixedBufferWriter w{out, out_size, 0, false};
132 w.init();
133 append_matrix(w, M);
134 return w.size();
135}
136
137} // namespace convex::debug
bool append_vector(FixedBufferWriter &w, const Vec &v)
bool append_array_slice(FixedBufferWriter &w, const std::array< T, N > &v, std::size_t size)
FixedBufferWriter make_writer(char(&out)[N])
std::size_t vector_to_cstr(const Vec &v, char *out, std::size_t out_size)
std::size_t matrix_to_cstr(const Mat &M, char *out, std::size_t out_size)
bool append_matrix(FixedBufferWriter &w, const Mat &M)
constexpr std::size_t dom_size_v
Small no-heap append-only writer for debug formatting.
bool format(const char *fmt, Args... args)
constexpr std::size_t size() const
constexpr const char * c_str() const