Motion Master
Loading...
Searching...
No Matches
util.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <bit>
5#include <charconv>
6#include <chrono>
7#include <condition_variable>
8#include <cstdint>
9#include <cstring>
10#include <fstream>
11#include <iostream>
12#include <iterator>
13#include <map>
14#include <memory>
15#include <mutex>
16#include <nlohmann/json.hpp>
17#include <optional>
18#include <queue>
19#include <set>
20#include <sstream>
21#include <string>
22#include <string_view>
23#include <thread>
24#include <type_traits>
25#include <typeindex>
26#include <unordered_map>
27#include <utility>
28#include <variant>
29#include <vector>
30
31namespace mm::core::util {
32
51template <typename T>
52T parseHex(const std::string& s) {
53 static_assert(std::is_unsigned<T>::value,
54 "parseHex only supports unsigned integer types");
55
56 // Use the appropriate std::stoul or std::stoull depending on size
57 if constexpr (sizeof(T) <= sizeof(unsigned long)) {
58 // Use std::stoul
59 return static_cast<T>(std::stoul(s, nullptr, 16));
60 } else {
61 // Use std::stoull for larger types like uint64_t
62 return static_cast<T>(std::stoull(s, nullptr, 16));
63 }
64}
65
76enum class Endianness { LITTLE, BIG };
77
101template <typename T>
102T toInteger(const std::vector<std::uint8_t>& data, std::size_t offset = 0,
104 // Ensure T is an integral type
105 static_assert(std::is_integral<T>::value, "T must be an integral type");
106
107 // Use unsigned type for accumulation to avoid sign extension issues
108 using U = typename std::make_unsigned<T>::type;
109 U value = 0;
110
111 // Check if offset is within bounds
112 // If offset is greater than the size of data, return 0
113 std::size_t remaining = (data.size() > offset) ? (data.size() - offset) : 0;
114 std::size_t byteCount = (sizeof(T) < remaining) ? sizeof(T) : remaining;
115
116 if (endian == Endianness::LITTLE) {
117 for (std::size_t i = 0; i < byteCount; ++i) {
118 value |= static_cast<U>(data[offset + i]) << (8 * i);
119 }
120 } else {
121 for (std::size_t i = 0; i < byteCount; ++i) {
122 value |= static_cast<U>(data[offset + i]) << (8 * (sizeof(T) - 1 - i));
123 }
124 }
125
126 return static_cast<T>(value);
127}
128
136std::vector<std::vector<uint8_t>> splitIntoParts(
137 const std::vector<uint8_t>& input, size_t partSize);
138
157std::vector<uint8_t> zipData(const std::string& filename,
158 const std::vector<uint8_t>& data);
159
176std::unordered_map<std::string, std::vector<uint8_t>> unzipData(
177 const std::vector<uint8_t>& data);
178
195template <typename T>
196bool stringViewToNumber(std::string_view sv, T& result) {
197 static_assert(std::is_arithmetic_v<T>, "T must be an arithmetic type");
198
199 auto [ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.size(), result);
200 return ec == std::errc();
201}
202
218template <typename T>
219std::vector<uint8_t> toBytes(T value, bool bigEndian = false) {
220 static_assert(std::is_trivially_copyable<T>::value,
221 "T must be trivially copyable");
222
223 std::vector<uint8_t> bytes(sizeof(T));
224 std::memcpy(bytes.data(), &value, sizeof(T));
225
226 if (bigEndian) {
227 std::reverse(bytes.begin(), bytes.end());
228 }
229
230 return bytes;
231}
232
253template <typename T>
254T fromBytes(const std::vector<uint8_t>& bytes, bool bigEndian = false) {
255 static_assert(std::is_trivially_copyable<T>::value,
256 "T must be trivially copyable");
257
258 if (bytes.size() != sizeof(T)) {
259 throw std::invalid_argument(
260 "Byte vector size does not match target type size");
261 }
262
263 std::vector<uint8_t> temp = bytes;
264
265 if (bigEndian) {
266 std::reverse(temp.begin(), temp.end());
267 }
268
269 T value;
270 std::memcpy(&value, temp.data(), sizeof(T));
271 return value;
272}
273
288inline std::string makeParameterId(int index, int subindex) {
289 std::stringstream oss;
290 // Format index and subindex into "0xINDEX:SUBINDEX"
291 oss << "0x" << std::setw(4) << std::setfill('0') << std::hex << std::uppercase
292 << index << ":" << std::setw(2) << std::setfill('0') << std::hex
293 << std::uppercase << subindex;
294
295 return oss.str();
296}
297
309inline std::string toHex(const std::vector<uint8_t>& data) {
310 std::ostringstream oss;
311 oss << std::uppercase; // Ensure hex letters are uppercase
312 for (size_t i = 0; i < data.size(); ++i) {
313 oss << "0x" << std::hex << std::setw(2) << std::setfill('0')
314 << static_cast<int>(data[i]);
315 if (i != data.size() - 1) {
316 oss << " ";
317 }
318 }
319 return oss.str();
320}
321
335template <typename T>
336inline std::string toHex(T value) {
337 static_assert(std::is_integral<T>::value, "toHex requires an integer type");
338 constexpr size_t hexWidth = sizeof(T) * 2;
339
340 std::ostringstream oss;
341 oss << "0x" << std::hex << std::uppercase << std::setw(hexWidth)
342 << std::setfill('0') << static_cast<uint64_t>(value);
343 return oss.str();
344}
345
357std::vector<uint8_t> readBinaryFile(const std::string& filename);
358
367std::string readTextFile(const std::string& filename);
368
381std::string joinStrings(const std::vector<std::string>& list,
382 const std::string& delimiter);
383
398std::string formatMacAddress(const std::string& originalMacAddress);
399
409std::string extractIpAddress(const std::string& socketAddress);
410
422unsigned short extractPort(const std::string& socketAddress);
423
431inline bool endsWith(const std::string& str, const std::string& suffix) {
432 return str.size() >= suffix.size() &&
433 std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
434}
435
443inline size_t countStringsStartingWith(const std::vector<std::string>& strings,
444 const std::string& prefix) {
445 return std::count_if(
446 strings.begin(), strings.end(), [&](const std::string& s) {
447 return s.rfind(prefix, 0) == 0; // checks if s starts with prefix
448 });
449}
450
462inline std::vector<std::string> split(const std::string& input,
463 char delimiter) {
464 std::vector<std::string> result;
465 std::istringstream stream(input);
466 std::string token;
467
468 while (std::getline(stream, token, delimiter)) {
469 result.push_back(token);
470 }
471
472 return result;
473}
474
483template <typename T>
485 private:
487 std::queue<T> queue_;
488
490 mutable std::mutex mtx_;
491
493 std::condition_variable cv_;
494
495 public:
499 ThreadSafeQueue() = default;
500
505
510
516 void push(T value) {
517 {
518 std::lock_guard<std::mutex> lock(mtx_);
519 queue_.push(std::move(value));
520 }
521 cv_.notify_one();
522 }
523
530 std::optional<T> try_pop() {
531 std::lock_guard<std::mutex> lock(mtx_);
532 if (queue_.empty()) return std::nullopt;
533 T value = std::move(queue_.front());
534 queue_.pop();
535 return value;
536 }
537
546 std::unique_lock<std::mutex> lock(mtx_);
547 cv_.wait(lock, [this] { return !queue_.empty(); });
548 T value = std::move(queue_.front());
549 queue_.pop();
550 return value;
551 }
552
558 bool empty() const {
559 std::lock_guard<std::mutex> lock(mtx_);
560 return queue_.empty();
561 }
562
570 size_t size() const {
571 std::lock_guard<std::mutex> lock(mtx_);
572 return queue_.size();
573 }
574};
575
585inline int64_t currentTimeMillis() {
586 // Get current time point from system clock
587 auto now = std::chrono::system_clock::now();
588
589 // Convert to duration since epoch in milliseconds
590 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
591 now.time_since_epoch());
592
593 // Return the count as an integer (int64_t)
594 return duration.count();
595}
596
608template <typename T>
609inline constexpr T linearScale(T value, T inMin, T inMax, T outMin, T outMax) {
610 static_assert(std::is_arithmetic<T>::value,
611 "linearScale requires a numeric type");
612 return outMin + (value - inMin) * (outMax - outMin) / (inMax - inMin);
613}
614
615} // namespace mm::core::util
616
627namespace std {
628template <>
629struct hash<std::pair<uint16_t, uint8_t>> {
640 size_t operator()(const std::pair<uint16_t, uint8_t>& p) const {
641 return hash<uint16_t>()(p.first) ^ (hash<uint8_t>()(p.second) << 1);
642 }
643};
644
645} // namespace std
A simple thread-safe FIFO queue.
Definition: util.h:484
ThreadSafeQueue & operator=(const ThreadSafeQueue &)=delete
Deleted copy assignment operator.
T wait_and_pop()
Wait for an item to be available and pop it.
Definition: util.h:545
void push(T value)
Push a new value into the queue.
Definition: util.h:516
ThreadSafeQueue(const ThreadSafeQueue &)=delete
Deleted copy constructor.
bool empty() const
Check whether the queue is empty.
Definition: util.h:558
std::optional< T > try_pop()
Try to pop a value from the queue without blocking.
Definition: util.h:530
size_t size() const
Get the current number of items in the queue.
Definition: util.h:570
ThreadSafeQueue()=default
Construct a new empty ThreadSafeQueue.
uint8_t * value
Definition: co_dictionary.h:9
uint16_t index
Definition: co_dictionary.h:0
Definition: util.cc:11
std::string joinStrings(const std::vector< std::string > &list, const std::string &delimiter)
Joins a list of strings into a single string with a delimiter.
Definition: util.cc:152
bool stringViewToNumber(std::string_view sv, T &result)
Converts a string_view to a numeric type.
Definition: util.h:196
std::vector< std::vector< uint8_t > > splitIntoParts(const std::vector< uint8_t > &input, size_t partSize)
Splits a byte vector into parts of a specified maximum size.
Definition: util.cc:13
int64_t currentTimeMillis()
Gets the current system time in milliseconds since the Unix epoch.
Definition: util.h:585
std::vector< uint8_t > zipData(const std::string &filename, const std::vector< uint8_t > &data)
Compresses a block of data into a ZIP archive containing a single file.
Definition: util.cc:31
Endianness
Specifies the byte order used when converting a byte sequence to an integer.
Definition: util.h:76
size_t countStringsStartingWith(const std::vector< std::string > &strings, const std::string &prefix)
Count how many strings in the list start with the given prefix.
Definition: util.h:443
T parseHex(const std::string &s)
Parses a hexadecimal string into an unsigned integer of type T.
Definition: util.h:52
std::string readTextFile(const std::string &filePath)
Reads the entire content of a text file into a std::string.
Definition: util.cc:138
unsigned short extractPort(const std::string &socketAddress)
Extracts the port number from a socket address string.
Definition: util.cc:199
bool endsWith(const std::string &str, const std::string &suffix)
Checks whether a string ends with the given suffix.
Definition: util.h:431
std::vector< std::string > split(const std::string &input, char delimiter)
Splits a string into substrings based on a delimiter character.
Definition: util.h:462
std::string extractIpAddress(const std::string &socketAddress)
Extracts the IP address from a socket address string.
Definition: util.cc:191
constexpr T linearScale(T value, T inMin, T inMax, T outMin, T outMax)
Definition: util.h:609
T fromBytes(const std::vector< uint8_t > &bytes, bool bigEndian=false)
Reconstructs a value of type T from a byte vector.
Definition: util.h:254
std::string toHex(const std::vector< uint8_t > &data)
Converts a vector of bytes to a space-separated hexadecimal string.
Definition: util.h:309
std::string formatMacAddress(const std::string &originalMacAddress)
Formats a MAC address string to ensure each component is two digits and uppercase.
Definition: util.cc:167
std::string makeParameterId(int index, int subindex)
Formats the given index and subindex into a parameter identifier string.
Definition: util.h:288
std::unordered_map< std::string, std::vector< uint8_t > > unzipData(const std::vector< uint8_t > &data)
Unzips a ZIP archive from an in-memory byte buffer.
Definition: util.cc:66
T toInteger(const std::vector< std::uint8_t > &data, std::size_t offset=0, Endianness endian=Endianness::LITTLE)
Converts a byte sequence to an integer of type T with optional offset and endianness.
Definition: util.h:102
std::vector< uint8_t > readBinaryFile(const std::string &filePath)
Reads the entire contents of a binary file into a byte vector.
Definition: util.cc:125
std::vector< uint8_t > toBytes(T value, bool bigEndian=false)
Converts a trivially copyable value to a byte vector.
Definition: util.h:219
Specialization of std::hash for std::pair<uint16_t, uint8_t>.
Definition: util.h:627
size_t operator()(const std::pair< uint16_t, uint8_t > &p) const
Computes a hash for a given std::pair<uint16_t, uint8_t>.
Definition: util.h:640