Skip to content

Commit 4c5ae12

Browse files
committed
tweaking
1 parent ac28865 commit 4c5ae12

File tree

5 files changed

+183
-25
lines changed

5 files changed

+183
-25
lines changed

cppcon2025/cppcon_2025_slides.md

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ CppCon 2025
2121

2222
---
2323

24+
![bg right 95%](images/alice.png)
25+
26+
2427
# JSON
2528

2629
* Portable, simple
@@ -33,16 +36,6 @@ CppCon 2025
3336
* arrays (list)
3437

3538

36-
---
37-
38-
```json
39-
{
40-
"username": "Alice",
41-
"level": 42,
42-
"health": 99.5,
43-
"inventory": ["sword", "shield", "potion"]
44-
}
45-
```
4639

4740
---
4841

@@ -60,8 +53,15 @@ Parsed 0.63 GB in 6.961 seconds (90.72 MB/s)
6053

6154
---
6255

56+
<style scoped>
57+
img[alt~="center"] {
58+
display: block;
59+
margin: 0 auto;
60+
}
61+
</style>
62+
63+
![w:700 center](images/gwen.jpeg)
6364

64-
<img src="images/gwen.jpeg" width="55%" />
6565

6666
Source: Gwen (Chen) Shapira
6767

@@ -78,7 +78,7 @@ Source: Gwen (Chen) Shapira
7878
* simdjson was the first library to break the gigabyte per second barrier
7979
* Parsing Gigabytes of JSON per Second, VLDB Journal 28 (6), 2019
8080
* On-Demand JSON: A Better Way to Parse Documents? SPE 54 (6), 2024
81-
* JSON for Modern C++ (nlohmann/json) can be $100\times$ slower!
81+
* JSON for Modern C++ (nlohmann/json) can be $10\times$ slower!
8282

8383
<img src="images/simdjson.png" width="10%" />
8484

@@ -96,12 +96,23 @@ Source: Gwen (Chen) Shapira
9696

9797
# Not All Processors are Equal
9898

99+
<style>
100+
.center-table {
101+
display: flex;
102+
justify-content: center;
103+
}
104+
</style>
105+
106+
<div class="center-table">
107+
99108
| processor | year | arithmetic logic units | SIMD units |
100109
|-----------------|---------|---------------------------|----------------|
101110
| Apple M* | 2019 | 6+ | $4 \times 128$ |
102111
| Intel Lion Cove | 2024 | 6 | $4 \times 256$ |
103112
| AMD Zen 5 | 2024 | 6 | $4 \times 512$ |
104113

114+
</div>
115+
105116
---
106117

107118
![bg right](images/avx.jpeg)
@@ -123,15 +134,15 @@ Source: Gwen (Chen) Shapira
123134

124135

125136
* First scan identifies the structural characters, start of all strings at about 10 GB/s using SIMD instructions.
126-
* Validates Unicode (UTF-8) at 30 GB/s.
137+
* Validates Unicode at 30 GB/s.
127138
* Rest of parsing relies on the generated index.
128139
* Allows fast skipping. (Only parse what we need)
129140
* Can minify JSON at 10 to 20 GB/s
130141

131142
---
132143

133144

134-
<img src="images/simdjson_benchmark.png" width="80%"/>
145+
<img src="images/simdjson_benchmark.png" width="85%"/>
135146

136147
https://openbenchmarking.org/test/pts/simdjson
137148

@@ -140,7 +151,7 @@ https://openbenchmarking.org/test/pts/simdjson
140151

141152
# Usage
142153

143-
You are probably using simdjson:
154+
**You are probably using simdjson:**
144155

145156
- Node.js, Electron,...
146157
- ClickHouse
@@ -277,7 +288,10 @@ section {
277288
# C#
278289
279290
```C#
291+
280292
string jsonString = JsonSerializer.Serialize(player, options);
293+
294+
281295
Player deserializedPlayer = JsonSerializer.Deserialize<Player>(jsonInput, options);
282296
```
283297

@@ -507,6 +521,20 @@ void serialize(string_builder& b, const std::set<T>& v) { /* ... */ }
507521
508522
Concepts let us say: **"If it walks like a duck and quacks like a duck..."**
509523
524+
```cpp
525+
template <typename T>
526+
concept container_but_not_string =
527+
requires(T a) {
528+
{ a.size() } -> std::convertible_to<std::size_t>;
529+
{
530+
a[std::declval<std::size_t>()]
531+
}; // check if elements are accessible for the subscript operator
532+
};
533+
```
534+
535+
---
536+
537+
510538
```cpp
511539
template <typename T>
512540
concept container_but_not_string =
@@ -522,19 +550,50 @@ concept container_but_not_string =
522550
---
523551
524552
```cpp
525-
template<typename T>
526-
requires(has_size_and_subscript<T>) // "If it has .size() and operator[]"
527-
void serialize(string_builder& b, const T& container) {
528-
b.append('[');
529-
for (size_t i = 0; i < container.size(); ++i) {
530-
serialize(b, container[i]);
531-
}
532-
b.append(']');
553+
template <class T>
554+
requires(container_but_not_string<T>)
555+
constexpr void atom(string_builder &b, const T &t) {
556+
if (t.size() == 0) {
557+
b.append_raw("[]");
558+
return;
559+
}
560+
b.append('[');
561+
atom(b, t[0]);
562+
for (size_t i = 1; i < t.size(); ++i) {
563+
b.append(',');
564+
atom(b, t[i]);
565+
}
566+
b.append(']');
533567
}
534568
```
535569

536570
✅ Works with `vector`, `array`, `deque`, custom containers...
537571

572+
573+
---
574+
575+
```cpp
576+
template <typename T>
577+
concept appendable_containers =
578+
(details::supports_emplace_back<T> || details::supports_emplace<T> ||
579+
details::supports_push_back<T> || details::supports_push<T> ||
580+
details::supports_add<T> || details::supports_append<T> ||
581+
details::supports_insert<T>);
582+
```
583+
584+
---
585+
586+
```cpp
587+
template <appendable_containers T, typename... Args>
588+
constexpr decltype(auto) emplace_one(T &vec, Args &&...args) {
589+
if constexpr (details::supports_emplace_back<T>) {
590+
return vec.emplace_back(std::forward<Args>(args)...);
591+
} else if constexpr (details::supports_emplace<T>) {
592+
return vec.emplace(std::forward<Args>(args)...);
593+
} else if // ...
594+
}
595+
```
596+
538597
---
539598
540599
# Concepts + Reflection = Automatic Support
@@ -566,8 +625,9 @@ The magic:
566625

567626
<img src="images/perf_with_simdjson.png" width="80%"/>
568627

569-
**3.4 GB/s** - 14x faster than nlohmann, 2.5x faster than Serde!
628+
---
570629

630+
**3.4 GB/s** - 14x faster than nlohmann, 2.5x faster than Serde!
571631

572632
---
573633

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
=== SimdJSON Reflection (simdjson_to) ===
2+
# Reading file /Users/random_person/Desktop/simdjson/buildreflect/jsonexamples/twitter.json
3+
# output volume: 93311 bytes
4+
bench_simdjson_to : 3598.34 MB/s 0.93 Ms/s
5+
6+
=== SimdJSON Static Reflection ===
7+
# Reading file /Users/random_person/Desktop/simdjson/buildreflect/jsonexamples/twitter.json
8+
# output volume: 93311 bytes
9+
bench_simdjson_static_reflection : 4257.15 MB/s 1.09 Ms/s
10+
11+
=== nlohmann::json ===
12+
# Reading file /Users/random_person/Desktop/simdjson/buildreflect/jsonexamples/twitter.json
13+
# output volume: 93311 bytes
14+
bench_nlohmann : 174.58 MB/s 0.00 Ms/s
15+
16+
=== RapidJSON ===
17+
# Reading file /Users/random_person/Desktop/simdjson/buildreflect/jsonexamples/twitter.json
18+
# output volume: 93311 bytes
19+
bench_rapidjson : 529.25 MB/s 0.01 Ms/s
20+
21+
=== YYJson ===
22+
# Reading file /Users/random_person/Desktop/simdjson/buildreflect/jsonexamples/twitter.json
23+
# output volume: 93311 bytes
24+
bench_yyjson : 1909.87 MB/s 0.02 Ms/s
25+
26+
=== Rust/Serde ===
27+
# Reading file /Users/random_person/Desktop/simdjson/buildreflect/jsonexamples/twitter.json
28+
# Note: Rust/Serde may include additional fields not in C++ structure.
29+
# output volume: 93311 bytes
30+
bench_rust : 417.89 MB/s 0.00 Ms/s
31+
32+
=== Reflect-cpp ===
33+
# Reading file /Users/random_person/Desktop/simdjson/buildreflect/jsonexamples/twitter.json
34+
# output volume: 93311 bytes
35+
bench_reflect_cpp : 1517.55 MB/s 0.02 Ms/s

cppcon2025/images/alice.html

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Formatted JSON Code</title>
7+
<style>
8+
body {
9+
font-family: 'Courier New', Courier, monospace;
10+
background-color: #1e1e1e;
11+
color: #d4d4d4;
12+
display: flex;
13+
justify-content: center;
14+
align-items: center;
15+
min-height: 100vh;
16+
margin: 0;
17+
padding: 20px;
18+
}
19+
.code-container {
20+
background-color: #252526;
21+
border-radius: 8px;
22+
padding: 20px;
23+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
24+
max-width: 600px;
25+
width: 100%;
26+
}
27+
pre {
28+
margin: 0;
29+
white-space: pre-wrap;
30+
word-wrap: break-word;
31+
}
32+
code {
33+
font-size: 16px;
34+
line-height: 1.5;
35+
}
36+
.key {
37+
color: #92b8d7;
38+
}
39+
.string {
40+
color: #f5f1f0;
41+
}
42+
.number {
43+
color: #b5cea8;
44+
}
45+
.array {
46+
color: #d7ba7d;
47+
}
48+
.punctuation {
49+
color: #d4d4d4;
50+
}
51+
</style>
52+
</head>
53+
<body>
54+
<div class="code-container">
55+
<pre><code><span class="punctuation">{</span>
56+
<span class="key">"username"</span><span class="punctuation">: </span><span class="string">"Alice"</span><span class="punctuation">,</span>
57+
<span class="key">"level"</span><span class="punctuation">: </span><span class="number">42</span><span class="punctuation">,</span>
58+
<span class="key">"health"</span><span class="punctuation">: </span><span class="number">99.5</span><span class="punctuation">,</span>
59+
<span class="key">"inventory"</span><span class="punctuation">: </span><span class="array">[<span class="string">"sword"</span><span class="punctuation">, </span><span class="string">"shield"</span><span class="punctuation">, </span><span class="string">"potion"</span>]</span>
60+
<span class="punctuation">}</span></code></pre>
61+
</div>
62+
</body>
63+
</html>

cppcon2025/images/alice.png

47.9 KB
Loading

cppcon2025/images/generate_perf_charts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
plt.close()
7171

7272

73-
# Chart 2b: Parsing only (même style)
73+
# Chart 2b: Parsing only (same style)
7474
plt.figure(figsize=(10, 6))
7575
bars = plt.bar(libraries_with, [172, 658, 1720, 2230, 4090], color=colors_with, edgecolor='black')
7676
ax = plt.gca()

0 commit comments

Comments
 (0)