Skip to content

Commit 83ccc62

Browse files
Updates
1 parent 22085ed commit 83ccc62

File tree

2 files changed

+67
-78
lines changed

2 files changed

+67
-78
lines changed

cppcon2025/cppcon_2025_slides.md

Lines changed: 58 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -243,63 +243,21 @@ This manual approach has several problems:
243243
244244
---
245245
246-
# Goal: Seamless Serialization/Deserialization
246+
# Our goal: Seamless Serialization/Deserialization
247247
248248
<img src="images/tofrom.svg" width="100%">
249249
250250
---
251251
252-
# The Solution: C++26 Static Reflection
253-
254-
With C++26 reflection and simdjson, **all that boilerplate disappears**:
255-
256-
```cpp
257-
// Just define your struct - no extra code needed!
258-
struct Player {
259-
std::string username;
260-
int level;
261-
double health;
262-
std::vector<std::string> inventory;
263-
std::map<std::string, Equipment> equipped;
264-
std::vector<Achievement> achievements;
265-
std::optional<std::string> guild_name;
266-
};
267-
```
268-
269-
---
270-
271-
# Automatic Serialization
272-
273-
```cpp
274-
// Serialization - one line!
275-
void save_player(const Player& p) {
276-
std::string json = simdjson::to_json(p); // That's it!
277-
// Save json to file...
278-
}
279-
```
280-
281-
---
282-
283-
# Automatic Deserialization
284-
285-
```cpp
286-
// Deserialization - one line!
287-
Player load_player(std::string& json_str) {
288-
return simdjson::from(json_str); // That's it!
252+
<!-- _class: centered -->
253+
<style scoped>
254+
section {
255+
text-align: center;
256+
font-size: 2em;
289257
}
290-
```
291-
292-
Runnable example at https://godbolt.org/z/Efr7bK9jn
293-
294-
---
295-
296-
# Benefits of our implementation
258+
</style>
297259
298-
- **No manual field mapping**
299-
- **No maintenance burden**
300-
- **Handles nested and user-defined structures and containers automatically**
301-
- **You can still customize things if you want**
302-
- **Performance tuned by the library**
260+
<p style="text-align:center">How do other languages do it?</p>
303261
304262
---
305263
@@ -314,6 +272,11 @@ Player deserializedPlayer = JsonSerializer.Deserialize<Player>(jsonInput, option
314272

315273
---
316274

275+
# Why can C# implementation be so elegant?
276+
It is using **reflection** to access the attributes of a struct during runtime.
277+
278+
---
279+
317280
# Rust (serde)
318281

319282
```rust
@@ -322,22 +285,20 @@ let json_str = serde_json::to_string(&player)?;
322285
let player: Player = serde_json::from_str(&json_str)?;
323286
```
324287

325-
326288
<img src="images/rust.png" width="10%" />
327289

328290
---
329291

330292
# Rust reflection
331293

332-
333-
- Rust does not have ANY reflection.
334-
- You cannot enumerate the methods of a struct. Either at runtime or at compile-time.
335-
- Serde relies on annotation followed by re-parsing of the code.
294+
- Rust does not have any built-in reflection capabilities.
295+
- Serde relies on annotation and macros.
336296

337297
<img src="image/rust_reflection.png">
338298

339299
---
340300

301+
341302
# Reflection as accessing the attributes of a struct.
342303

343304
| language | runtime reflection | compile-time reflection |
@@ -350,42 +311,66 @@ let player: Player = serde_json::from_str(&json_str)?;
350311

351312
---
352313

353-
# With C++26: simple, maintainable, performant code
314+
# Now it's our turn to have reflection!
315+
316+
<!-- TODO: maybe add a reference to one of Herb's talks -->
317+
318+
With C++26 reflection and simdjson, **all that boilerplate disappears**:
354319

355320
```cpp
356-
std::string json_str = simdjson::to_json(player);
357-
Player player = simdjson::from(json_str);
321+
// Just define your struct - no extra code needed!
322+
struct Player {
323+
std::string username;
324+
int level;
325+
double health;
326+
std::vector<std::string> inventory;
327+
std::map<std::string, Equipment> equipped;
328+
std::vector<Achievement> achievements;
329+
std::optional<std::string> guild_name;
330+
};
358331
```
359332
360-
- no extra tooling required
361-
- no annotation
362-
363333
---
364334
335+
# Automatic Serialization
365336
366-
# How Does It Work?
367-
368-
## The Key Insight: Compile-Time Code Generation
369-
370-
**"How can compile-time reflection handle runtime JSON data?"**
371-
372-
The answer: Reflection operates on **types and structure**, not runtime values.
337+
```cpp
338+
// Serialization - one line!
339+
void save_player(const Player& p) {
340+
std::string json = simdjson::to_json(p); // That's it!
341+
// Save json to file...
342+
}
343+
```
373344

374-
It generates regular C++ code at compile time that handles your runtime data.
345+
---
375346

347+
# Automatic Deserialization
376348

349+
```cpp
350+
// Deserialization - one line!
351+
Player load_player(std::string& json_str) {
352+
return simdjson::from(json_str); // That's it!
353+
}
354+
```
377355
356+
Runnable example at https://godbolt.org/z/Efr7bK9jn
378357
358+
---
379359
360+
# Benefits of our implementation
380361
362+
- **No manual field mapping**
363+
- **Minimal maintenance burden**
364+
- **Handles nested and user-defined structures and containers automatically**
365+
- **You can still customize things if and when you want to**
381366
382367
---
383368
384369
# What Happens Behind the Scenes
385370
386371
```cpp
387372
// What you write:
388-
Player p = simdjson::from<Player>(runtime_json_string);
373+
Player p = simdjson::from(runtime_json_string);
389374
390375
// What reflection generates at COMPILE TIME (conceptually):
391376
Player deserialize_Player(const json& j) {
@@ -406,6 +391,8 @@ Player deserialize_Player(const json& j) {
406391
```cpp
407392
// Simplified snippet, members stores information about the class
408393
// obtained via std::define_static_array(std::meta::nonstatic_data_members_of(^^T, ...))...
394+
simdjson::ondemand::object obj;
395+
409396
template for (constexpr auto member : members) {
410397
// These are compile-time constants
411398
constexpr std::string_view field_name = std::meta::identifier_of(member);
@@ -436,7 +423,7 @@ struct Player {
436423

437424
// RUNTIME: The generated code processes actual JSON data
438425
std::string json = R"({"username":"Alice","level":42,"health":100.0})";
439-
Player p = simdjson::from<Player>(json);
426+
Player p = simdjson::from(json);
440427
// Runtime values flow through compile-time generated code
441428
```
442429

cppcon2025/instruction_count_analysis.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,19 @@ std::string serialize_manual(const Car& car) {
185185
// Generates 1,635 lines of assembly!
186186
}
187187

188-
// Reflection: 38 assembly instructions for user
188+
// Reflection: 648 total assembly instructions
189189
std::string serialize_reflection(const Car& car) {
190-
return simdjson::to_json(car); // 1 line!
191-
// User sees: 38 lines of wrapper assembly
192-
// Compiler generates: 648 lines of optimized template code
190+
return simdjson::to_json(car); // 1 line of C++!
191+
// Compiler generates: 648 lines of optimized assembly
192+
// (38 wrapper + 610 template instantiation)
193193
}
194194
```
195195
196-
**43x code reduction for the developer!**
197-
**2.5x fewer instructions overall!**
198-
**15x fewer branches to predict!**
196+
**What actually matters:**
197+
- **2.5x fewer instructions** (1,635 → 648)
198+
- **15x fewer branches** (311 → ~20)
199+
- **70+ lines of C++ → 1 line**
200+
- **Zero manual string escaping**
199201
200202
---
201203

0 commit comments

Comments
 (0)