Skip to content

Commit b4eb06e

Browse files
author
XuhuaHuang
committed
Polish template for example
1 parent b99f04e commit b4eb06e

1 file changed

Lines changed: 151 additions & 12 deletions

File tree

Template/template_for.cpp

Lines changed: 151 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,162 @@
1+
#include <cmath>
2+
#include <cstdint>
3+
#include <iostream>
4+
#include <string_view>
15
#include <tuple>
6+
#include <type_traits>
27

3-
std::tuple<int, char, double> get_tuple();
4-
8+
// Domain model: a telemetry packet
59
struct Data {
6-
int a;
7-
char b;
8-
double c;
10+
int i; // e.g., sensor id
11+
char c; // e.g., status code
12+
double d; // e.g., measurement
913
};
1014

11-
Data get_data();
15+
// Simulated runtime acquisition
16+
Data get_data() {
17+
return Data{42, 'O', 23.75};
18+
}
19+
20+
// Compile-time "golden" packet (build-time contract)
21+
consteval Data get_constexpr_data() {
22+
return Data{1, 'a', 1.0};
23+
}
24+
25+
26+
// Field reflection (standard C++): tuple-of-references
27+
28+
constexpr auto as_tuple(Data& x) {
29+
return std::tie(x.i, x.c, x.d);
30+
}
31+
32+
constexpr auto as_tuple(const Data& x) {
33+
return std::tie(x.i, x.c, x.d);
34+
}
35+
36+
// Apply a callable to each field of Data
37+
template <class F>
38+
constexpr void for_each_field(Data& x, F&& f) {
39+
std::apply([&](auto&... fields) { (f(fields), ...); }, as_tuple(x));
40+
}
41+
template <class F>
42+
constexpr void for_each_field(const Data& x, F&& f) {
43+
std::apply([&](const auto&... fields) { (f(fields), ...); }, as_tuple(x));
44+
}
45+
46+
47+
// Logging & validation (runtime)
48+
49+
void use(int v) {
50+
std::cout << "int : " << v << "\n";
51+
}
52+
void use(char v) {
53+
std::cout << "char : '" << v << "'\n";
54+
}
55+
void use(double v) {
56+
std::cout << "double : " << v << "\n";
57+
}
58+
59+
struct Validation {
60+
bool ok = true;
61+
std::string_view first_error{};
62+
};
63+
64+
inline void require(bool cond, Validation& out, std::string_view msg) {
65+
if (!cond && out.ok) {
66+
out.ok = false;
67+
out.first_error = msg;
68+
}
69+
}
70+
71+
Validation validate(const Data& x) {
72+
Validation v{};
73+
require(x.i >= 0, v, "sensor id must be non-negative");
74+
require(std::isprint(static_cast<unsigned char>(x.c)) != 0, v, "status must be printable ASCII");
75+
require(std::isfinite(x.d) != 0, v, "measurement must be finite");
76+
// Example domain rule:
77+
require(x.d >= -1000.0 && x.d <= 1000.0, v, "measurement out of expected range");
78+
return v;
79+
}
80+
81+
82+
// Compile-time checksum (build-time self-test)
83+
84+
consteval std::uint64_t mix_u64(std::uint64_t h, std::uint64_t x) {
85+
// Simple 64-bit mixing (not cryptographic)
86+
h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
87+
return h;
88+
}
89+
90+
template <auto Value>
91+
consteval std::uint64_t fold_value(std::uint64_t h) {
92+
using T = decltype(Value);
93+
94+
if constexpr (std::is_same_v<T, int>) {
95+
return mix_u64(h, static_cast<std::uint64_t>(static_cast<std::int64_t>(Value)));
96+
} else if constexpr (std::is_same_v<T, char>) {
97+
return mix_u64(h, static_cast<std::uint64_t>(static_cast<unsigned char>(Value)));
98+
} else if constexpr (std::is_same_v<T, double>) {
99+
// Convert double to an integer-ish stable representation for checksum purposes.
100+
// Here we quantize to micro-units; adjust to your tolerance requirements.
101+
const long long q = static_cast<long long>(Value * 1'000'000.0);
102+
return mix_u64(h, static_cast<std::uint64_t>(q));
103+
} else {
104+
static_assert(!sizeof(T), "Unsupported field type in checksum");
105+
}
106+
}
107+
108+
consteval std::uint64_t golden_checksum() {
109+
constexpr Data g = get_constexpr_data();
110+
std::uint64_t h = 0xcbf29ce484222325ULL;
12111

13-
void use(double);
14-
void use(char);
15-
void use(int);
112+
// Standard C++ compile-time fold over fields:
113+
// (we can’t literally “loop” over heterogeneous fields without a helper)
114+
h = fold_value<g.i>(h);
115+
h = fold_value<g.c>(h);
116+
h = fold_value<g.d>(h);
117+
118+
return h;
119+
}
120+
121+
// If someone changes golden data values or field order, this will break the build.
122+
static_assert(golden_checksum() == golden_checksum(), "checksum sanity"); // tautology
123+
// In a real project, pin the expected value once, then keep it stable:
124+
// static_assert(golden_checksum() == 0xDEADBEEF..., "Golden packet changed unexpectedly");
125+
126+
127+
// Application entry
16128

17129
int main() {
18-
template for (const auto& element : get_tuple()) {
19-
// Do something with element
20-
use(element);
130+
std::cout << "=== Telemetry Packet Logger ===\n";
131+
132+
Data sample = get_data();
133+
134+
// Validate first
135+
if (auto v = validate(sample); !v.ok) {
136+
std::cout << "Invalid packet: " << v.first_error << "\n";
137+
return 1;
21138
}
139+
140+
// Log fields one-by-one (your “iterate fields” intent)
141+
std::cout << "Packet fields:\n";
142+
for_each_field(sample, [](const auto& field) { use(field); });
143+
144+
// Example: derive a simple runtime checksum too (for transmission integrity)
145+
// std::uint64_t h = 0xcbf29ce484222325ULL;
146+
// for_each_field(sample, [&](const auto& field) {
147+
// using T = std::remove_cvref_t<decltype(field)>;
148+
// if constexpr (std::is_same_v<T, int>) {
149+
// h = mix_u64(h, static_cast<std::uint64_t>(static_cast<std::int64_t>(field)));
150+
// } else if constexpr (std::is_same_v<T, char>) {
151+
// h = mix_u64(h, static_cast<std::uint64_t>(static_cast<unsigned char>(field)));
152+
// } else if constexpr (std::is_same_v<T, double>) {
153+
// const long long q = static_cast<long long>(field * 1'000'000.0);
154+
// h = mix_u64(h, static_cast<std::uint64_t>(q));
155+
// }
156+
// });
157+
158+
// std::cout << "Runtime checksum: 0x" << std::hex << h << std::dec << "\n";
159+
std::cout << "Golden checksum : 0x" << std::hex << golden_checksum() << std::dec << "\n";
160+
22161
return 0;
23162
}

0 commit comments

Comments
 (0)