Skip to content

Commit dd59ac2

Browse files
committed
Backport to C++20
1 parent 6d306cb commit dd59ac2

File tree

8 files changed

+2960
-142
lines changed

8 files changed

+2960
-142
lines changed

README.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,10 @@ std::string element = jsonh_cpp::jsonh_reader::parse_element<std::string>(jsonh)
5757

5858
## Dependencies
5959

60+
- C++20
6061
- [nlohmann/json](https://github.com/nlohmann/json) (up-to-date 2025/04/17)
6162
- [catchorg/Catch2](https://github.com/catchorg/Catch2) ([help](https://stackoverflow.com/a/78804393)) (up-to-date 2025/04/17)
62-
- C++23
63+
- [zeus-cpp/expected](https://github.com/zeus-cpp/expected) (backport) (up-to-date 2025/04/18)
6364

6465
## Limitations
6566

@@ -80,8 +81,4 @@ Numbers are parsed as `long long` and `long double`, which correspond to 64-bit
8081
### No token streaming
8182

8283
While tokens can be read one by one from a stream, the tokens are aggregated in a `std::vector`
83-
before returning due to a lack of `yield` in C++.
84-
85-
### C++23 or higher
86-
87-
Since the library makes use of `std::expected`, you must build it with a C++23-compatible compiler.
84+
before returning due to a lack of `yield` in C++.

jsonh_cpp/backports.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// <expected> backport
2+
#ifdef __cpp_lib_expected
3+
#include <expected> // for std::expected
4+
#define JSONH_CPP_EXPECTED std::expected
5+
#define JSONH_CPP_UNEXPECTED std::unexpected
6+
#endif
7+
#ifndef __cpp_lib_expected
8+
#include "zeus/expected.hpp" // for zeus::expected
9+
#define JSONH_CPP_EXPECTED zeus::expected
10+
#define JSONH_CPP_UNEXPECTED zeus::unexpected
11+
#endif

jsonh_cpp/jsonh_cpp.vcxproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
<ConformanceMode>true</ConformanceMode>
113113
<PrecompiledHeader>NotUsing</PrecompiledHeader>
114114
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
115-
<LanguageStandard>stdcpp23</LanguageStandard>
115+
<LanguageStandard>stdcpp20</LanguageStandard>
116116
<LanguageStandard_C>stdc17</LanguageStandard_C>
117117
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
118118
<AdditionalOptions>/utf-8</AdditionalOptions>
@@ -144,13 +144,15 @@
144144
</ItemDefinitionGroup>
145145
<ItemGroup>
146146
<ClCompile Include="jsonh_reader.hpp" />
147+
<ClInclude Include="backports.hpp" />
147148
<ClInclude Include="jsonh_cpp.hpp" />
148149
<ClInclude Include="jsonh_number_parser.hpp" />
149150
<ClInclude Include="jsonh_reader_options.hpp" />
150151
<ClInclude Include="jsonh_token.hpp" />
151152
<ClInclude Include="jsonh_token_type.hpp" />
152153
<ClInclude Include="nlohmann\json.hpp" />
153154
<ClInclude Include="utf8_reader.hpp" />
155+
<ClInclude Include="zeus\expected.hpp" />
154156
</ItemGroup>
155157
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
156158
<ImportGroup Label="ExtensionTargets">

jsonh_cpp/jsonh_cpp.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,11 @@
4141
<ClInclude Include="utf8_reader.hpp">
4242
<Filter>Header Files</Filter>
4343
</ClInclude>
44+
<ClInclude Include="zeus\expected.hpp">
45+
<Filter>Header Files</Filter>
46+
</ClInclude>
47+
<ClInclude Include="backports.hpp">
48+
<Filter>Header Files</Filter>
49+
</ClInclude>
4450
</ItemGroup>
4551
</Project>

jsonh_cpp/jsonh_number_parser.hpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <string> // for std::string
44
#include <expected> // for std::expected
55
#include <cmath> // for pow
6+
#include "backports.hpp" // for backport macros
67

78
namespace jsonh_cpp {
89

@@ -17,7 +18,7 @@ class jsonh_number_parser final {
1718
/// Input: <c>+5.2e3.0</c><br/>
1819
/// Output: <c>5200</c>
1920
/// </summary>
20-
static std::expected<long double, std::string> parse(std::string jsonh_number) noexcept {
21+
static JSONH_CPP_EXPECTED<long double, std::string> parse(std::string jsonh_number) noexcept {
2122
// Decimal
2223
std::string base_digits = "0123456789";
2324
// Hexadecimal
@@ -47,7 +48,7 @@ class jsonh_number_parser final {
4748
/// <summary>
4849
/// Converts a fractional number with an exponent (e.g. <c>12.3e4.5</c>) from the given base (e.g. <c>01234567</c>) to a base-10 real.
4950
/// </summary>
50-
static std::expected<long double, std::string> parse_fractional_number_with_exponent(std::string_view digits, std::string_view base_digits) noexcept {
51+
static JSONH_CPP_EXPECTED<long double, std::string> parse_fractional_number_with_exponent(std::string_view digits, std::string_view base_digits) noexcept {
5152
// Find exponent
5253
size_t exponent_index = digits.find_first_of("eE");
5354
// If no exponent then normalize real
@@ -60,13 +61,13 @@ class jsonh_number_parser final {
6061
std::string_view exponent_part = digits.substr(exponent_index + 1);
6162

6263
// Parse mantissa and exponent
63-
std::expected<long double, std::string> mantissa = parse_fractional_number(mantissa_part, base_digits);
64+
JSONH_CPP_EXPECTED<long double, std::string> mantissa = parse_fractional_number(mantissa_part, base_digits);
6465
if (!mantissa) {
65-
return std::unexpected(mantissa.error());
66+
return JSONH_CPP_UNEXPECTED(mantissa.error());
6667
}
67-
std::expected<long double, std::string> exponent = parse_fractional_number(exponent_part, base_digits);
68+
JSONH_CPP_EXPECTED<long double, std::string> exponent = parse_fractional_number(exponent_part, base_digits);
6869
if (!exponent) {
69-
return std::unexpected(exponent.error());
70+
return JSONH_CPP_UNEXPECTED(exponent.error());
7071
}
7172

7273
// Multiply mantissa by 10 ^ exponent
@@ -75,7 +76,7 @@ class jsonh_number_parser final {
7576
/// <summary>
7677
/// Converts a fractional number (e.g. <c>123.45</c>) from the given base (e.g. <c>01234567</c>) to a base-10 real.
7778
/// </summary>
78-
static std::expected<long double, std::string> parse_fractional_number(std::string_view digits, std::string_view base_digits) noexcept {
79+
static JSONH_CPP_EXPECTED<long double, std::string> parse_fractional_number(std::string_view digits, std::string_view base_digits) noexcept {
7980
// Optimization for base-10 digits
8081
if (base_digits == "0123456789") {
8182
return std::stold(std::string(digits));
@@ -85,9 +86,9 @@ class jsonh_number_parser final {
8586
size_t dot_index = digits.find('.');
8687
// If no dot then normalize integer
8788
if (dot_index == std::string::npos) {
88-
std::expected<long long, std::string> integer = parse_whole_number(digits, base_digits);
89+
JSONH_CPP_EXPECTED<long long, std::string> integer = parse_whole_number(digits, base_digits);
8990
if (!integer) {
90-
return std::unexpected(integer.error());
91+
return JSONH_CPP_UNEXPECTED(integer.error());
9192
}
9293
return (long double)integer.value();
9394
}
@@ -97,13 +98,13 @@ class jsonh_number_parser final {
9798
std::string_view fraction_part = digits.substr(dot_index + 1);
9899

99100
// Parse parts of number
100-
std::expected<long long, std::string> whole = parse_whole_number(whole_part, base_digits);
101+
JSONH_CPP_EXPECTED<long long, std::string> whole = parse_whole_number(whole_part, base_digits);
101102
if (!whole) {
102-
return std::unexpected(whole.error());
103+
return JSONH_CPP_UNEXPECTED(whole.error());
103104
}
104-
std::expected<long long, std::string> fraction = parse_whole_number(fraction_part, base_digits);
105+
JSONH_CPP_EXPECTED<long long, std::string> fraction = parse_whole_number(fraction_part, base_digits);
105106
if (!fraction) {
106-
return std::unexpected(fraction.error());
107+
return JSONH_CPP_UNEXPECTED(fraction.error());
107108
}
108109

109110
// Combine whole and fraction
@@ -112,7 +113,7 @@ class jsonh_number_parser final {
112113
/// <summary>
113114
/// Converts a whole number (e.g. <c>12345</c>) from the given base (e.g. <c>01234567</c>) to a base-10 integer.
114115
/// </summary>
115-
static std::expected<long long, std::string> parse_whole_number(std::string_view digits, std::string_view base_digits) noexcept {
116+
static JSONH_CPP_EXPECTED<long long, std::string> parse_whole_number(std::string_view digits, std::string_view base_digits) noexcept {
116117
// Optimization for base-10 digits
117118
if (base_digits == "0123456789") {
118119
return std::stoll(digits.data());
@@ -138,7 +139,7 @@ class jsonh_number_parser final {
138139

139140
// Ensure digit is valid
140141
if (digit_int == std::string::npos) {
141-
return std::unexpected("Invalid digit");
142+
return JSONH_CPP_UNEXPECTED("Invalid digit");
142143
}
143144

144145
// Get magnitude of current digit column

0 commit comments

Comments
 (0)