Skip to content

Commit 333580d

Browse files
committed
conversion: fix to_string overload resolution and document module
- Fix template overload conflict between integral and floating to_string - Make bool and enum conversions unambiguous - Document conversion module with clear API overview and examples - Align README with Vix conversion design (expected-based, no exceptions)
1 parent 64e6867 commit 333580d

2 files changed

Lines changed: 250 additions & 18 deletions

File tree

README.md

Lines changed: 241 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,241 @@
1-
# conversion
2-
Low-level, zero-overhead type conversion utilities for C++ (string to int, enum, bool, etc.) with explicit error handling.
1+
# Vix Conversion
2+
3+
The **conversion module** provides fast, explicit, and allocation-aware helpers
4+
to convert **strings to typed values** and **typed values to strings** in C++.
5+
6+
It is designed as a low-level building block for:
7+
- parsers
8+
- configuration systems
9+
- CLI tools
10+
- HTTP APIs
11+
- validation pipelines (used by `vix::validation`)
12+
13+
The module favors **predictability**, **performance**, and **explicit error handling**.
14+
15+
---
16+
17+
## Philosophy
18+
19+
Conversion in Vix follows strict rules:
20+
21+
- No exceptions
22+
- No implicit conversions
23+
- No locale dependence
24+
- No iostreams
25+
- Precise error reporting (code, position, input)
26+
27+
Every conversion returns an `expected<T, ConversionError>`.
28+
29+
---
30+
31+
## Core Concepts
32+
33+
| Concept | Purpose |
34+
|------|-------|
35+
| `to_int<T>` | Parse integer from string |
36+
| `to_float<T>` | Parse floating point from string |
37+
| `to_bool` | Parse boolean values |
38+
| `to_enum<T>` | Parse enum using explicit mapping |
39+
| `parse<T>` | Generic typed parsing facade |
40+
| `to_string` | Convert values to string |
41+
| `ConversionError` | Structured conversion error |
42+
| `expected<T,E>` | Explicit success / failure |
43+
44+
---
45+
46+
## Error Model
47+
48+
All conversions return:
49+
50+
```cpp
51+
expected<T, ConversionError>
52+
```
53+
54+
Where `ConversionError` contains:
55+
56+
- `code` — semantic error code
57+
- `position` — error index in input
58+
- `input` — original input
59+
60+
Example:
61+
62+
```cpp
63+
static void print_err(const ConversionError &e)
64+
{
65+
std::cout << "error: " << to_string(e.code)
66+
<< " position=" << e.position
67+
<< " input='" << e.input << "'\n";
68+
}
69+
```
70+
71+
---
72+
73+
## Parsing Integers
74+
75+
```cpp
76+
#include <vix/conversion/ToInt.hpp>
77+
78+
auto r = to_int<int>(" -42 ");
79+
if (!r)
80+
{
81+
// handle r.error()
82+
}
83+
else
84+
{
85+
int value = r.value();
86+
}
87+
```
88+
89+
Examples:
90+
- `examples/parse_int.cpp`
91+
- `examples/parse_generic.cpp`
92+
93+
---
94+
95+
## Parsing Floating Point Values
96+
97+
```cpp
98+
#include <vix/conversion/ToFloat.hpp>
99+
100+
auto r = to_float<double>(" 3.14 ");
101+
```
102+
103+
Supports:
104+
- scientific notation
105+
- leading / trailing spaces
106+
107+
Examples:
108+
- `examples/parse_float.cpp`
109+
110+
---
111+
112+
## Parsing Booleans
113+
114+
Accepted values (case-insensitive):
115+
- `true`, `false`
116+
- `1`, `0`
117+
- `yes`, `no`
118+
- `on`, `off`
119+
120+
```cpp
121+
#include <vix/conversion/ToBool.hpp>
122+
123+
auto r = to_bool("yes");
124+
```
125+
126+
Examples:
127+
- `examples/parse_bool.cpp`
128+
129+
---
130+
131+
## Parsing Enums
132+
133+
Enums are parsed using an explicit mapping table.
134+
135+
```cpp
136+
enum class Role { Admin, User };
137+
138+
static constexpr EnumEntry<Role> roles[] = {
139+
{"admin", Role::Admin},
140+
{"user", Role::User},
141+
};
142+
143+
auto r = to_enum<Role>("ADMIN", roles); // case-insensitive
144+
```
145+
146+
Examples:
147+
- `examples/parse_enum.cpp`
148+
149+
---
150+
151+
## Generic Parsing
152+
153+
`parse<T>` automatically selects the correct converter.
154+
155+
```cpp
156+
#include <vix/conversion/Parse.hpp>
157+
158+
auto a = parse<int>("42");
159+
auto b = parse<double>("3.14");
160+
auto c = parse<bool>("true");
161+
```
162+
163+
Examples:
164+
- `examples/parse_generic.cpp`
165+
166+
---
167+
168+
## Converting Values to String
169+
170+
```cpp
171+
#include <vix/conversion/ToString.hpp>
172+
173+
auto a = to_string(42);
174+
auto b = to_string(3.14);
175+
auto c = to_string(true);
176+
```
177+
178+
Enums require a mapping table:
179+
180+
```cpp
181+
auto r = to_string(Role::Admin, roles);
182+
```
183+
184+
Examples:
185+
- `examples/to_string.cpp`
186+
187+
---
188+
189+
## Performance Notes
190+
191+
- Uses `std::from_chars` / `std::to_chars`
192+
- No heap allocations in parsing paths
193+
- Stack buffers only
194+
- Locale-independent
195+
196+
This makes the module suitable for hot paths and low-latency systems.
197+
198+
---
199+
200+
## Tests
201+
202+
Unit tests are located in `tests/`:
203+
204+
- `to_int_smoke.cpp`
205+
- `to_float_smoke.cpp`
206+
- `to_bool_smoke.cpp`
207+
- `to_enum_smoke.cpp`
208+
209+
Run:
210+
211+
```bash
212+
ctest
213+
```
214+
215+
---
216+
217+
## Relationship with Validation
218+
219+
The `conversion` module is the foundation of `vix::validation`:
220+
221+
- `ParsedValidator<T>` relies on `parse<T>`
222+
- Form binding depends on conversion error reporting
223+
- Errors propagate without loss of information
224+
225+
---
226+
227+
## Design Goals Recap
228+
229+
- Explicit over implicit
230+
- Errors as values
231+
- No runtime surprises
232+
- Easy to embed
233+
- Predictable behavior
234+
235+
---
236+
237+
## License
238+
239+
MIT
240+
Part of the **Vix.cpp** project.
241+

include/vix/conversion/ToString.hpp

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define VIX_CONVERSION_TO_STRING_HPP
1717

1818
#include <charconv>
19+
#include <cstddef>
1920
#include <string>
2021
#include <string_view>
2122
#include <type_traits>
@@ -32,16 +33,17 @@ namespace vix::conversion
3233
*
3334
* Uses std::to_chars for fast, allocation-free formatting into a stack buffer.
3435
*
35-
* @tparam Int Integral type.
36+
* Note: bool is excluded from this overload (use to_string(bool)).
37+
*
38+
* @tparam Int Integral type (excluding bool).
3639
* @param value Value to format.
3740
* @return expected<std::string, ConversionError> containing the string or an error.
3841
*/
3942
template <typename Int>
43+
requires(std::is_integral_v<Int> && !std::is_same_v<std::remove_cv_t<Int>, bool>)
4044
[[nodiscard]] VIX_EXPECTED_CONSTEXPR expected<std::string, ConversionError>
4145
to_string(Int value) noexcept
4246
{
43-
static_assert(std::is_integral_v<Int>, "to_string<Int>: Int must be integral");
44-
4547
char buffer[64];
4648
auto [ptr, ec] = std::to_chars(buffer, buffer + sizeof(buffer), value);
4749

@@ -65,11 +67,10 @@ namespace vix::conversion
6567
* @return expected<std::string, ConversionError> containing the string or an error.
6668
*/
6769
template <typename Float>
70+
requires(std::is_floating_point_v<Float>)
6871
[[nodiscard]] VIX_EXPECTED_CONSTEXPR expected<std::string, ConversionError>
6972
to_string(Float value) noexcept
7073
{
71-
static_assert(std::is_floating_point_v<Float>, "to_string<Float>: Float must be floating point");
72-
7374
char buffer[128];
7475
auto [ptr, ec] = std::to_chars(buffer, buffer + sizeof(buffer), value);
7576

@@ -100,29 +101,20 @@ namespace vix::conversion
100101
*
101102
* If the enum value is not found in the mapping table, returns UnknownEnumValue.
102103
*
103-
* Example:
104-
* static constexpr EnumEntry<Role> roles[] = {
105-
* {"admin", Role::Admin},
106-
* {"user", Role::User}
107-
* };
108-
*
109-
* auto s = to_string(Role::Admin, roles);
110-
*
111104
* @tparam Enum Enum type.
112105
* @param value Enum value.
113106
* @param entries Mapping table entries.
114107
* @param count Number of entries.
115108
* @return expected<std::string, ConversionError> containing the string or an error.
116109
*/
117110
template <typename Enum>
111+
requires(std::is_enum_v<Enum>)
118112
[[nodiscard]] VIX_EXPECTED_CONSTEXPR expected<std::string, ConversionError>
119113
to_string(
120114
Enum value,
121115
const EnumEntry<Enum> *entries,
122116
std::size_t count) noexcept
123117
{
124-
static_assert(std::is_enum_v<Enum>, "to_string<Enum>: Enum must be an enum");
125-
126118
for (std::size_t i = 0; i < count; ++i)
127119
{
128120
if (entries[i].value == value)
@@ -146,6 +138,7 @@ namespace vix::conversion
146138
* @return expected<std::string, ConversionError> containing the string or an error.
147139
*/
148140
template <typename Enum, std::size_t N>
141+
requires(std::is_enum_v<Enum>)
149142
[[nodiscard]] VIX_EXPECTED_CONSTEXPR expected<std::string, ConversionError>
150143
to_string(Enum value, const EnumEntry<Enum> (&entries)[N]) noexcept
151144
{
@@ -154,4 +147,4 @@ namespace vix::conversion
154147

155148
} // namespace vix::conversion
156149

157-
#endif
150+
#endif // VIX_CONVERSION_TO_STRING_HPP

0 commit comments

Comments
 (0)