Skip to content

Commit c6fe0b3

Browse files
committed
feat: initialize rix debug package
1 parent 2427059 commit c6fe0b3

13 files changed

Lines changed: 692 additions & 37 deletions

File tree

.gitignore

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,12 @@
1-
# Prerequisites
2-
*.d
1+
build*/
2+
.vix/
3+
.cache/
34

4-
# Compiled Object files
5-
*.slo
6-
*.lo
75
*.o
86
*.obj
9-
10-
# Precompiled Headers
11-
*.gch
12-
*.pch
13-
14-
# Linker files
15-
*.ilk
16-
17-
# Debugger Files
18-
*.pdb
19-
20-
# Compiled Dynamic libraries
21-
*.so
22-
*.dylib
23-
*.dll
24-
25-
# Fortran module files
26-
*.mod
27-
*.smod
28-
29-
# Compiled Static libraries
30-
*.lai
31-
*.la
327
*.a
338
*.lib
34-
35-
# Executables
9+
*.so
10+
*.dll
11+
*.dylib
3612
*.exe
37-
*.out
38-
*.app
39-
40-
# debug information files
41-
*.dwo

CMakeLists.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
3+
project(rix_debug
4+
VERSION 0.1.0
5+
DESCRIPTION "Debug printing, formatting, logging, and inspection utilities for Rix"
6+
LANGUAGES CXX
7+
)
8+
9+
option(RIX_DEBUG_BUILD_EXAMPLES "Build rix/debug examples" ON)
10+
option(RIX_DEBUG_BUILD_TESTS "Build rix/debug tests" ON)
11+
12+
add_library(rix_debug INTERFACE)
13+
add_library(rix::debug ALIAS rix_debug)
14+
15+
target_compile_features(rix_debug INTERFACE cxx_std_20)
16+
17+
target_include_directories(rix_debug
18+
INTERFACE
19+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
20+
$<INSTALL_INTERFACE:include>
21+
)
22+
23+
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
24+
if(RIX_DEBUG_BUILD_EXAMPLES)
25+
add_subdirectory(examples)
26+
endif()
27+
28+
if(RIX_DEBUG_BUILD_TESTS)
29+
enable_testing()
30+
add_subdirectory(tests)
31+
endif()
32+
endif()

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
# rix-thread
2-
Thread and synchronization utilities: thread creation, mutex, lock, and condition variables.
1+
# Debug
2+
3+
Debug printing, formatting, logging, and inspection utilities for Rix.

examples/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
add_executable(rix_debug_basic
2+
basic.cpp
3+
)
4+
5+
target_link_libraries(rix_debug_basic
6+
PRIVATE
7+
rix::debug
8+
)

examples/basic.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* @file basic.cpp
3+
* @brief Basic example for rix/debug.
4+
*/
5+
6+
#include <rix/debug.hpp>
7+
8+
int main()
9+
{
10+
rixlib::debug::Debug debug;
11+
12+
debug.print("Hello {}", "Rix");
13+
14+
auto text = debug.format("Package: {}", "rix/debug");
15+
16+
debug.log("loaded {} rows", 3);
17+
debug.log.warn("slow request: {}ms", 120);
18+
19+
debug.inspect(text);
20+
21+
return 0;
22+
}

include/rix/debug.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @file debug.hpp
3+
* @brief Unified debug module for Rix.
4+
*/
5+
6+
#ifndef RIXCPP_DEBUG_INCLUDE_RIX_DEBUG_HPP_INCLUDED
7+
#define RIXCPP_DEBUG_INCLUDE_RIX_DEBUG_HPP_INCLUDED
8+
9+
#include <rix/debug/format.hpp>
10+
#include <rix/debug/inspect.hpp>
11+
#include <rix/debug/log.hpp>
12+
#include <rix/debug/print.hpp>
13+
14+
namespace rixlib::debug
15+
{
16+
class Debug
17+
{
18+
public:
19+
Format format{};
20+
Print print{};
21+
Log log{};
22+
Inspect inspect{};
23+
};
24+
}
25+
26+
#endif // RIXCPP_DEBUG_INCLUDE_RIX_DEBUG_HPP_INCLUDED

include/rix/debug/format.hpp

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
/**
2+
* @file format.hpp
3+
* @brief Placeholder-based formatting API for rix/debug.
4+
*/
5+
6+
#ifndef RIXCPP_DEBUG_INCLUDE_RIX_DEBUG_FORMAT_HPP_INCLUDED
7+
#define RIXCPP_DEBUG_INCLUDE_RIX_DEBUG_FORMAT_HPP_INCLUDED
8+
9+
#include <array>
10+
#include <cstddef>
11+
#include <sstream>
12+
#include <stdexcept>
13+
#include <string>
14+
#include <string_view>
15+
#include <type_traits>
16+
17+
namespace rixlib::debug
18+
{
19+
class FormatError : public std::runtime_error
20+
{
21+
public:
22+
explicit FormatError(const std::string &message)
23+
: std::runtime_error(message)
24+
{
25+
}
26+
27+
explicit FormatError(const char *message)
28+
: std::runtime_error(message)
29+
{
30+
}
31+
};
32+
33+
namespace detail
34+
{
35+
template <typename T>
36+
[[nodiscard]] std::string render_value(const T &value)
37+
{
38+
std::ostringstream stream;
39+
40+
if constexpr (std::is_same_v<std::remove_cvref_t<T>, bool>)
41+
{
42+
stream << (value ? "true" : "false");
43+
}
44+
else
45+
{
46+
stream << value;
47+
}
48+
49+
return stream.str();
50+
}
51+
52+
class RenderedArgs
53+
{
54+
public:
55+
template <std::size_t N>
56+
explicit RenderedArgs(const std::array<std::string, N> &values) noexcept
57+
: data_(values.data()), size_(N)
58+
{
59+
}
60+
61+
[[nodiscard]] std::size_t size() const noexcept
62+
{
63+
return size_;
64+
}
65+
66+
[[nodiscard]] const std::string &at(std::size_t index) const
67+
{
68+
if (index >= size_)
69+
{
70+
throw FormatError("format argument index out of range");
71+
}
72+
73+
return data_[index];
74+
}
75+
76+
private:
77+
const std::string *data_{nullptr};
78+
std::size_t size_{0};
79+
};
80+
81+
[[nodiscard]] inline std::size_t parse_index(std::string_view text)
82+
{
83+
if (text.empty())
84+
{
85+
throw FormatError("empty explicit format index");
86+
}
87+
88+
std::size_t value = 0;
89+
90+
for (char ch : text)
91+
{
92+
if (ch < '0' || ch > '9')
93+
{
94+
throw FormatError("invalid explicit format index");
95+
}
96+
97+
value = (value * 10u) + static_cast<std::size_t>(ch - '0');
98+
}
99+
100+
return value;
101+
}
102+
103+
inline void render_format_string(
104+
std::string &out,
105+
std::string_view fmt,
106+
const RenderedArgs &args)
107+
{
108+
std::size_t i = 0;
109+
std::size_t next_auto_index = 0;
110+
bool used_auto_index = false;
111+
bool used_explicit_index = false;
112+
113+
while (i < fmt.size())
114+
{
115+
const char ch = fmt[i];
116+
117+
if (ch == '{')
118+
{
119+
if ((i + 1u) < fmt.size() && fmt[i + 1u] == '{')
120+
{
121+
out.push_back('{');
122+
i += 2u;
123+
continue;
124+
}
125+
126+
const std::size_t close = fmt.find('}', i + 1u);
127+
128+
if (close == std::string_view::npos)
129+
{
130+
throw FormatError("unmatched '{' in format string");
131+
}
132+
133+
const std::string_view token = fmt.substr(i + 1u, close - (i + 1u));
134+
135+
if (token.empty())
136+
{
137+
if (used_explicit_index)
138+
{
139+
throw FormatError("cannot mix automatic and explicit format indexes");
140+
}
141+
142+
used_auto_index = true;
143+
out += args.at(next_auto_index++);
144+
}
145+
else
146+
{
147+
if (used_auto_index)
148+
{
149+
throw FormatError("cannot mix automatic and explicit format indexes");
150+
}
151+
152+
if (token.find(':') != std::string_view::npos)
153+
{
154+
throw FormatError("format specifiers are not supported yet");
155+
}
156+
157+
used_explicit_index = true;
158+
out += args.at(parse_index(token));
159+
}
160+
161+
i = close + 1u;
162+
continue;
163+
}
164+
165+
if (ch == '}')
166+
{
167+
if ((i + 1u) < fmt.size() && fmt[i + 1u] == '}')
168+
{
169+
out.push_back('}');
170+
i += 2u;
171+
continue;
172+
}
173+
174+
throw FormatError("single '}' encountered in format string");
175+
}
176+
177+
out.push_back(ch);
178+
++i;
179+
}
180+
}
181+
182+
[[nodiscard]] inline std::size_t estimate_output_size(
183+
std::string_view fmt,
184+
const RenderedArgs &args)
185+
{
186+
std::size_t total = fmt.size();
187+
188+
for (std::size_t i = 0; i < args.size(); ++i)
189+
{
190+
total += args.at(i).size();
191+
}
192+
193+
return total;
194+
}
195+
}
196+
197+
class Format
198+
{
199+
public:
200+
template <typename... Args>
201+
[[nodiscard]] std::string operator()(std::string_view fmt, const Args &...args) const
202+
{
203+
std::array<std::string, sizeof...(Args)> rendered_args{
204+
detail::render_value(args)...};
205+
206+
const detail::RenderedArgs rendered{rendered_args};
207+
208+
std::string output;
209+
output.reserve(detail::estimate_output_size(fmt, rendered));
210+
detail::render_format_string(output, fmt, rendered);
211+
212+
return output;
213+
}
214+
215+
template <typename... Args>
216+
void append(std::string &out, std::string_view fmt, const Args &...args) const
217+
{
218+
out += operator()(fmt, args...);
219+
}
220+
221+
template <typename... Args>
222+
void to(std::string &out, std::string_view fmt, const Args &...args) const
223+
{
224+
out.clear();
225+
append(out, fmt, args...);
226+
}
227+
};
228+
}
229+
230+
#endif // RIXCPP_DEBUG_INCLUDE_RIX_DEBUG_FORMAT_HPP_INCLUDED

0 commit comments

Comments
 (0)