Skip to content

Commit 7bf82b0

Browse files
committed
this completes the extra_into work.
1 parent 88a1b3e commit 7bf82b0

39 files changed

Lines changed: 6487 additions & 4761 deletions

doc/basics.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,38 @@ and then assign values to the public members.
14031403
If a key is missing in the JSON document, an error is generated (`NO_SUCH_FIELD`),
14041404
except if the attribute is of a type like `std::optional` (`simdjson::concepts::optional_type`).
14051405
1406+
1407+
Sometimes you might want to only extract some attributes from the JSON. You can
1408+
achieve this result with the `extract_into` method supported by both `object` and
1409+
`document` instances. It returns an error code that evaluates to false when there
1410+
is no error.
1411+
1412+
Consider the following
1413+
1414+
```cpp
1415+
struct car_type {
1416+
std::string make;
1417+
std::string model;
1418+
uint64_t year;
1419+
std::vector<double> tire_pressure;
1420+
};
1421+
1422+
void f() {
1423+
auto json = R"( {
1424+
"make": "Toyota",
1425+
"model": "Camry",
1426+
"year": 2024,
1427+
"tire_pressure": [ 40.1, 39.9 ]
1428+
} )"_padded;
1429+
ondemand::parser parser;
1430+
ondemand::document doc = parser.iterate(json);
1431+
Car car{};
1432+
auto error = doc.extract_into<"make","model">(car);
1433+
if(error) { /** error handling */ }
1434+
//
1435+
}
1436+
```
1437+
14061438
#### Special cases
14071439
14081440
However, there are instances where the construction cannot
@@ -1459,7 +1491,7 @@ The code might be as simple as the following.
14591491
auto padded = R"({"time":["2023-03-15T12:00:00Z"],"temperature":[42]})"_padded;
14601492
simdjson::ondemand::parser parser;
14611493
simdjson::ondemand::document doc = parser.iterate(padded);
1462-
complicated_weather_data p = doc.get<>(complicated_weather_data);
1494+
complicated_weather_data p = doc.get<complicated_weather_data>();
14631495
```
14641496
14651497
Thus you can combine C++26 static reflection with custom deserialization
@@ -2774,15 +2806,16 @@ a parameter a reference to a `std::string`.
27742806
ondemand::parser parser;
27752807
ondemand::document doc = parser.iterate(json);
27762808
std::string name;
2777-
doc["name"].get_string(name);
2809+
auto error = doc["name"].get_string(name);
2810+
if(error) { /* handle error */ }
27782811
```
27792812
27802813
The same routine can be written without exceptions handling:
27812814
27822815
```C++
27832816
std::string name;
2784-
auto err = doc["name"].get_string(name);
2785-
if (err) { /* handle error */ }
2817+
auto error = doc["name"].get_string(name);
2818+
if (error) { /* handle error */ }
27862819
```
27872820
27882821
The `std::string` instance, once created, is independent. Unlike our `std::string_view` instances,

include/simdjson/concepts.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,20 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
127127

128128

129129

130+
// Types we serialize as JSON strings (not as containers)
131+
template <typename T>
132+
concept string_like =
133+
std::is_same_v<std::remove_cvref_t<T>, std::string> ||
134+
std::is_same_v<std::remove_cvref_t<T>, std::string_view> ||
135+
std::is_same_v<std::remove_cvref_t<T>, const char*> ||
136+
std::is_same_v<std::remove_cvref_t<T>, char*>;
137+
138+
// Concept that checks if a type is a container but not a string (because
139+
// strings handling must be handled differently)
140+
// Now uses iterator-based approach for broader container support
141+
template <typename T>
142+
concept container_but_not_string =
143+
std::ranges::input_range<T> && !string_like<T> && !concepts::string_view_keyed_map<T>;
130144

131145

132146
} // namespace concepts

include/simdjson/constevalutil.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,27 @@ consteval std::string consteval_to_quoted_escaped(std::string_view input) {
4747
out.push_back('"');
4848
return out;
4949
}
50+
51+
#if SIMDJSON_SUPPORTS_CONCEPTS
52+
template <std::size_t N>
53+
struct fixed_string {
54+
constexpr fixed_string(const char (&str)[N]) {
55+
for (std::size_t i = 0; i < N; ++i) {
56+
data[i] = str[i];
57+
}
58+
}
59+
char data[N];
60+
constexpr std::string_view view() const { return {data, N - 1}; }
61+
};
62+
template <std::size_t N>
63+
fixed_string(const char (&)[N]) -> fixed_string<N>;
64+
65+
template <fixed_string str>
66+
struct string_constant {
67+
static constexpr std::string_view value = str.view();
68+
};
69+
#endif // SIMDJSON_SUPPORTS_CONCEPTS
70+
5071
} // namespace constevalutil
5172
} // namespace simdjson
5273
#endif // SIMDJSON_CONSTEVAL

include/simdjson/generic/implementation_simdjson_result_base-inl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b
2929
}
3030

3131
template<typename T>
32-
simdjson_inline error_code implementation_simdjson_result_base<T>::error() const noexcept {
32+
simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_base<T>::error() const noexcept {
3333
return this->second;
3434
}
3535

3636

3737
template<typename T>
38-
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
38+
simdjson_warn_unused simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
3939
return this->error() == SUCCESS;
4040
}
4141

include/simdjson/generic/implementation_simdjson_result_base.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,17 @@ struct implementation_simdjson_result_base {
6767
*
6868
* @param value The variable to assign the value to. May not be set if there is an error.
6969
*/
70-
simdjson_inline error_code get(T &value) && noexcept;
70+
simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept;
7171

7272
/**
7373
* The error.
7474
*/
75-
simdjson_inline error_code error() const noexcept;
75+
simdjson_warn_unused simdjson_inline error_code error() const noexcept;
7676

7777
/**
7878
* Whether there is a value.
7979
*/
80-
simdjson_inline bool has_value() const noexcept;
80+
simdjson_warn_unused simdjson_inline bool has_value() const noexcept;
8181

8282
#if SIMDJSON_EXCEPTIONS
8383

include/simdjson/generic/numberparsing.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ simdjson_inline bool is_digit(const uint8_t c) {
361361
return static_cast<uint8_t>(c - '0') <= 9;
362362
}
363363

364-
simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const uint8_t *const src, const uint8_t *&p, uint64_t &i, int64_t &exponent) {
364+
simdjson_warn_unused simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const uint8_t *const src, const uint8_t *&p, uint64_t &i, int64_t &exponent) {
365365
// we continue with the fiction that we have an integer. If the
366366
// floating point number is representable as x * 10^z for some integer
367367
// z that fits in 53 bits, then we will be able to convert back the
@@ -389,7 +389,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u
389389
return SUCCESS;
390390
}
391391

392-
simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) {
392+
simdjson_warn_unused simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) {
393393
// Exp Sign: -123.456e[-]78
394394
bool neg_exp = ('-' == *p);
395395
if (neg_exp || '+' == *p) { p++; } // Skip + as well
@@ -478,7 +478,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double
478478

479479
/** @private */
480480
template<typename W>
481-
simdjson_inline error_code write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer) {
481+
simdjson_warn_unused simdjson_inline error_code write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer) {
482482
// If we frequently had to deal with long strings of digits,
483483
// we could extend our code by using a 128-bit integer instead
484484
// of a 64-bit integer. However, this is uncommon in practice.
@@ -541,13 +541,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative,
541541
//
542542
// Our objective is accurate parsing (ULP of 0) at high speed.
543543
template<typename W>
544-
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer);
544+
simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer);
545545

546546
// for performance analysis, it is sometimes useful to skip parsing
547547
#ifdef SIMDJSON_SKIPNUMBERPARSING
548548

549549
template<typename W>
550-
simdjson_inline error_code parse_number(const uint8_t *const, W &writer) {
550+
simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const, W &writer) {
551551
writer.append_s64(0); // always write zero
552552
return SUCCESS; // always succeeds
553553
}
@@ -573,7 +573,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
573573
//
574574
// Our objective is accurate parsing (ULP of 0) at high speed.
575575
template<typename W>
576-
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
576+
simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
577577
//
578578
// Check for minus sign
579579
//

include/simdjson/generic/ondemand/array-inl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
8585
simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
8686
return array_iterator(iter);
8787
}
88-
simdjson_inline error_code array::consume() noexcept {
88+
simdjson_warn_unused simdjson_warn_unused simdjson_inline error_code array::consume() noexcept {
8989
auto error = iter.json_iter().skip_child(iter.depth()-1);
9090
if(error) { iter.abandon(); }
9191
return error;

include/simdjson/generic/ondemand/array.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class array {
141141
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
142142
*/
143143
template <typename T>
144-
simdjson_inline error_code get(T &out)
144+
simdjson_warn_unused simdjson_inline error_code get(T &out)
145145
noexcept(custom_deserializable<T, array> ? nothrow_custom_deserializable<T, array> : true) {
146146
static_assert(custom_deserializable<T, array>);
147147
return deserialize(*this, out);
@@ -166,7 +166,7 @@ class array {
166166
/**
167167
* Go to the end of the array, no matter where you are right now.
168168
*/
169-
simdjson_inline error_code consume() noexcept;
169+
simdjson_warn_unused simdjson_inline error_code consume() noexcept;
170170

171171
/**
172172
* Begin array iteration.
@@ -252,7 +252,7 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> : public SIMDJS
252252
return first.get<T>();
253253
}
254254
template<typename T>
255-
simdjson_inline error_code get(T& out) noexcept {
255+
simdjson_warn_unused simdjson_inline error_code get(T& out) noexcept {
256256
if (error()) { return error(); }
257257
if constexpr (std::is_same_v<T, SIMDJSON_IMPLEMENTATION::ondemand::array>) {
258258
out = first;

0 commit comments

Comments
 (0)