|
6 | 6 | #include <variant> |
7 | 7 | #include <cstring> |
8 | 8 | #include <sstream> |
| 9 | +#include <charconv> |
9 | 10 | #include <cmath> |
10 | 11 | #include "log.h" |
11 | 12 |
|
12 | 13 | namespace mavsdk { |
13 | 14 |
|
| 15 | +// Original implementation using std::ostream << for float/double conversion. |
| 16 | +// Kept for benchmark comparison. |
| 17 | +template<typename T> void value_to_json_stream(std::ostream& json_stream, const T& value) |
| 18 | +{ |
| 19 | + if constexpr ( |
| 20 | + std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> || std::is_same_v<T, uint32_t> || |
| 21 | + std::is_same_v<T, uint64_t> || std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t> || |
| 22 | + std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t>) { |
| 23 | + json_stream << static_cast<int64_t>(value); |
| 24 | + } else if constexpr (std::is_same_v<T, char>) { |
| 25 | + json_stream << static_cast<int>(value); |
| 26 | + } else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>) { |
| 27 | + if (!std::isfinite(value)) { |
| 28 | + json_stream << "null"; |
| 29 | + } else { |
| 30 | + json_stream << value; |
| 31 | + } |
| 32 | + } else if constexpr (std::is_same_v<T, std::string>) { |
| 33 | + json_stream << "\"" << value << "\""; |
| 34 | + } else if constexpr ( |
| 35 | + std::is_same_v<T, std::vector<uint8_t>> || std::is_same_v<T, std::vector<int8_t>>) { |
| 36 | + // Handle uint8_t/int8_t vectors specially to avoid character output |
| 37 | + json_stream << "["; |
| 38 | + bool first = true; |
| 39 | + for (const auto& elem : value) { |
| 40 | + if (!first) |
| 41 | + json_stream << ","; |
| 42 | + first = false; |
| 43 | + json_stream << static_cast<int>(elem); |
| 44 | + } |
| 45 | + json_stream << "]"; |
| 46 | + } else if constexpr ( |
| 47 | + std::is_same_v<T, std::vector<uint16_t>> || std::is_same_v<T, std::vector<uint32_t>> || |
| 48 | + std::is_same_v<T, std::vector<uint64_t>> || std::is_same_v<T, std::vector<int16_t>> || |
| 49 | + std::is_same_v<T, std::vector<int32_t>> || std::is_same_v<T, std::vector<int64_t>>) { |
| 50 | + // Handle integer vector types |
| 51 | + json_stream << "["; |
| 52 | + bool first = true; |
| 53 | + for (const auto& elem : value) { |
| 54 | + if (!first) |
| 55 | + json_stream << ","; |
| 56 | + first = false; |
| 57 | + json_stream << elem; |
| 58 | + } |
| 59 | + json_stream << "]"; |
| 60 | + } else if constexpr ( |
| 61 | + std::is_same_v<T, std::vector<float>> || std::is_same_v<T, std::vector<double>>) { |
| 62 | + // Handle float/double vector types with NaN check |
| 63 | + json_stream << "["; |
| 64 | + bool first = true; |
| 65 | + for (const auto& elem : value) { |
| 66 | + if (!first) |
| 67 | + json_stream << ","; |
| 68 | + first = false; |
| 69 | + if (!std::isfinite(elem)) { |
| 70 | + json_stream << "null"; |
| 71 | + } else { |
| 72 | + json_stream << elem; |
| 73 | + } |
| 74 | + } |
| 75 | + json_stream << "]"; |
| 76 | + } else { |
| 77 | + // Fallback for unknown types |
| 78 | + json_stream << "null"; |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +// Optimized implementation using std::to_chars for float/double conversion. |
| 83 | +template<typename T> void value_to_json_stream_fast(std::ostream& json_stream, const T& value) |
| 84 | +{ |
| 85 | + if constexpr ( |
| 86 | + std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> || std::is_same_v<T, uint32_t> || |
| 87 | + std::is_same_v<T, uint64_t> || std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t> || |
| 88 | + std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t>) { |
| 89 | + char buf[32]; |
| 90 | + auto [ptr, ec] = std::to_chars(buf, buf + sizeof(buf), value); |
| 91 | + json_stream.write(buf, ptr - buf); |
| 92 | + } else if constexpr (std::is_same_v<T, char>) { |
| 93 | + char buf[8]; |
| 94 | + auto [ptr, ec] = std::to_chars(buf, buf + sizeof(buf), static_cast<int>(value)); |
| 95 | + json_stream.write(buf, ptr - buf); |
| 96 | + } else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>) { |
| 97 | + if (!std::isfinite(value)) { |
| 98 | + json_stream << "null"; |
| 99 | + } else { |
| 100 | + char buf[32]; |
| 101 | + auto [ptr, ec] = std::to_chars(buf, buf + sizeof(buf), value); |
| 102 | + json_stream.write(buf, ptr - buf); |
| 103 | + } |
| 104 | + } else if constexpr (std::is_same_v<T, std::string>) { |
| 105 | + json_stream << "\"" << value << "\""; |
| 106 | + } else if constexpr ( |
| 107 | + std::is_same_v<T, std::vector<uint8_t>> || std::is_same_v<T, std::vector<int8_t>>) { |
| 108 | + json_stream << "["; |
| 109 | + bool first = true; |
| 110 | + for (const auto& elem : value) { |
| 111 | + if (!first) |
| 112 | + json_stream << ","; |
| 113 | + first = false; |
| 114 | + char buf[8]; |
| 115 | + auto [ptr, ec] = std::to_chars(buf, buf + sizeof(buf), static_cast<int>(elem)); |
| 116 | + json_stream.write(buf, ptr - buf); |
| 117 | + } |
| 118 | + json_stream << "]"; |
| 119 | + } else if constexpr ( |
| 120 | + std::is_same_v<T, std::vector<uint16_t>> || std::is_same_v<T, std::vector<uint32_t>> || |
| 121 | + std::is_same_v<T, std::vector<uint64_t>> || std::is_same_v<T, std::vector<int16_t>> || |
| 122 | + std::is_same_v<T, std::vector<int32_t>> || std::is_same_v<T, std::vector<int64_t>>) { |
| 123 | + json_stream << "["; |
| 124 | + bool first = true; |
| 125 | + for (const auto& elem : value) { |
| 126 | + if (!first) |
| 127 | + json_stream << ","; |
| 128 | + first = false; |
| 129 | + char buf[32]; |
| 130 | + auto [ptr, ec] = std::to_chars(buf, buf + sizeof(buf), elem); |
| 131 | + json_stream.write(buf, ptr - buf); |
| 132 | + } |
| 133 | + json_stream << "]"; |
| 134 | + } else if constexpr ( |
| 135 | + std::is_same_v<T, std::vector<float>> || std::is_same_v<T, std::vector<double>>) { |
| 136 | + json_stream << "["; |
| 137 | + bool first = true; |
| 138 | + for (const auto& elem : value) { |
| 139 | + if (!first) |
| 140 | + json_stream << ","; |
| 141 | + first = false; |
| 142 | + if (!std::isfinite(elem)) { |
| 143 | + json_stream << "null"; |
| 144 | + } else { |
| 145 | + char buf[32]; |
| 146 | + auto [ptr, ec] = std::to_chars(buf, buf + sizeof(buf), elem); |
| 147 | + json_stream.write(buf, ptr - buf); |
| 148 | + } |
| 149 | + } |
| 150 | + json_stream << "]"; |
| 151 | + } else { |
| 152 | + // Fallback for unknown types |
| 153 | + json_stream << "null"; |
| 154 | + } |
| 155 | +} |
| 156 | + |
| 157 | +// Explicit instantiations for benchmark testing - original |
| 158 | +template void value_to_json_stream<float>(std::ostream&, const float&); |
| 159 | +template void value_to_json_stream<double>(std::ostream&, const double&); |
| 160 | +template void value_to_json_stream<int8_t>(std::ostream&, const int8_t&); |
| 161 | +template void value_to_json_stream<int16_t>(std::ostream&, const int16_t&); |
| 162 | +template void value_to_json_stream<int32_t>(std::ostream&, const int32_t&); |
| 163 | +template void value_to_json_stream<int64_t>(std::ostream&, const int64_t&); |
| 164 | +template void value_to_json_stream<uint8_t>(std::ostream&, const uint8_t&); |
| 165 | +template void value_to_json_stream<uint16_t>(std::ostream&, const uint16_t&); |
| 166 | +template void value_to_json_stream<uint32_t>(std::ostream&, const uint32_t&); |
| 167 | +template void value_to_json_stream<uint64_t>(std::ostream&, const uint64_t&); |
| 168 | +template void value_to_json_stream<std::string>(std::ostream&, const std::string&); |
| 169 | +template void value_to_json_stream<std::vector<float>>(std::ostream&, const std::vector<float>&); |
| 170 | +template void value_to_json_stream<std::vector<double>>(std::ostream&, const std::vector<double>&); |
| 171 | + |
| 172 | +// Explicit instantiations for benchmark testing - optimized |
| 173 | +template void value_to_json_stream_fast<float>(std::ostream&, const float&); |
| 174 | +template void value_to_json_stream_fast<double>(std::ostream&, const double&); |
| 175 | +template void value_to_json_stream_fast<int8_t>(std::ostream&, const int8_t&); |
| 176 | +template void value_to_json_stream_fast<int16_t>(std::ostream&, const int16_t&); |
| 177 | +template void value_to_json_stream_fast<int32_t>(std::ostream&, const int32_t&); |
| 178 | +template void value_to_json_stream_fast<int64_t>(std::ostream&, const int64_t&); |
| 179 | +template void value_to_json_stream_fast<uint8_t>(std::ostream&, const uint8_t&); |
| 180 | +template void value_to_json_stream_fast<uint16_t>(std::ostream&, const uint16_t&); |
| 181 | +template void value_to_json_stream_fast<uint32_t>(std::ostream&, const uint32_t&); |
| 182 | +template void value_to_json_stream_fast<uint64_t>(std::ostream&, const uint64_t&); |
| 183 | +template void value_to_json_stream_fast<std::string>(std::ostream&, const std::string&); |
| 184 | +template void |
| 185 | +value_to_json_stream_fast<std::vector<float>>(std::ostream&, const std::vector<float>&); |
| 186 | +template void |
| 187 | +value_to_json_stream_fast<std::vector<double>>(std::ostream&, const std::vector<double>&); |
| 188 | + |
14 | 189 | LibmavReceiver::LibmavReceiver(MavsdkImpl& mavsdk_impl) : _mavsdk_impl(mavsdk_impl) |
15 | 190 | { |
16 | 191 | // No need for individual BufferParser - we'll use MavsdkImpl's thread-safe parsing |
@@ -116,80 +291,9 @@ std::string LibmavReceiver::libmav_message_to_json(const mav::Message& msg) cons |
116 | 291 | if (variant_opt) { |
117 | 292 | const auto& variant = variant_opt.value(); |
118 | 293 |
|
119 | | - // Convert variant to JSON string based on the field type |
| 294 | + // Convert variant to JSON string using extracted function |
120 | 295 | std::visit( |
121 | | - [&json_stream](const auto& value) { |
122 | | - using T = std::decay_t<decltype(value)>; |
123 | | - |
124 | | - if constexpr ( |
125 | | - std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> || |
126 | | - std::is_same_v<T, uint32_t> || std::is_same_v<T, uint64_t> || |
127 | | - std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t> || |
128 | | - std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t>) { |
129 | | - json_stream << static_cast<int64_t>(value); |
130 | | - } else if constexpr (std::is_same_v<T, char>) { |
131 | | - json_stream << static_cast<int>(value); |
132 | | - } else if constexpr ( |
133 | | - std::is_same_v<T, float> || std::is_same_v<T, double>) { |
134 | | - if (!std::isfinite(value)) { |
135 | | - json_stream << "null"; |
136 | | - } else { |
137 | | - json_stream << value; |
138 | | - } |
139 | | - } else if constexpr (std::is_same_v<T, std::string>) { |
140 | | - json_stream << "\"" << value << "\""; |
141 | | - } else if constexpr ( |
142 | | - std::is_same_v<T, std::vector<uint8_t>> || |
143 | | - std::is_same_v<T, std::vector<int8_t>>) { |
144 | | - // Handle uint8_t/int8_t vectors specially to avoid character output |
145 | | - json_stream << "["; |
146 | | - bool first = true; |
147 | | - for (const auto& elem : value) { |
148 | | - if (!first) |
149 | | - json_stream << ","; |
150 | | - first = false; |
151 | | - json_stream << static_cast<int>(elem); |
152 | | - } |
153 | | - json_stream << "]"; |
154 | | - } else if constexpr ( |
155 | | - std::is_same_v<T, std::vector<uint16_t>> || |
156 | | - std::is_same_v<T, std::vector<uint32_t>> || |
157 | | - std::is_same_v<T, std::vector<uint64_t>> || |
158 | | - std::is_same_v<T, std::vector<int16_t>> || |
159 | | - std::is_same_v<T, std::vector<int32_t>> || |
160 | | - std::is_same_v<T, std::vector<int64_t>>) { |
161 | | - // Handle integer vector types |
162 | | - json_stream << "["; |
163 | | - bool first = true; |
164 | | - for (const auto& elem : value) { |
165 | | - if (!first) |
166 | | - json_stream << ","; |
167 | | - first = false; |
168 | | - json_stream << elem; |
169 | | - } |
170 | | - json_stream << "]"; |
171 | | - } else if constexpr ( |
172 | | - std::is_same_v<T, std::vector<float>> || |
173 | | - std::is_same_v<T, std::vector<double>>) { |
174 | | - // Handle float/double vector types with NaN check |
175 | | - json_stream << "["; |
176 | | - bool first = true; |
177 | | - for (const auto& elem : value) { |
178 | | - if (!first) |
179 | | - json_stream << ","; |
180 | | - first = false; |
181 | | - if (!std::isfinite(elem)) { |
182 | | - json_stream << "null"; |
183 | | - } else { |
184 | | - json_stream << elem; |
185 | | - } |
186 | | - } |
187 | | - json_stream << "]"; |
188 | | - } else { |
189 | | - // Fallback for unknown types |
190 | | - json_stream << "null"; |
191 | | - } |
192 | | - }, |
| 296 | + [&json_stream](const auto& value) { value_to_json_stream(json_stream, value); }, |
193 | 297 | variant); |
194 | 298 | } else { |
195 | 299 | // Field not present or failed to extract |
|
0 commit comments