重新设置代码格式

This commit is contained in:
2026-06-25 15:44:25 +08:00
parent 6a87cf52a8
commit 26b5c8a54d
123 changed files with 34632 additions and 35952 deletions
File diff suppressed because it is too large Load Diff
+269 -280
View File
@@ -10,300 +10,289 @@
#include <type_traits>
namespace yC {
template <typename T = std::pmr::string>
typename std::enable_if<std::is_same<T, std::pmr::string>::value, T>::type
create_string(size_t size, std::pmr::memory_resource* resource = nullptr) {
std::pmr::memory_resource* r = resource ? resource : std::pmr::get_default_resource();
std::pmr::string ret(r);
ret.resize(size);
return ret; // 返回 std::pmr::string
}
template <typename T = std::string>
typename std::enable_if<std::is_same<T, std::string>::value, T>::type
create_string(size_t size, std::pmr::memory_resource* resource = nullptr) {
std::string ret;
ret.resize(size);
return ret; // 返回 std::string
}
template <typename T>
struct cacl_type {
using type = T;
size_t size(T& a) {
return a.size();
}
static void* data(T& a) {
return (void*)a.data();
}
static size_t size(const T& a) {
return a.size();
}
static void* data(const T& a) {
return (void*)a.data();
}
};
template <>
struct cacl_type<const char*> {
using type = std::string;
static size_t size(const char* a) {return strlen(a);}
static void* data(const char* a) {return (void*)a;}
};
template <size_t N>
struct cacl_type<char[N]> {
using type = std::string;
static size_t size(const char (&a)[N]) { return N - 1; }
static void* data(const char (&a)[N]) { return (void*)a; }
};
template <size_t N>
struct cacl_type<const char[N]> {
using type = std::string;
static size_t size(const char (&a)[N]) { return N - 1; }
static void* data(const char (&a)[N]) { return (void*)a; }
};
template <typename T = std::pmr::string>
typename std::enable_if<std::is_same<T, std::pmr::string>::value, T>::type
create_string(size_t size, std::pmr::memory_resource *resource = nullptr) {
std::pmr::memory_resource *r =
resource ? resource : std::pmr::get_default_resource();
std::pmr::string ret(r);
ret.resize(size);
return ret; // 返回 std::pmr::string
}
template <typename T = std::string>
typename std::enable_if<std::is_same<T, std::string>::value, T>::type
create_string(size_t size, std::pmr::memory_resource *resource = nullptr) {
std::string ret;
ret.resize(size);
return ret; // 返回 std::string
}
template <typename T> struct cacl_type {
using type = T;
size_t size(T &a) { return a.size(); }
static void *data(T &a) { return (void *)a.data(); }
static size_t size(const T &a) { return a.size(); }
static void *data(const T &a) { return (void *)a.data(); }
};
template <> struct cacl_type<const char *> {
using type = std::string;
static size_t size(const char *a) { return strlen(a); }
static void *data(const char *a) { return (void *)a; }
};
#define Base template <typename allocator_type = std::allocator<char>, \
typename STR_Type = std::basic_string<char, std::char_traits<char>, allocator_type>, \
typename ret_type = typename cacl_type<STR_Type>::type \
>
template <size_t N> struct cacl_type<char[N]> {
using type = std::string;
static size_t size(const char (&a)[N]) { return N - 1; }
static void *data(const char (&a)[N]) { return (void *)a; }
};
template <size_t N> struct cacl_type<const char[N]> {
using type = std::string;
static size_t size(const char (&a)[N]) { return N - 1; }
static void *data(const char (&a)[N]) { return (void *)a; }
};
} // namespace yC
#define Base \
template <typename allocator_type = std::allocator<char>, \
typename STR_Type = std::basic_string< \
char, std::char_traits<char>, allocator_type>, \
typename ret_type = typename cacl_type<STR_Type>::type>
// #define Base template <\
// typename STR_Type, \
// typename ret_type = typename cacl_type<STR_Type>::type \
// >
namespace yC {
// 检查当前机器是否是大端字节序
extern const bool is_big_endian;
void big_endian_2_platform(void* dest, const char* d, size_t size);
void little_endian_2_platform(void* dest, const char* d, size_t size);
// 检查当前机器是否是大端字节序
extern const bool is_big_endian;
void big_endian_2_platform(void *dest, const char *d, size_t size);
void little_endian_2_platform(void *dest, const char *d, size_t size);
void big_endian_2_platform(const std::string &big_endian, char *dest);
void little_endian_2_platform(const std::string &little_endian, char *dest);
std::string big_endian_2_platform(const std::string &big_endian);
std::string little_endian_2_platform(const std::string &little_endian);
std::string platform_2_big_endian(void *memory, int size);
std::string platform_2_little_endian(void *memory, int size);
void big_endian_2_platform(const std::string& big_endian, char* dest);
void little_endian_2_platform(const std::string& little_endian, char* dest);
std::string big_endian_2_platform(const std::string& big_endian);
std::string little_endian_2_platform(const std::string& little_endian);
std::string platform_2_big_endian(void* memory, int size);
std::string platform_2_little_endian(void* memory, int size);
inline size_t get_xor_hex_size(size_t n1, size_t n2){return std::max(n1, n2);}
void xor_hex_Ex(void* dest, const char* s1, size_t n1, const char* s2, size_t n2, bool big_dian, bool is_upper);
Base
ret_type xorHex(const STR_Type& s1, const STR_Type& s2, std::pmr::memory_resource* resource = nullptr) {
auto n1 = cacl_type<STR_Type>::size(s1);
auto n2 = cacl_type<STR_Type>::size(s2);
auto size = get_xor_hex_size(n1, n2);
auto ret = create_string<ret_type>(size, resource);
xor_hex_Ex((void*)ret.data(), (const char*)cacl_type<STR_Type>::data(s1), n1, (const char*)cacl_type<STR_Type>::data(s2), n2, true, true);
return ret;
}
inline size_t get_xor_bin_size(size_t n1, size_t n2){return std::max(n1, n2);}
void xor_bin_Ex(void* dest, const char* s1, size_t n1, const char* s2, size_t n2, bool big_dian);
Base
ret_type xorBin(const STR_Type& s1, const STR_Type& s2, std::pmr::memory_resource* resource = nullptr) {
auto n1 = cacl_type<STR_Type>::size(s1);
auto n2 = cacl_type<STR_Type>::size(s2);
auto size = get_xor_bin_size(n1, n2);
auto ret = create_string<ret_type>(size, resource);
xor_bin_Ex((void*)ret.data(), (const char*)cacl_type<STR_Type>::data(s1), n1, (const char*)cacl_type<STR_Type>::data(s2), n2, true);
return ret;
}
inline size_t get_bin2hex_size(size_t num) {return (num + 3) / 4;}
void bin2hex_Ex(void* dest, const char* data, size_t size, bool big_dian, bool isupper);
Base
ret_type bin2hex(const STR_Type& mem, std::pmr::memory_resource* resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret = create_string<ret_type>(get_bin2hex_size(size), resource);
bin2hex_Ex((void*)ret.data(), (const char*)cacl_type<STR_Type>::data(mem), size, true, true);
return ret;
}
inline size_t get_hex2bin_size(size_t num) {return num * 4;}
void hex2bin_Ex(void* dest, const char* data, size_t size, bool big_dian);
Base
ret_type hex2bin(const STR_Type& mem, std::pmr::memory_resource* resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret = create_string<ret_type>(get_hex2bin_size(size), resource);
hex2bin_Ex((void*)ret.data(), (const char*)cacl_type<STR_Type>::data(mem), size, true);
return ret;
}
inline size_t get_bin2mem_size(size_t num) {return num/8;};
void bin2mem(void* dest, const char* data, size_t size);
Base
STR_Type bin2mem(const STR_Type& mem, std::pmr::memory_resource* resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret = create_string<STR_Type>(get_bin2mem_size(size), resource);
bin2mem((void*)ret.data(), (const char*)cacl_type<STR_Type>::data(mem), size);
return ret;
}
// inline ret_str bin2mem(param_str mem, std::pmr::memory_resource* resource = nullptr) {
// auto size = mem.size();
// auto ret = ret_str();
// ret.resize(get_bin2mem_size(size));
// bin2mem((void*)ret.data(), (const char*)mem.data(), size);
// return ret;
// }
inline size_t get_hex2mem_size(size_t hex_hum) {return hex_hum/2;};
void hex2mem_Ex(void* dest, const char* data, size_t size);
Base
STR_Type hex2mem(const STR_Type& mem, std::pmr::memory_resource* resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret = create_string<STR_Type>(get_hex2mem_size(size), resource);
hex2mem_Ex((void*)ret.data(), (const char*)cacl_type<STR_Type>::data(mem), size);
return ret;
}
// inline ret_str hex2mem(param_str hex, std::pmr::memory_resource* resource = nullptr) {
// auto size = hex.size();
// auto ret = ret_str();
// ret.resize(get_hex2mem_size(size));
// hex2mem_Ex((void*)ret.data(), (const char*)hex.data(), size);
// return ret;
// }
inline size_t get_mem2hex_size(size_t num, size_t middle_len) { return num * 2 + (num - 1) * middle_len;}
void mem2hex_Ex2(void* dest, void* mem, size_t num, bool uppercase, const char* middle, size_t middle_len = std::numeric_limits<size_t>::max());
Base
STR_Type mem2hex(const STR_Type& mem, bool uppercase = true, const std::string& middle = "", std::pmr::memory_resource* resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret = create_string<STR_Type>(get_mem2hex_size(size, middle.size()), resource);
mem2hex_Ex2(ret.data(), cacl_type<STR_Type>::data(mem), size, uppercase, middle.data(), middle.size());
return ret;
}
// inline ret_str mem2hex(param_str& mem, bool uppercase = true, const std::string& middle = "", std::pmr::memory_resource* resource = nullptr) {
// auto size = get_mem2hex_size(mem.size(), middle.size());
// auto ret = ret_str();
// mem2hex_Ex2(ret.data(), (void*)mem.data(), size, uppercase, middle.data(), middle.size());
// return ret;
// }
template <int start, int len>
void get_bin(std::string& msg, int& n) {
n = std::bitset<len>(msg.substr(start, len)).to_ullong();
}
template <int start, int len, typename Enum>
void get_bin(std::string& msg, Enum& n) {
n = static_cast<Enum>(std::bitset<len>(msg.substr(start, len)).to_ullong());
}
template <int start, int len, typename Enum>
Enum get_bin(std::string& msg) {
return static_cast<Enum>(std::bitset<len>(msg.substr(start, len)).to_ullong());
}
template <int start, int len>
int get_bin(const std::string& msg) {
return std::bitset<len>(msg.substr(start, len)).to_ullong();
}
template <int start, int len>
void set_bin(std::string& msg, unsigned long long n) {
msg.replace(start, len, std::bitset<len>(n).to_string());
}
template <int start, int len>
void set_bin(std::string& msg, const std::string& value) {
if (value.size() != len) {
std::cout << "len == " << len << " bits.size() == " << value.size() << std::endl;
throw std::out_of_range("Start position and length exceed bit string size");
}
msg.replace(start, len, value);
}
template <int len>
std::string to_bin(unsigned long long n) {
return std::bitset<len>(n).to_string();
}
template <int num>
std::string to_bin(double n) {
return std::bitset<num>(static_cast<unsigned long long>(n)).to_string();
}
template <typename T>
T bin2(const std::string& binstr) {
return std::stoull(binstr, nullptr, 2);
}
template <typename T>
unsigned long long hex2(const std::string& hexstr) {
return std::stoull(hexstr, nullptr, 16);
}
template <>
inline int bin2<int>(const std::string& binstr) {
int bit_limit = sizeof(int) * 8;
if (binstr.size() > bit_limit) {
std::cout << "Bitset.h inline int bin2<int> error! Binary string exceeds int bit limit" << std::endl;
}
return std::stoi(binstr, nullptr, 2);
}
// 设置dest的从off位起n位,写入value的低n位
template <typename T = std::uint64_t>
void set_bits(void* dest, size_t off, size_t n, T value) {
auto d = static_cast<uint8_t*>(dest);
size_t bit_pos = off;
size_t val_pos = 0;
while (n > 0) {
size_t byte_idx = bit_pos / 8;
size_t bit_in_byte = bit_pos % 8;
size_t bits_in_this_byte = std::min(n, 8 - bit_in_byte);
// 为当前字节构建掩码
uint8_t mask = ((1u << bits_in_this_byte) - 1) << bit_in_byte;
// 取value对应的低bits_in_this_byte位
uint8_t v = (value >> val_pos) & ((1u << bits_in_this_byte) - 1);
// 清除目标字节对应位置后设置
d[byte_idx] = (d[byte_idx] & ~mask) | ((v << bit_in_byte) & mask);
bit_pos += bits_in_this_byte;
val_pos += bits_in_this_byte;
n -= bits_in_this_byte;
}
}
// 大批量位处理性能不好 但是通常也没有这样的场景
void bit_move(void* d, size_t doff, const void* s, size_t soff, size_t n);
void bit_xor(void* d, size_t doff, const void* s, size_t soff, size_t n);
void bit_or(void* d, size_t doff, const void* s, size_t soff, size_t n);
void bit_and(void* d, size_t doff, const void* s, size_t soff, size_t n);
template <typename T = std::uint64_t>
T get_bits(void* src, size_t off, size_t n) {
auto s = static_cast<const uint8_t*>(src);
size_t bit_pos = off;
size_t val_pos = 0;
T result = 0;
while (n > 0) {
size_t byte_idx = bit_pos / 8;
size_t bit_in_byte = bit_pos % 8;
size_t bits_in_this_byte = std::min(n, 8 - bit_in_byte);
uint8_t mask = ((1u << bits_in_this_byte) - 1) << bit_in_byte;
uint8_t bits = (s[byte_idx] & mask) >> bit_in_byte;
result |= (T(bits) << val_pos);
bit_pos += bits_in_this_byte;
val_pos += bits_in_this_byte;
n -= bits_in_this_byte;
}
return result;
}
inline size_t get_xor_hex_size(size_t n1, size_t n2) {
return std::max(n1, n2);
}
void xor_hex_Ex(void *dest, const char *s1, size_t n1, const char *s2,
size_t n2, bool big_dian, bool is_upper);
Base ret_type xorHex(const STR_Type &s1, const STR_Type &s2,
std::pmr::memory_resource *resource = nullptr) {
auto n1 = cacl_type<STR_Type>::size(s1);
auto n2 = cacl_type<STR_Type>::size(s2);
auto size = get_xor_hex_size(n1, n2);
auto ret = create_string<ret_type>(size, resource);
xor_hex_Ex((void *)ret.data(), (const char *)cacl_type<STR_Type>::data(s1),
n1, (const char *)cacl_type<STR_Type>::data(s2), n2, true, true);
return ret;
}
inline size_t get_xor_bin_size(size_t n1, size_t n2) {
return std::max(n1, n2);
}
void xor_bin_Ex(void *dest, const char *s1, size_t n1, const char *s2,
size_t n2, bool big_dian);
Base ret_type xorBin(const STR_Type &s1, const STR_Type &s2,
std::pmr::memory_resource *resource = nullptr) {
auto n1 = cacl_type<STR_Type>::size(s1);
auto n2 = cacl_type<STR_Type>::size(s2);
auto size = get_xor_bin_size(n1, n2);
auto ret = create_string<ret_type>(size, resource);
xor_bin_Ex((void *)ret.data(), (const char *)cacl_type<STR_Type>::data(s1),
n1, (const char *)cacl_type<STR_Type>::data(s2), n2, true);
return ret;
}
inline size_t get_bin2hex_size(size_t num) { return (num + 3) / 4; }
void bin2hex_Ex(void *dest, const char *data, size_t size, bool big_dian,
bool isupper);
Base ret_type bin2hex(const STR_Type &mem,
std::pmr::memory_resource *resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret = create_string<ret_type>(get_bin2hex_size(size), resource);
bin2hex_Ex((void *)ret.data(), (const char *)cacl_type<STR_Type>::data(mem),
size, true, true);
return ret;
}
inline size_t get_hex2bin_size(size_t num) { return num * 4; }
void hex2bin_Ex(void *dest, const char *data, size_t size, bool big_dian);
Base ret_type hex2bin(const STR_Type &mem,
std::pmr::memory_resource *resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret = create_string<ret_type>(get_hex2bin_size(size), resource);
hex2bin_Ex((void *)ret.data(), (const char *)cacl_type<STR_Type>::data(mem),
size, true);
return ret;
}
inline size_t get_bin2mem_size(size_t num) { return num / 8; };
void bin2mem(void *dest, const char *data, size_t size);
Base STR_Type bin2mem(const STR_Type &mem,
std::pmr::memory_resource *resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret = create_string<STR_Type>(get_bin2mem_size(size), resource);
bin2mem((void *)ret.data(), (const char *)cacl_type<STR_Type>::data(mem),
size);
return ret;
}
// inline ret_str bin2mem(param_str mem, std::pmr::memory_resource* resource =
// nullptr) {
// auto size = mem.size();
// auto ret = ret_str();
// ret.resize(get_bin2mem_size(size));
// bin2mem((void*)ret.data(), (const char*)mem.data(), size);
// return ret;
// }
inline size_t get_hex2mem_size(size_t hex_hum) { return hex_hum / 2; };
void hex2mem_Ex(void *dest, const char *data, size_t size);
Base STR_Type hex2mem(const STR_Type &mem,
std::pmr::memory_resource *resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret = create_string<STR_Type>(get_hex2mem_size(size), resource);
hex2mem_Ex((void *)ret.data(), (const char *)cacl_type<STR_Type>::data(mem),
size);
return ret;
}
// inline ret_str hex2mem(param_str hex, std::pmr::memory_resource* resource =
// nullptr) {
// auto size = hex.size();
// auto ret = ret_str();
// ret.resize(get_hex2mem_size(size));
// hex2mem_Ex((void*)ret.data(), (const char*)hex.data(), size);
// return ret;
// }
inline size_t get_mem2hex_size(size_t num, size_t middle_len) {
return num * 2 + (num - 1) * middle_len;
}
void mem2hex_Ex2(void *dest, void *mem, size_t num, bool uppercase,
const char *middle,
size_t middle_len = std::numeric_limits<size_t>::max());
Base STR_Type mem2hex(const STR_Type &mem, bool uppercase = true,
const std::string &middle = "",
std::pmr::memory_resource *resource = nullptr) {
auto size = cacl_type<STR_Type>::size(mem);
auto ret =
create_string<STR_Type>(get_mem2hex_size(size, middle.size()), resource);
mem2hex_Ex2(ret.data(), cacl_type<STR_Type>::data(mem), size, uppercase,
middle.data(), middle.size());
return ret;
}
// inline ret_str mem2hex(param_str& mem, bool uppercase = true, const
// std::string& middle = "", std::pmr::memory_resource* resource = nullptr) {
// auto size = get_mem2hex_size(mem.size(), middle.size());
// auto ret = ret_str();
// mem2hex_Ex2(ret.data(), (void*)mem.data(), size, uppercase,
// middle.data(), middle.size()); return ret;
// }
template <int start, int len> void get_bin(std::string &msg, int &n) {
n = std::bitset<len>(msg.substr(start, len)).to_ullong();
}
template <int start, int len, typename Enum>
void get_bin(std::string &msg, Enum &n) {
n = static_cast<Enum>(std::bitset<len>(msg.substr(start, len)).to_ullong());
}
template <int start, int len, typename Enum> Enum get_bin(std::string &msg) {
return static_cast<Enum>(
std::bitset<len>(msg.substr(start, len)).to_ullong());
}
template <int start, int len> int get_bin(const std::string &msg) {
return std::bitset<len>(msg.substr(start, len)).to_ullong();
}
template <int start, int len>
void set_bin(std::string &msg, unsigned long long n) {
msg.replace(start, len, std::bitset<len>(n).to_string());
}
template <int start, int len>
void set_bin(std::string &msg, const std::string &value) {
if (value.size() != len) {
std::cout << "len == " << len << " bits.size() == " << value.size()
<< std::endl;
throw std::out_of_range("Start position and length exceed bit string size");
}
msg.replace(start, len, value);
}
template <int len> std::string to_bin(unsigned long long n) {
return std::bitset<len>(n).to_string();
}
template <int num> std::string to_bin(double n) {
return std::bitset<num>(static_cast<unsigned long long>(n)).to_string();
}
template <typename T> T bin2(const std::string &binstr) {
return std::stoull(binstr, nullptr, 2);
}
template <typename T> unsigned long long hex2(const std::string &hexstr) {
return std::stoull(hexstr, nullptr, 16);
}
template <> inline int bin2<int>(const std::string &binstr) {
int bit_limit = sizeof(int) * 8;
if (binstr.size() > bit_limit) {
std::cout << "Bitset.h inline int bin2<int> error! Binary string exceeds "
"int bit limit"
<< std::endl;
}
return std::stoi(binstr, nullptr, 2);
}
// 设置dest的从off位起n位,写入value的低n位
template <typename T = std::uint64_t>
void set_bits(void *dest, size_t off, size_t n, T value) {
auto d = static_cast<uint8_t *>(dest);
size_t bit_pos = off;
size_t val_pos = 0;
while (n > 0) {
size_t byte_idx = bit_pos / 8;
size_t bit_in_byte = bit_pos % 8;
size_t bits_in_this_byte = std::min(n, 8 - bit_in_byte);
// 为当前字节构建掩码
uint8_t mask = ((1u << bits_in_this_byte) - 1) << bit_in_byte;
// 取value对应的低bits_in_this_byte位
uint8_t v = (value >> val_pos) & ((1u << bits_in_this_byte) - 1);
// 清除目标字节对应位置后设置
d[byte_idx] = (d[byte_idx] & ~mask) | ((v << bit_in_byte) & mask);
bit_pos += bits_in_this_byte;
val_pos += bits_in_this_byte;
n -= bits_in_this_byte;
}
}
// 大批量位处理性能不好 但是通常也没有这样的场景
void bit_move(void *d, size_t doff, const void *s, size_t soff, size_t n);
void bit_xor(void *d, size_t doff, const void *s, size_t soff, size_t n);
void bit_or(void *d, size_t doff, const void *s, size_t soff, size_t n);
void bit_and(void *d, size_t doff, const void *s, size_t soff, size_t n);
template <typename T = std::uint64_t>
T get_bits(void *src, size_t off, size_t n) {
auto s = static_cast<const uint8_t *>(src);
size_t bit_pos = off;
size_t val_pos = 0;
T result = 0;
while (n > 0) {
size_t byte_idx = bit_pos / 8;
size_t bit_in_byte = bit_pos % 8;
size_t bits_in_this_byte = std::min(n, 8 - bit_in_byte);
uint8_t mask = ((1u << bits_in_this_byte) - 1) << bit_in_byte;
uint8_t bits = (s[byte_idx] & mask) >> bit_in_byte;
result |= (T(bits) << val_pos);
bit_pos += bits_in_this_byte;
val_pos += bits_in_this_byte;
n -= bits_in_this_byte;
}
return result;
}
} // namespace yC
#undef Base
#endif
@@ -6,101 +6,102 @@
using namespace yC;
MLAT_timestamp::MLAT_timestamp() {
std::chrono::time_point<std::chrono::high_resolution_clock> t = std::chrono::high_resolution_clock::now();
// 获取当前的系统时间(秒)
std::chrono::duration duration_since_epoch = t.time_since_epoch();
// 获取秒数和纳秒数
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration_since_epoch);
auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(duration_since_epoch);
// 获取当天的秒数和纳秒数
this->daysec = seconds.count() % 86400; // 86400 = 24 * 60 * 60 (一天的秒数)
this->nanosec = nanoseconds.count() % 86400000000000; // 1秒 = 10^9纳秒
memory = bin2mem(to_bin_string());
parse_hhmmss();
std::chrono::time_point<std::chrono::high_resolution_clock> t =
std::chrono::high_resolution_clock::now();
// 获取当前的系统时间(秒)
std::chrono::duration duration_since_epoch = t.time_since_epoch();
// 获取秒数和纳秒数
auto seconds =
std::chrono::duration_cast<std::chrono::seconds>(duration_since_epoch);
auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(
duration_since_epoch);
// 获取当天的秒数和纳秒数
this->daysec = seconds.count() % 86400; // 86400 = 24 * 60 * 60 (一天的秒数)
this->nanosec = nanoseconds.count() % 86400000000000; // 1秒 = 10^9纳秒
memory = bin2mem(to_bin_string());
parse_hhmmss();
}
MLAT_timestamp::MLAT_timestamp(const std::string &memory_6) : memory(memory_6) {
assert(memory_6.size() == 6);
auto msg_bin = hex2bin(mem2hex(memory));
daysec = std::bitset<18>(msg_bin.substr(0, 18)).to_ulong();
nanosec = std::bitset<30>(msg_bin.substr(18, 30)).to_ulong();
parse_hhmmss();
MLAT_timestamp::MLAT_timestamp(const std::string& memory_6) : memory(memory_6) {
assert(memory_6.size() == 6);
auto msg_bin = hex2bin(mem2hex(memory));
daysec = std::bitset<18>(msg_bin.substr(0, 18)).to_ulong();
nanosec = std::bitset<30>(msg_bin.substr(18, 30)).to_ulong();
parse_hhmmss();
//assert(memory_6 == bin2mem(to_bin_string()), "MLAT_timestamp,内存转换错误!");
// assert(memory_6 == bin2mem(to_bin_string()),
// "MLAT_timestamp,内存转换错误!");
}
MLAT_timestamp::MLAT_timestamp(std::uint32_t daysec, std::uint32_t nanosec) : daysec(daysec), nanosec(nanosec) {
parse_hhmmss();
MLAT_timestamp::MLAT_timestamp(std::uint32_t daysec, std::uint32_t nanosec)
: daysec(daysec), nanosec(nanosec) {
parse_hhmmss();
}
std::string MLAT_timestamp::to_bin_string() const {
std::bitset<18> daysec_bits = daysec;
std::bitset<30> nanosec_bits = nanosec;
return daysec_bits.to_string() + nanosec_bits.to_string();
std::bitset<18> daysec_bits = daysec;
std::bitset<30> nanosec_bits = nanosec;
return daysec_bits.to_string() + nanosec_bits.to_string();
}
// std::string MLAT_timestamp::to_memory() {
// return bin2memory(to_bin_string());
// }
std::string MLAT_timestamp::to_memory() const {
return memory;
}
std::string MLAT_timestamp::to_memory() const { return memory; }
void MLAT_timestamp::parse_hhmmss() {
hh = (daysec/3600) % 24;
mm = (daysec/60) % 60;
ss = daysec % 60;
hh = (daysec / 3600) % 24;
mm = (daysec / 60) % 60;
ss = daysec % 60;
}
std::string packet_to_escape_format(std::string t) {
std::string result = "\x1a";
for (size_t i = 1; i < t.size(); ++i) {
result.push_back(t[i]); // 插入当前字符
if (t[i] == '\x1a') {
result.push_back('\x1a'); // 如果是 0x1a,插入另一个 0x1a
}
std::string packet_to_escape_format(std::string t) {
std::string result = "\x1a";
for (size_t i = 1; i < t.size(); ++i) {
result.push_back(t[i]); // 插入当前字符
if (t[i] == '\x1a') {
result.push_back('\x1a'); // 如果是 0x1a,插入另一个 0x1a
}
return result;
}
return result;
}
void Binary_Format_handle_buffer(std::string& buffer, const std::string& data, const std::function<void(std::string&)>& callback) {
size_t i = 0;
while (i < data.size()) {
if (data[i] == 0x1A) {
// 如果遇到起始标记 0x1A
if (i + 1 < data.size() && data[i + 1] == 0x1A) {
// 如果是转义的 0x1A 0x1A,继续处理
buffer.push_back(0x1A); // 添加一个正常的 0x1A 字节
i += 2; // 跳过这两个字节
} else {
// 检测到起始标记 0x1A,认为是新消息的开始
if (!buffer.empty()) {
// 如果当前消息 buffer 中已有数据,调用回调函数处理当前消息
callback(buffer);
buffer.clear(); // 清空当前消息的缓存
}
buffer.push_back(0x1A);
// 跳过当前的 SOP 标记 (0x1A)
i++;
}
} else
{
// 如果不是 0x1A,直接将数据添加到 buffer 中
buffer.push_back(data[i]);
i++;
void Binary_Format_handle_buffer(
std::string &buffer, const std::string &data,
const std::function<void(std::string &)> &callback) {
size_t i = 0;
while (i < data.size()) {
if (data[i] == 0x1A) {
// 如果遇到起始标记 0x1A
if (i + 1 < data.size() && data[i + 1] == 0x1A) {
// 如果是转义的 0x1A 0x1A,继续处理
buffer.push_back(0x1A); // 添加一个正常的 0x1A 字节
i += 2; // 跳过这两个字节
} else {
// 检测到起始标记 0x1A,认为是新消息的开始
if (!buffer.empty()) {
// 如果当前消息 buffer 中已有数据,调用回调函数处理当前消息
callback(buffer);
buffer.clear(); // 清空当前消息的缓存
}
buffer.push_back(0x1A);
// 跳过当前的 SOP 标记 (0x1A)
i++;
}
} else {
// 如果不是 0x1A,直接将数据添加到 buffer 中
buffer.push_back(data[i]);
i++;
}
}
}
// 9 + 2
// 9 + 7
// 9 + 14
std::string mode_s_msg_packet_to_server_packet(std::uint32_t id, std::string packet) {
std::string id_code = yC::platform_2_big_endian((char*)&id, sizeof(id));
//assert(id_code.size() == 4, "id.size != 4");
packet.insert(1, id_code.c_str(), 4);
return packet;
std::string mode_s_msg_packet_to_server_packet(std::uint32_t id,
std::string packet) {
std::string id_code = yC::platform_2_big_endian((char *)&id, sizeof(id));
// assert(id_code.size() == 4, "id.size != 4");
packet.insert(1, id_code.c_str(), 4);
return packet;
}
@@ -7,8 +7,8 @@ using namespace yC;
// *02E99619FACDAE;
// *8D3C5EE69901BD9540078D37335F;
// *7700;
inline std::string create_AVR_format(const std::string& msg_hex) {
return "*" + msg_hex + ";";
inline std::string create_AVR_format(const std::string &msg_hex) {
return "*" + msg_hex + ";";
}
// @016CE3671C7423FFE7AB7BFCAB;
@@ -16,120 +16,130 @@ inline std::string create_AVR_format(const std::string& msg_hex) {
// @016CE3671C747700;
// @5500068BA46CB402c18d34fc8000;
inline std::string create_MLAT_AVR_format(const std::string& msg_hex, MLAT_timestamp* timestamp) {
//std::string signal_level_str = bin2hex(std::bitset<8>(signal_level).to_string());
//std::cout << "signal:" << signal_level_str << std::endl;
return "@" + bin2hex(timestamp->to_bin_string()) + msg_hex + ";";
inline std::string create_MLAT_AVR_format(const std::string &msg_hex,
MLAT_timestamp *timestamp) {
// std::string signal_level_str =
// bin2hex(std::bitset<8>(signal_level).to_string()); std::cout << "signal:"
// << signal_level_str << std::endl;
return "@" + bin2hex(timestamp->to_bin_string()) + msg_hex + ";";
}
// Binary Format
// <esc> "1" : 6 byte MLAT timestamp, 1 byte signal level, 2 byte Mode-AC
// <esc> "2" : 6 byte MLAT timestamp, 1 byte signal level, 7 byte Mode-S short frame
// <esc> "3" : 6 byte MLAT timestamp, 1 byte signal level, 14 byte Mode-S long frame
// <esc> "4" : 6 byte MLAT timestamp, 1 byte unused, DIP switch configuration settings, time stamp error ticks as int8_t (1 tick is 15ns) (message "4" not on Mode-S Beast classic)
// <esc><esc>: true 0x1a
// <esc> is 0x1a, and "1", "2" and "3" are 0x31, 0x32 and 0x33
inline std::string create_Binary_Format_memory(const std::string& msg_hex, char signal_level, MLAT_timestamp* timestamp) {
std::string type;
switch (msg_hex.size()) {
case 4: type = '1';
break;
case 14: type = '2';
break;
case 28: type = '3';
break;
default: std::cerr << msg_hex << "create_Binary_Format error is not a valid binary format." << std::endl;
throw std::runtime_error("create_Binary_Format error!");
// <esc> "2" : 6 byte MLAT timestamp, 1 byte signal level, 7 byte Mode-S short
// frame <esc> "3" : 6 byte MLAT timestamp, 1 byte signal level, 14 byte Mode-S
// long frame <esc> "4" : 6 byte MLAT timestamp, 1 byte unused, DIP switch
// configuration settings, time stamp error ticks as int8_t (1 tick is 15ns)
// (message "4" not on Mode-S Beast classic) <esc><esc>: true 0x1a <esc> is
// 0x1a, and "1", "2" and "3" are 0x31, 0x32 and 0x33
inline std::string create_Binary_Format_memory(const std::string &msg_hex,
char signal_level,
MLAT_timestamp *timestamp) {
std::string type;
switch (msg_hex.size()) {
case 4:
type = '1';
break;
case 14:
type = '2';
break;
case 28:
type = '3';
break;
default:
std::cerr << msg_hex
<< "create_Binary_Format error is not a valid binary format."
<< std::endl;
throw std::runtime_error("create_Binary_Format error!");
}
std::string t = timestamp->to_memory() + signal_level + yC::hex2mem(msg_hex);
// std::cout << "msg_hex.size():" << msg_hex.size() << std::endl;
// std::cout << "hex2memory(msg_hex):" << hex2memory(msg_hex).size() <<
// std::endl; std::cout << t.size() << std::endl;
std::string result;
// 遍历原始字符串
for (size_t i = 0; i < t.size(); ++i) {
result.push_back(t[i]); // 插入当前字符
if (t[i] == '\x1a') {
result.push_back('\x1a'); // 如果是 0x1a,插入另一个 0x1a
}
}
std::string t = timestamp->to_memory() + signal_level + yC::hex2mem(msg_hex);
// std::cout << "msg_hex.size():" << msg_hex.size() << std::endl;
// std::cout << "hex2memory(msg_hex):" << hex2memory(msg_hex).size() << std::endl;
// std::cout << t.size() << std::endl;
std::string result;
// 遍历原始字符串
for (size_t i = 0; i < t.size(); ++i) {
result.push_back(t[i]); // 插入当前字符
if (t[i] == '\x1a') {
result.push_back('\x1a'); // 如果是 0x1a,插入另一个 0x1a
}
}
return char(0x1a) + type + result;
return char(0x1a) + type + result;
}
// 把要传递的信息转化成转义字符 二进制==>转义二进制
std::string packet_to_escape_format(std::string t);
inline std::string unescape_packet(std::string t) {
std::string result;
for (size_t i = 0; i < t.size(); ++i) {
if (t[i] == '\x1a' && i + 1 < t.size() && t[i + 1] == '\x1a') {
result.push_back('\x1a'); // 如果是连续的两个 \x1a,只添加一个
++i; // 跳过下一个 \x1a
} else {
result.push_back(t[i]); // 否则,直接添加当前字符
}
std::string result;
for (size_t i = 0; i < t.size(); ++i) {
if (t[i] == '\x1a' && i + 1 < t.size() && t[i + 1] == '\x1a') {
result.push_back('\x1a'); // 如果是连续的两个 \x1a,只添加一个
++i; // 跳过下一个 \x1a
} else {
result.push_back(t[i]); // 否则,直接添加当前字符
}
return result;
}
return result;
}
// 用于dip_setting
// FPGA switch settings
// Bit 0: Data output mode(port 10002 only) Binary AVR hexdump
// Bit 1: Raw data frame types DF11, DF17 and DF18 only no pre-filtering
// Bit 2: Timestamps within AVR format enabled disabled
// Bit 0: Data output mode(port 10002 only) Binary AVR hexdump Bit
// 1: Raw data frame types DF11, DF17 and DF18
// only no pre-filtering Bit 2: Timestamps within AVR
// format enabled disabled
// Bit 3: not used
// Bit 4: Timestamp mode GPS legacy 12MHz
// Bit 5: FPGA/USB handshake disabled enabled
// Bit 6: 1 bit forward error correction (FEC) disabled enabled
// Bit 7: Mode-A/C decoding enabled disabled
// Bit 4: Timestamp mode GPS legacy 12MHz Bit
// 5: FPGA/USB handshake disabled enabled
// Bit 6: 1 bit forward error correction (FEC) disabled enabled Bit
// 7: Mode-A/C decoding enabled disabled
// GPS status information
// Bit 0: Antenna status good fail
// Bit 1: Tracking at least 1 satellite true false
// Bit 2: Tracking at least 3 satellites true false
// Bit 3: Time value base UTC time GPS time (8sec offset)
// Bit 4: unused
// Bit 5: unused
// Bit 6: unused
// Bit 7: Daysec value range 0 ... 86399 1 ... 86400
inline std::string create_Binary_Format_4(MLAT_timestamp timestamp, char signal_level, char dip_setting, char time_stamp_error_ticks) {
return char(0x1a) + "4" + timestamp.to_bin_string() + char(0xaa) + dip_setting + time_stamp_error_ticks;
// Bit 3: Time value base UTC time GPS time
// (8sec offset) Bit 4: unused Bit 5: unused Bit 6: unused Bit 7: Daysec
// value range 0 ... 86399 1 ... 86400
inline std::string create_Binary_Format_4(MLAT_timestamp timestamp,
char signal_level, char dip_setting,
char time_stamp_error_ticks) {
return char(0x1a) + "4" + timestamp.to_bin_string() + char(0xaa) +
dip_setting + time_stamp_error_ticks;
}
//相对时间戳(无 GPS):在没有连接 GPS 接收器的情况下,时间戳是一个 48 位无符号数字,
//计数 12 MHz 周期。时间戳大约每 271 天换行一次。
// 相对时间戳(无 GPS):在没有连接 GPS 接收器的情况下,时间戳是一个 48
// 位无符号数字, 计数 12 MHz 周期。时间戳大约每 271 天换行一次。
struct TCXO_Clock {
unsigned long long times;
unsigned long long times;
explicit TCXO_Clock(const std::string& hex) {
times = std::bitset<48>(hex2bin(hex)).to_ullong();
}
explicit TCXO_Clock(const std::string &hex) {
times = std::bitset<48>(hex2bin(hex)).to_ullong();
}
[[nodiscard]] std::string to_string() const {
// 每个周期的时间是 1 / 12,000,000 秒
double seconds = static_cast<double>(times) / 12000000.0;
// 计算小时、分钟、秒
int hours = static_cast<int>(seconds / 3600);
seconds -= hours * 3600;
int minutes = static_cast<int>(seconds / 60);
seconds -= minutes * 60;
int secs = static_cast<int>(seconds);
// 格式化为时分秒字符串
std::ostringstream oss;
oss.fill('0');
oss << hours << ":";
oss.width(2);
oss << minutes << ":";
oss.width(2);
oss << secs;
return oss.str();
}
[[nodiscard]] std::string to_string() const {
// 每个周期的时间是 1 / 12,000,000 秒
double seconds = static_cast<double>(times) / 12000000.0;
// 计算小时、分钟、秒
int hours = static_cast<int>(seconds / 3600);
seconds -= hours * 3600;
int minutes = static_cast<int>(seconds / 60);
seconds -= minutes * 60;
int secs = static_cast<int>(seconds);
// 格式化为时分秒字符串
std::ostringstream oss;
oss.fill('0');
oss << hours << ":";
oss.width(2);
oss << minutes << ":";
oss.width(2);
oss << secs;
return oss.str();
}
};
/*
@@ -152,9 +162,10 @@ Fields:
x1xx xxxx xxxx xxxx - GPS valid (GGA, RMC present)
xx1x xxxx xxxx xxxx - GPS currently has a valid fix
xxx1 xxxx xxxx xxxx - High accuracy absolute time is available via PPS
xxxx xxxx 1xxx xxxx - TX-Queue overflow since start-up (normal if HW-handshaking is used)
xxxx xxxx x1xx xxxx - TX-Queue overflow during last second (probably due to HW-handshaking)
xxxx xxxx xx1x xxxx - Excessive NMEA found (other than GGA/RMC)
xxxx xxxx 1xxx xxxx - TX-Queue overflow since start-up (normal if
HW-handshaking is used) xxxx xxxx x1xx xxxx - TX-Queue overflow during last
second (probably due to HW-handshaking) xxxx xxxx xx1x xxxx - Excessive NMEA
found (other than GGA/RMC)
*/
//
// All HULC messages (Type 0x48) have the following structure:
@@ -163,368 +174,371 @@ Fields:
// ID: HULC Message ID
// LEN: Number of bytes following
struct HULC_Message {
std::uint8_t head;
std::uint8_t id;
std::uint8_t len; // 指示下面的长度
std::uint8_t head;
std::uint8_t id;
std::uint8_t len; // 指示下面的长度
};
struct HULC_Status_Message : HULC_Message {
std::uint32_t SerNum{};
std::uint16_t Flags{}; // MSB大端字节序
std::uint16_t I_U_{}; // Internal Use
std::uint32_t xTime{}; // Unix-Timestamp (Seconds since midnight 1970-01-01, UTC)
std::int32_t Lat{};
std::int32_t Lon{};
std::int16_t Alt{};
std::uint8_t Sat{}; // Sat字段记录了定位过程中使用的卫星数量
std::uint8_t HDOP{};
std::uint32_t SerNum{};
std::uint16_t Flags{}; // MSB大端字节序
std::uint16_t I_U_{}; // Internal Use
std::uint32_t
xTime{}; // Unix-Timestamp (Seconds since midnight 1970-01-01, UTC)
std::int32_t Lat{};
std::int32_t Lon{};
std::int16_t Alt{};
std::uint8_t Sat{}; // Sat字段记录了定位过程中使用的卫星数量
std::uint8_t HDOP{};
[[nodiscard]] double get_HDOP() const {
// HDOPHorizontal Dilution of Precision 描述的是 水平精度的衰减,即 GPS 系统的水平定位精度与卫星的几何布局有关。HDOP 数值越低,说明卫星的几何布局越好,定位精度越高。
// 较低的 HDOP 值(例如 1-2)表示卫星信号较强,且卫星的分布较为理想,因此定位精度较高。
// 较高的 HDOP 值(例如 5 或更高)表示卫星信号较弱,或卫星的分布较差,可能导致较差的定位精度。
return double(HDOP) / 10.0;
}
[[nodiscard]] double get_HDOP() const {
// HDOPHorizontal Dilution of Precision 描述的是 水平精度的衰减,即 GPS
// 系统的水平定位精度与卫星的几何布局有关。HDOP
// 数值越低,说明卫星的几何布局越好,定位精度越高。 较低的 HDOP 值(例如
// 1-2)表示卫星信号较强,且卫星的分布较为理想,因此定位精度较高。 较高的
// HDOP 值(例如 5
// 或更高)表示卫星信号较弱,或卫星的分布较差,可能导致较差的定位精度。
return double(HDOP) / 10.0;
}
void set_latitude(double latitude) {
// 根据经纬度设置 Lat 值
Lat = static_cast<int32_t>((latitude / 360.0) * pow(2, 32));
}
void set_latitude(double latitude) {
// 根据经纬度设置 Lat 值
Lat = static_cast<int32_t>((latitude / 360.0) * pow(2, 32));
}
void set_longitude(double longitude) {
// 根据经纬度设置 Lon 值
Lon = static_cast<int32_t>((longitude / 360.0) * pow(2, 32));
}
void set_longitude(double longitude) {
// 根据经纬度设置 Lon 值
Lon = static_cast<int32_t>((longitude / 360.0) * pow(2, 32));
}
[[nodiscard]] double get_latitude() const {
return (static_cast<double>(Lat) / pow(2, 32)) * 360.0;
}
[[nodiscard]] double get_latitude() const {
return (static_cast<double>(Lat) / pow(2, 32)) * 360.0;
}
[[nodiscard]] double get_longitude() const {
return (static_cast<double>(Lon) / pow(2, 32)) * 360.0;
}
[[nodiscard]] double get_longitude() const {
return (static_cast<double>(Lon) / pow(2, 32)) * 360.0;
}
[[nodiscard]] std::string get_latitude_d_m_s() const{
return decimalToDMS(get_latitude());
}
[[nodiscard]] std::string get_latitude_d_m_s() const {
return decimalToDMS(get_latitude());
}
[[nodiscard]] std::string get_longitude_d_m_s() const{
return decimalToDMS(get_longitude());
}
[[nodiscard]] std::string get_longitude_d_m_s() const {
return decimalToDMS(get_longitude());
}
[[nodiscard]] std::string get_timestamp_string() const{
return convert_timestamp_to_string(xTime);
}
[[nodiscard]] std::string get_timestamp_string() const {
return convert_timestamp_to_string(xTime);
}
static std::string convert_timestamp_to_string(std::uint32_t time32) {
std::time_t time = time32;
std::stringstream ss;
ss << std::put_time(std::gmtime(&time), "%Y-%m-%d %H:%M:%S"); // 使用 std::put_time 格式化日期
return ss.str(
static std::string convert_timestamp_to_string(std::uint32_t time32) {
std::time_t time = time32;
std::stringstream ss;
ss << std::put_time(std::gmtime(&time),
"%Y-%m-%d %H:%M:%S"); // 使用 std::put_time 格式化日期
return ss.str(
);
// 返回格式化后的字符串
// std::time_t time = time32;
// std::stringstream ss;
// // 将时间戳转换为本地时间
// ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S"); // 使用 std::localtime 格式化日期
// return ss.str(); // 返回格式化后的字符串
// // Unix Timestamp
// std::time_t timestamp = xTime;
//
// std::tm* ptm = std::gmtime(&timestamp);
//
// return std::asctime(ptm);
}
);
// 返回格式化后的字符串
// std::time_t time = time32;
// std::stringstream ss;
// // 将时间戳转换为本地时间
// ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S"); // 使用
// std::localtime 格式化日期 return ss.str(); // 返回格式化后的字符串
// // Unix Timestamp
// std::time_t timestamp = xTime;
//
// std::tm* ptm = std::gmtime(&timestamp);
//
// return std::asctime(ptm);
}
// 转化经纬度变成 度 分 秒
static std::string decimalToDMS(double decimalDegree) {
int degrees = static_cast<int>(decimalDegree);
double minutesDouble = (decimalDegree - degrees) * 60;
int minutes = static_cast<int>(minutesDouble);
int seconds = static_cast<int>((minutesDouble - minutes) * 60.0);
return "(" + std::to_string(degrees) + "°" + std::to_string(minutes) + "'" +
std::to_string(seconds) + "\")";
}
/*
Status Flags:
1xxx xxxx xxxx xxxx - GPS device detected -> Using absolute timestamp
x1xx xxxx xxxx xxxx - GPS valid (GGA, RMC present)
xx1x xxxx xxxx xxxx - GPS currently has a valid fix
xxx1 xxxx xxxx xxxx - High accuracy absolute time is available via PPS
xxxx xxxx 1xxx xxxx - TX-Queue overflow since start-up (normal if
HW-handshaking is used) xxxx xxxx x1xx xxxx - TX-Queue overflow during last
second (probably due to HW-handshaking) xxxx xxxx xx1x xxxx - Excessive NMEA
found (other than GGA/RMC)
*/
[[nodiscard]] bool GPS_device_detected() const {
return Flags & (1 << 15); // 检查第 15 位,GPS 设备是否检测到
}
// 转化经纬度变成 度 分 秒
static std::string decimalToDMS(double decimalDegree) {
int degrees = static_cast<int>(decimalDegree);
double minutesDouble = (decimalDegree - degrees) * 60;
int minutes = static_cast<int>(minutesDouble);
int seconds = static_cast<int>((minutesDouble - minutes) * 60.0);
return "(" + std::to_string(degrees) + "°" + std::to_string(minutes) + "'" + std::to_string(seconds) + "\")";
}
/*
Status Flags:
1xxx xxxx xxxx xxxx - GPS device detected -> Using absolute timestamp
x1xx xxxx xxxx xxxx - GPS valid (GGA, RMC present)
xx1x xxxx xxxx xxxx - GPS currently has a valid fix
xxx1 xxxx xxxx xxxx - High accuracy absolute time is available via PPS
xxxx xxxx 1xxx xxxx - TX-Queue overflow since start-up (normal if HW-handshaking is used)
xxxx xxxx x1xx xxxx - TX-Queue overflow during last second (probably due to HW-handshaking)
xxxx xxxx xx1x xxxx - Excessive NMEA found (other than GGA/RMC)
*/
[[nodiscard]] bool GPS_device_detected() const {
return Flags & (1 << 15); // 检查第 15 位,GPS 设备是否检测到
}
[[nodiscard]] bool GPS_valid() const {
return Flags & (1 << 14); // 检查第 14 位,GPS 数据是否有效
}
[[nodiscard]] bool GPS_valid() const {
return Flags & (1 << 14); // 检查第 14 位,GPS 数据是否有效
}
[[nodiscard]] bool GPS_has_valid_fix() const {
return Flags & (1 << 13); // 检查第 13 位,GPS 是否有定位
}
[[nodiscard]] bool GPS_has_valid_fix() const {
return Flags & (1 << 13); // 检查第 13 位,GPS 是否有有效定位
}
[[nodiscard]] bool GPS_high_accuracy_time() const {
return Flags & (1 << 12); // 检查第 12 位,是否通过 PPS 提供高精度绝对时间
}
[[nodiscard]] bool GPS_high_accuracy_time() const {
return Flags & (1 << 12); // 检查第 12 位,是否通过 PPS 提供高精度绝对时间
}
[[nodiscard]] bool TX_queue_overflow_since_startup() const {
return Flags & (1 << 7); // 检查第 7 位,自启动以来是否发生 TX 队列溢出
}
[[nodiscard]] bool TX_queue_overflow_since_startup() const {
return Flags & (1 << 7); // 检查第 7 位,自启动以来是否发生 TX 队列溢出
}
[[nodiscard]] bool TX_queue_overflow_last_second() const {
return Flags & (1 << 6); // 检查第 6 位,过去一秒内是否发生 TX 队列溢出
}
[[nodiscard]] bool TX_queue_overflow_last_second() const {
return Flags & (1 << 6); // 检查第 6 位,过去一秒内是否发生 TX 队列溢出
}
[[nodiscard]] bool excessive_NMEA_found() const {
return Flags &
(1 << 5); // 检查第 5 位,是否发现过多的 NMEA 数据(非 GGA/RMC
}
[[nodiscard]] bool excessive_NMEA_found() const {
return Flags & (1 << 5); // 检查第 5 位,是否发现过多的 NMEA 数据(非 GGA/RMC
}
[[nodiscard]] Json toJson() const {
Json ret = Json::object();
ret.append({"序列号", SerNum});
ret.append({"状态标志", Flags});
ret.append({"内部使用", I_U_});
ret.append({"时间戳", get_timestamp_string()});
ret.append(
{"纬度", std::to_string(get_latitude()) + " " + get_latitude_d_m_s()});
ret.append({"经度",
std::to_string(get_longitude()) + " " + get_longitude_d_m_s()});
ret.append({"高度", Alt});
ret.append({"卫星数量", Sat});
ret.append({"HDOP", get_HDOP()});
ret.append({"GPS设备检测到", GPS_device_detected()});
ret.append({"GPS有效", GPS_valid()});
ret.append({"GPS有效定位", GPS_has_valid_fix()});
ret.append({"GPS高精度时间", GPS_high_accuracy_time()});
ret.append({"启动以来TX队列溢出", TX_queue_overflow_since_startup()});
ret.append({"过去一秒TX队列溢出", TX_queue_overflow_last_second()});
ret.append({"发现过多NMEA数据", excessive_NMEA_found()});
return ret;
}
[[nodiscard]] Json toJson() const {
Json ret = Json::object();
ret.append({"序列号", SerNum});
ret.append({"状态标志", Flags});
ret.append({"内部使用", I_U_});
ret.append({"时间戳", get_timestamp_string()});
ret.append({"纬度", std::to_string(get_latitude()) + " " + get_latitude_d_m_s()});
ret.append({"经度", std::to_string(get_longitude()) + " " + get_longitude_d_m_s()});
ret.append({"高度", Alt});
ret.append({"卫星数量", Sat});
ret.append({"HDOP", get_HDOP()});
ret.append({"GPS设备检测到", GPS_device_detected()});
ret.append({"GPS有效", GPS_valid()});
ret.append({"GPS有效定位", GPS_has_valid_fix()});
ret.append({"GPS高精度时间", GPS_high_accuracy_time()});
ret.append({"启动以来TX队列溢出", TX_queue_overflow_since_startup()});
ret.append({"过去一秒TX队列溢出", TX_queue_overflow_last_second()});
ret.append({"发现过多NMEA数据", excessive_NMEA_found()});
return ret;
}
static double decodeLatitudeFromBAM(const std::string& bigdian4) {
std::uint32_t value;
yC::big_endian_2_platform(bigdian4, (char*)&value);
// BAM 格式解码公式
// return (static_cast<double>(value) / pow(2, 32)) * 360.0;
return (static_cast<double>(value) / pow(2, 32)) * 360.0;
}
std::string toBinary() {
std::string binary = {0x1a, 0x48, 0x01, 0x18};
binary.append(yC::platform_2_big_endian(&SerNum, 4));
binary.append(yC::platform_2_big_endian(&Flags, 2));
binary.append(std::string((char*)&I_U_, 2)); // 内部使用没说什么序 默认大端序
binary.append(yC::platform_2_big_endian(&xTime, 4));
binary.append(yC::platform_2_big_endian(&Lat, 4));
binary.append(yC::platform_2_big_endian(&Lon, 4));
binary.append(yC::platform_2_big_endian(&Alt, 2));
// 没说什么序 一字节 大端小端 等同
binary.append({(char)Sat});
binary.append({(char)HDOP});
return binary;
}
static double decodeLatitudeFromBAM(const std::string &bigdian4) {
std::uint32_t value;
yC::big_endian_2_platform(bigdian4, (char *)&value);
// BAM 格式解码公式
// return (static_cast<double>(value) / pow(2, 32)) * 360.0;
return (static_cast<double>(value) / pow(2, 32)) * 360.0;
}
std::string toBinary() {
std::string binary = {0x1a, 0x48, 0x01, 0x18};
binary.append(yC::platform_2_big_endian(&SerNum, 4));
binary.append(yC::platform_2_big_endian(&Flags, 2));
binary.append(
std::string((char *)&I_U_, 2)); // 内部使用没说什么序 默认大端序
binary.append(yC::platform_2_big_endian(&xTime, 4));
binary.append(yC::platform_2_big_endian(&Lat, 4));
binary.append(yC::platform_2_big_endian(&Lon, 4));
binary.append(yC::platform_2_big_endian(&Alt, 2));
// 没说什么序 一字节 大端小端 等同
binary.append({(char)Sat});
binary.append({(char)HDOP});
return binary;
}
};
static void hulc_big_endian_set(const std::string& msg, void* field, int start, int len) {
auto str = msg.substr(start, len);
yC::big_endian_2_platform(str, (char*)field);
static void hulc_big_endian_set(const std::string &msg, void *field, int start,
int len) {
auto str = msg.substr(start, len);
yC::big_endian_2_platform(str, (char *)field);
}
static void hulc_set2(const std::string& msg, void* field, int start, int len) {
auto it = msg.substr(start, len);
std::memcpy(field, it.data(), len);
static void hulc_set2(const std::string &msg, void *field, int start, int len) {
auto it = msg.substr(start, len);
std::memcpy(field, it.data(), len);
}
// msg 是文本二进制字符串 转义后的 1a34
static HULC_Status_Message create_HULC_Status_Message(const std::string& msg) {
HULC_Status_Message ret{};
hulc_big_endian_set(msg, &ret.SerNum, 4, 4);
hulc_big_endian_set(msg, &ret.Flags, 8, 2);
hulc_set2(msg, &ret.I_U_, 10, 2);
hulc_big_endian_set(msg, &ret.xTime, 12, 4);
hulc_big_endian_set(msg, &ret.Lat, 16, 4);
hulc_big_endian_set(msg, &ret.Lon, 20, 4);
hulc_big_endian_set(msg, &ret.Alt, 24, 2);
hulc_set2(msg, &ret.Sat, 26, 1);
hulc_set2(msg, &ret.HDOP, 27, 1);
return ret;
static HULC_Status_Message create_HULC_Status_Message(const std::string &msg) {
HULC_Status_Message ret{};
hulc_big_endian_set(msg, &ret.SerNum, 4, 4);
hulc_big_endian_set(msg, &ret.Flags, 8, 2);
hulc_set2(msg, &ret.I_U_, 10, 2);
hulc_big_endian_set(msg, &ret.xTime, 12, 4);
hulc_big_endian_set(msg, &ret.Lat, 16, 4);
hulc_big_endian_set(msg, &ret.Lon, 20, 4);
hulc_big_endian_set(msg, &ret.Alt, 24, 2);
hulc_set2(msg, &ret.Sat, 26, 1);
hulc_set2(msg, &ret.HDOP, 27, 1);
return ret;
}
struct HULC_Reply_to_command : HULC_Message {
std::uint8_t CMD;
std::uint8_t POO_14;
std::uint8_t CMD;
std::uint8_t POO_14;
};
// 0x1A 0x48 0x01 0x18 SerNum Flags I.U. xTime Lat Lon Alt Sat HDOP
inline std::uint8_t get_id(const std::string& msg) {
return msg[2];
}
inline std::uint8_t get_id(const std::string &msg) { return msg[2]; }
inline std::uint8_t get_len(const std::string& msg) {
return msg[3];
}
inline std::uint8_t get_len(const std::string &msg) { return msg[3]; }
// Type Payload Size Description
// 0x31 4 bytes Mode-A/C raw data
// 0x32 7 bytes Mode-S Short Squitter raw data
// 0x33 14 bytes Mode-S Extended Squitter raw data
// 0x48 variable HULC Message, see below for details
// HULC Protocol uses the byte 0x1A as start-of-packet (SOP) marker. In order to avoid misinterpretation
// of normal data bytes with value 0x1A as SOP, each occurrence of data byte 0x1A is doubled in the
// data stream during transmission ('escaping'). It is thus necessary during reception to detect every
// 0x1A not followed by another 0x1A as an SOP marker and to reduce every occurrence of a double
// 0x1A to a single 0x1A data byte ('un-escaping').
// HULC Protocol uses the byte 0x1A as start-of-packet (SOP) marker. In order to
// avoid misinterpretation of normal data bytes with value 0x1A as SOP, each
// occurrence of data byte 0x1A is doubled in the data stream during
// transmission ('escaping'). It is thus necessary during reception to detect
// every 0x1A not followed by another 0x1A as an SOP marker and to reduce every
// occurrence of a double 0x1A to a single 0x1A data byte ('un-escaping').
// Example of a 4-byte long packet including SOP marker and 0x1A data bytes:
// Before Escaping: 1A 32 27 1A E8 57 F0 1A 6C
// During Transmission: 1A 32 27 1A 1A E8 57 F0 1A 1A 6C
// After Un-Escaping: 1A 32 27 1A E8 57 F0 1A 6C
void Binary_Format_handle_buffer(std::string& buffer, const std::string& data, const std::function<void(std::string&)>& callback);
void Binary_Format_handle_buffer(
std::string &buffer, const std::string &data,
const std::function<void(std::string &)> &callback);
/* Command Message (Host ==> Device)
The command-message has a simple ASCII based structure. Each message starts with a # (0x23) and
ends with <CR><LF> (0x0D, 0x0A). In-between are one to 16 bytes in 2-digit hexadecimal representation
using upper-case letters, separated by - (0x2D).
For example:
#00<CR><LF> or hexadecimal 0x23 0x30 0x30 0x0D 0x0A
#43-02<CR><LF> or hexadecimal 0x23 0x34 0x33 0x2D 0x30 0x32 0x0D 0x0A
The first byte is mandatory and holds the command while the remaining bytes are parameters.
Available commands depend on the selected protocol and are discussed in the respective protocol
section.
The command-message has a simple ASCII based structure. Each message starts with
a # (0x23) and ends with <CR><LF> (0x0D, 0x0A). In-between are one to 16
bytes in 2-digit hexadecimal representation using upper-case letters, separated
by - (0x2D). For example: #00<CR><LF> or hexadecimal 0x23 0x30 0x30 0x0D
0x0A #43-02<CR><LF> or hexadecimal 0x23 0x34 0x33 0x2D 0x30 0x32 0x0D 0x0A The
first byte is mandatory and holds the command while the remaining bytes are
parameters. Available commands depend on the selected protocol and are discussed
in the respective protocol section.
*/
std::string mode_s_msg_packet_to_server_packet(std::uint32_t id, std::string packet);
std::string mode_s_msg_packet_to_server_packet(std::uint32_t id,
std::string packet);
// 1a34 radarcape 状态帧消息
// https://wiki.jetvision.de/wiki/Radarcape:Version_History#Status_Frame_0x34_contents_were_extended_with_GPS_and_UTC_information
// 状态帧0x34内容已扩展为 GPS 和 UTC 信息
// 当选择 GPS 时间戳时,状态帧由 1PPS 脉冲触发,在传统 12MHz 时间戳的情况下随机触发。
// 状态帧包含有效的时间戳
// 信号电平值为零/保留
// 当选择 GPS 时间戳时,状态帧由 1PPS 脉冲触发,在传统 12MHz
// 时间戳的情况下随机触发。 状态帧包含有效的时间戳 信号电平值为零/保留
#define SETGET(name, pos) \
void set_##name(bool value) { set(pos, value); } \
bool get_##name() { return get(pos); }
#define SETGET(name, pos) void set_##name(bool value) { set(pos, value); } \
bool get_##name() { return get(pos); }
#define SETGET2(Type, name, pos) void set_##name(Type value) { set(pos, (uint8_t)value); } \
Type get_##name() { return (Type)get(pos); }
#define SETGET2(Type, name, pos) \
void set_##name(Type value) { set(pos, (uint8_t)value); } \
Type get_##name() { return (Type)get(pos); }
struct BYTE_Settings {
protected:
uint8_t settings{}; // 8 位的字段,存储所有设置
void set(uint8_t pos, bool value) {
if (value) {
// 设置指定位置的位为 1
settings |= (1 << pos);
} else {
// 设置指定位置的位为 0
settings &= ~(1 << pos);
}
}
[[nodiscard]] bool get(uint8_t pos) const {
// 获取指定位置的位值
return (settings >> pos) & 0x01;
uint8_t settings{}; // 8 位的字段,存储所有设置
void set(uint8_t pos, bool value) {
if (value) {
// 设置指定位置的位为 1
settings |= (1 << pos);
} else {
// 设置指定位置的位为 0
settings &= ~(1 << pos);
}
}
[[nodiscard]] bool get(uint8_t pos) const {
// 获取指定位置的位值
return (settings >> pos) & 0x01;
}
};
struct FPGA_Setting : BYTE_Settings {
enum class Data_Output_Mode { AVR_hexdump, Binary };
enum class Raw_Data_Frame_Type { No_Pre_Filtering, DF11_17_18_only };
enum class Timestamp_Mode { Legacy_12MHz, GPS };
SETGET2(Data_Output_Mode, data_output_mode, 0)
SETGET2(Raw_Data_Frame_Type, raw_data_frame_type, 1)
SETGET(timestamps_within_AVR_format, 2)
SETGET2(Timestamp_Mode, timestamp_mode, 4)
SETGET(serial_flow_control, 5)
SETGET(FEC, 6) // 1位转发错误校正
SETGET(mode_ac_decoding , 7)
Json toJson() {
Json ret = Json::object();
ret.append({"Data_Output_Mode", to_string(get_data_output_mode())});
ret.append({"Raw_Data_Frame_Type", to_string(get_raw_data_frame_type())});
ret.append({"timestamps_within_AVR_format", get_timestamps_within_AVR_format()});
ret.append({"timestamps_mode", to_string(get_timestamp_mode())});
ret.append({"serial_flow_control", get_serial_flow_control()});
ret.append({"1位转发错误校正", get_FEC()});
ret.append({"mode_ac_decoding", get_mode_ac_decoding()});
return ret;
}
enum class Data_Output_Mode { AVR_hexdump, Binary };
enum class Raw_Data_Frame_Type { No_Pre_Filtering, DF11_17_18_only };
enum class Timestamp_Mode { Legacy_12MHz, GPS };
SETGET2(Data_Output_Mode, data_output_mode, 0)
SETGET2(Raw_Data_Frame_Type, raw_data_frame_type, 1)
SETGET(timestamps_within_AVR_format, 2)
SETGET2(Timestamp_Mode, timestamp_mode, 4)
SETGET(serial_flow_control, 5)
SETGET(FEC, 6) // 1位转发错误校正
SETGET(mode_ac_decoding, 7)
Json toJson() {
Json ret = Json::object();
ret.append({"Data_Output_Mode", to_string(get_data_output_mode())});
ret.append({"Raw_Data_Frame_Type", to_string(get_raw_data_frame_type())});
ret.append(
{"timestamps_within_AVR_format", get_timestamps_within_AVR_format()});
ret.append({"timestamps_mode", to_string(get_timestamp_mode())});
ret.append({"serial_flow_control", get_serial_flow_control()});
ret.append({"1位转发错误校正", get_FEC()});
ret.append({"mode_ac_decoding", get_mode_ac_decoding()});
return ret;
}
};
struct GPS_Setting : BYTE_Settings {
enum class Time_Value_Base { UTC, GPS };
enum class Daysec_Range { R_0_86399, R_1_86400 };
SETGET(antenna_status, 0) // 位 0: 天线状态
SETGET(tracking_at_least_1_satellite, 1) // 位 1: 至少跟踪 1 颗卫星
SETGET(tracking_at_least_3_satellites, 2) // 位 2: 至少跟踪 3 颗卫星
SETGET2(Time_Value_Base, time_value_base, 3) // 位 3: 时间值基数 (UTC/GPS)
SETGET(unused4, 4) // 位 4: 保留
SETGET(unused5, 5) // 位 5: 保留
SETGET(unused6, 6) // 位 6: 保留
SETGET2(Daysec_Range, daysec_range, 7) // 位 7: Daysec 值范围
Json toJson() {
Json ret = Json::object(); // 创建 JSON 对象
ret.append({"antenna_status", get_antenna_status()});
ret.append({"至少跟踪 1 颗卫星", get_tracking_at_least_1_satellite()});
ret.append({"至少跟踪 3 颗卫星", get_tracking_at_least_3_satellites()});
ret.append({"timestamps_mode", to_string(get_time_value_base())});
ret.append({"daysec_range", to_string(get_daysec_range())});
return ret;
}
enum class Time_Value_Base { UTC, GPS };
enum class Daysec_Range { R_0_86399, R_1_86400 };
SETGET(antenna_status, 0) // 位 0: 天线状态
SETGET(tracking_at_least_1_satellite, 1) // 位 1: 至少跟踪 1 颗卫星
SETGET(tracking_at_least_3_satellites, 2) // 位 2: 至少跟踪 3 颗卫星
SETGET2(Time_Value_Base, time_value_base, 3) // 位 3: 时间值基数 (UTC/GPS)
SETGET(unused4, 4) // 位 4: 保留
SETGET(unused5, 5) // 位 5: 保留
SETGET(unused6, 6) // 位 6: 保留
SETGET2(Daysec_Range, daysec_range, 7) // 位 7: Daysec 值范围
Json toJson() {
Json ret = Json::object(); // 创建 JSON 对象
ret.append({"antenna_status", get_antenna_status()});
ret.append({"至少跟踪 1 颗卫星", get_tracking_at_least_1_satellite()});
ret.append({"至少跟踪 3 颗卫星", get_tracking_at_least_3_satellites()});
ret.append({"timestamps_mode", to_string(get_time_value_base())});
ret.append({"daysec_range", to_string(get_daysec_range())});
return ret;
}
};
struct Radarcape_STATUS_Message {
FPGA_Setting fpga_settings;
std::uint8_t pps_nanosecond_offset{}; // 包含 1PPS 事件时纳秒计时器的偏移量,单位为 15.625ns。正常值范围为 -3 ... +3。
GPS_Setting gps_settings;
void set_pps_nanosecond(double value) {
if (value < 0.0 || value > 4000) {
std::cerr << "Invalid value. Must be in range [0.0, 4000.0]." << std::endl;
return;
}
pps_nanosecond_offset = static_cast<std::uint8_t>((value)/15.625);
}
[[nodiscard]] double get_pps_nanosecond() const {
return (double)pps_nanosecond_offset * 15.625;
}
std::string toBinary() {
std::string binary = {0x1a, 0x34};
binary.append(reinterpret_cast<const char*>(&fpga_settings), 1);
binary.append(reinterpret_cast<const char*>(&pps_nanosecond_offset), 1);
binary.append(reinterpret_cast<const char*>(&gps_settings), 1);
return binary;
}
Json toJson() {
Json ret = Json::object();
ret.append({"pps_nanosecond_offset", get_pps_nanosecond()});
ret.append({"fpga_settings", fpga_settings.toJson()});
ret.append({"gps_settings", gps_settings.toJson()});
return ret;
FPGA_Setting fpga_settings;
std::uint8_t
pps_nanosecond_offset{}; // 包含 1PPS
// 事件时纳秒计时器的偏移量,单位为 15.625ns。正常值范围为
// -3 ... +3。
GPS_Setting gps_settings;
void set_pps_nanosecond(double value) {
if (value < 0.0 || value > 4000) {
std::cerr << "Invalid value. Must be in range [0.0, 4000.0]."
<< std::endl;
return;
}
pps_nanosecond_offset = static_cast<std::uint8_t>((value) / 15.625);
}
[[nodiscard]] double get_pps_nanosecond() const {
return (double)pps_nanosecond_offset * 15.625;
}
std::string toBinary() {
std::string binary = {0x1a, 0x34};
binary.append(reinterpret_cast<const char *>(&fpga_settings), 1);
binary.append(reinterpret_cast<const char *>(&pps_nanosecond_offset), 1);
binary.append(reinterpret_cast<const char *>(&gps_settings), 1);
return binary;
}
Json toJson() {
Json ret = Json::object();
ret.append({"pps_nanosecond_offset", get_pps_nanosecond()});
ret.append({"fpga_settings", fpga_settings.toJson()});
ret.append({"gps_settings", gps_settings.toJson()});
return ret;
}
};
// 消息5字节
//
static Radarcape_STATUS_Message create_Radarcape_STATUS_Message(const std::string& msg_5) {
std::string msg = yC::big_endian_2_platform(msg_5.substr(2));
Radarcape_STATUS_Message ret{};
std::memcpy(&ret, (void*)(msg.data()), 3);
return ret;
static Radarcape_STATUS_Message
create_Radarcape_STATUS_Message(const std::string &msg_5) {
std::string msg = yC::big_endian_2_platform(msg_5.substr(2));
Radarcape_STATUS_Message ret{};
std::memcpy(&ret, (void *)(msg.data()), 3);
return ret;
}
#undef SETGET
#undef SETGET2
@@ -1,74 +1,68 @@
#ifndef BASE_FORMAT_H
#define BASE_FORMAT_H
#include <cstring>
#include <iomanip>
#include <iostream>
#include <string>
#include <bitset>
#include <sstream>
#include <algorithm>
#include <utility>
#include <vector>
#include <set>
#include <string>
#include <algorithm>
#include <array>
#include <cmath>
#include <stdexcept>
#include <string>
#include <numeric>
#include <unordered_map>
#include <map>
#include <chrono>
#include <functional>
#include "Bit.h"
#include "Json.h"
#include "magic_enum/export.h"
#include <algorithm>
#include <array>
#include <bitset>
#include <chrono>
#include <cmath>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
// 1纳秒是 10 -9次方秒
struct MLAT_timestamp {
explicit MLAT_timestamp();
explicit MLAT_timestamp(const std::string& memory_6);
MLAT_timestamp(std::uint32_t daysec, std::uint32_t nanosec);
std::uint32_t daysec{}; // 当天的秒数 高18位
std::uint32_t nanosec{}; // 当天的纳秒数 低30位
std::string to_bin_string() const;
std::string to_memory() const;
unsigned long hh{};
unsigned long mm{};
unsigned long ss{};
std::string memory{};
bool operator<(const MLAT_timestamp& other) const {
// 比较 daysec(高18位)
if (daysec != other.daysec) {
return daysec < other.daysec;
}
// 如果 daysec 相等,比较 nanosec(低30位)
return nanosec < other.nanosec;
explicit MLAT_timestamp();
explicit MLAT_timestamp(const std::string &memory_6);
MLAT_timestamp(std::uint32_t daysec, std::uint32_t nanosec);
std::uint32_t daysec{}; // 当天的秒数 高18位
std::uint32_t nanosec{}; // 当天的纳秒数 低30位
std::string to_bin_string() const;
std::string to_memory() const;
unsigned long hh{};
unsigned long mm{};
unsigned long ss{};
std::string memory{};
bool operator<(const MLAT_timestamp &other) const {
// 比较 daysec(高18位)
if (daysec != other.daysec) {
return daysec < other.daysec;
}
// 如果 daysec 相等,比较 nanosec(低30位)
return nanosec < other.nanosec;
}
[[nodiscard]] Json toJson() const {
Json ret = Json::object();
ret.append({"", daysec});
ret.append({"纳秒", nanosec});
ret.append({"时间", std::to_string(hh) + ":" + std::to_string(mm) + ":" +
std::to_string(ss)});
return ret;
}
[[nodiscard]] Json toJson() const {
Json ret = Json::object();
ret.append({"", daysec});
ret.append({"纳秒", nanosec});
ret.append({"时间", std::to_string(hh) + ":" + std::to_string(mm) + ":" + std::to_string(ss)});
return ret;
}
[[nodiscard]] std::string to_string() const {
return "{" + std::to_string(daysec) + "," + std::to_string(nanosec) + "}_" +
"[" + std::to_string(hh) + "时:" + std::to_string(mm) +
"分:" + std::to_string(ss) +
""
"]";
}
[[nodiscard]] std::string to_string() const {
return
"{" + std::to_string(daysec) + "," + std::to_string(nanosec) + "}_" +
"[" +
std::to_string(hh) + "时:" +
std::to_string(mm) + "分:" +
std::to_string(ss) + ""
"]";
}
void parse_hhmmss();
void parse_hhmmss();
};
#endif
@@ -4,111 +4,94 @@
#include <iostream>
#include <sstream>
template <typename EnumType>
EnumType to_enum(const std::string& str) {
auto opt = magic_enum::enum_cast<EnumType>(str);
if (opt.has_value()) {
return opt.value(); // 返回枚举值
}
std::cerr << std::string(magic_enum::enum_type_name<EnumType>()) +" 字符串转换枚举值错误!str:" + str + "\n";
exit(-1);
template <typename EnumType> EnumType to_enum(const std::string &str) {
auto opt = magic_enum::enum_cast<EnumType>(str);
if (opt.has_value()) {
return opt.value(); // 返回枚举值
}
std::cerr << std::string(magic_enum::enum_type_name<EnumType>()) +
" 字符串转换枚举值错误!str:" + str + "\n";
exit(-1);
}
template <typename EnumType>
std::optional<EnumType> to_enum2(const std::string& str) {
auto opt = magic_enum::enum_cast<EnumType>(str);
if (opt.has_value()) {
return opt.value(); // 返回枚举值
}
return std::nullopt;
std::optional<EnumType> to_enum2(const std::string &str) {
auto opt = magic_enum::enum_cast<EnumType>(str);
if (opt.has_value()) {
return opt.value(); // 返回枚举值
}
return std::nullopt;
}
template <typename EnumType>
std::string to_string(EnumType type) {
return std::string(magic_enum::enum_name(type));
template <typename EnumType> std::string to_string(EnumType type) {
return std::string(magic_enum::enum_name(type));
}
template <typename EnumType>
std::optional<EnumType> int_to_enum(int enum_value) {
// 静态断言,确保 EnumType 是枚举类型
static_assert(std::is_enum_v<EnumType>, "EnumType must be an enum type");
// 使用 magic_enum 获取所有的枚举值
auto enum_values = magic_enum::enum_values<EnumType>();
// 检查是否存在匹配的枚举值
for (auto value : enum_values) {
if (static_cast<int>(value) == enum_value) {
return value; // 返回匹配的枚举值
}
// 静态断言,确保 EnumType 是枚举类型
static_assert(std::is_enum_v<EnumType>, "EnumType must be an enum type");
// 使用 magic_enum 获取所有的枚举值
auto enum_values = magic_enum::enum_values<EnumType>();
// 检查是否存在匹配的枚举值
for (auto value : enum_values) {
if (static_cast<int>(value) == enum_value) {
return value; // 返回匹配的枚举值
}
// 如果没有匹配的枚举值,返回 std::nullopt
return std::nullopt;
}
// 如果没有匹配的枚举值,返回 std::nullopt
return std::nullopt;
}
template <typename EnumType>
std::optional<std::string> enum_int_to_string(int enum_value) {
auto tmp = int_to_enum<EnumType>(enum_value);
if (!tmp.has_value()) return std::nullopt;
return to_string(tmp.value());
auto tmp = int_to_enum<EnumType>(enum_value);
if (!tmp.has_value())
return std::nullopt;
return to_string(tmp.value());
}
template <typename Enum>
std::vector<Enum> split_flags(Enum flags)
{
static_assert(std::is_enum_v<Enum>, "Template parameter must be an enum type");
std::vector<Enum> setFlags;
for (auto flag : magic_enum::enum_values<Enum>())
{
if ((flags & flag) == flag)
{
setFlags.push_back(flag);
}
template <typename Enum> std::vector<Enum> split_flags(Enum flags) {
static_assert(std::is_enum_v<Enum>,
"Template parameter must be an enum type");
std::vector<Enum> setFlags;
for (auto flag : magic_enum::enum_values<Enum>()) {
if ((flags & flag) == flag) {
setFlags.push_back(flag);
}
return setFlags;
}
return setFlags;
}
inline std::string to_string(const char *val) { return std::string(val); }
inline std::string to_string(const char* val) {
return std::string(val);
template <> inline std::string to_string(std::string val) { return val; }
template <> inline std::string to_string(bool val) {
return val ? "true" : "false";
}
template <> inline std::string to_string(void *val) {
std::ostringstream oss;
oss << "0x" << std::hex << std::showbase
<< reinterpret_cast<std::uintptr_t>(val);
return oss.str();
}
template <>
inline std::string to_string(std::string val) {
return val;
}
template <>
inline std::string to_string(bool val) {
return val ? "true" : "false";
}
template <>
inline std::string to_string(void* val) {
std::ostringstream oss;
oss << "0x" << std::hex << std::showbase << reinterpret_cast<std::uintptr_t>(val);
return oss.str();
}
#define IMPL_to_string_from_std(Type) \
template <> inline std::string to_string(Type val) { \
return std::to_string(val); \
}
#define IMPL_to_string_from_std(Type) template <> \
inline std::string to_string(Type val) { \
return std::to_string(val); \
} \
IMPL_to_string_from_std(signed char)
IMPL_to_string_from_std(short)
IMPL_to_string_from_std(int)
IMPL_to_string_from_std(long)
IMPL_to_string_from_std(long long)
IMPL_to_string_from_std(unsigned char)
IMPL_to_string_from_std(unsigned short)
IMPL_to_string_from_std(unsigned int)
IMPL_to_string_from_std(unsigned long)
IMPL_to_string_from_std(unsigned long long)
IMPL_to_string_from_std(float)
IMPL_to_string_from_std(double)
IMPL_to_string_from_std(long double)
IMPL_to_string_from_std(signed char) IMPL_to_string_from_std(short)
IMPL_to_string_from_std(int) IMPL_to_string_from_std(long)
IMPL_to_string_from_std(long long)
IMPL_to_string_from_std(unsigned char)
IMPL_to_string_from_std(unsigned short)
IMPL_to_string_from_std(unsigned int)
IMPL_to_string_from_std(unsigned long)
IMPL_to_string_from_std(unsigned long long)
IMPL_to_string_from_std(float)
IMPL_to_string_from_std(double)
IMPL_to_string_from_std(long double)
#undef IMPL_to_string_from_std
#endif
File diff suppressed because it is too large Load Diff
@@ -11,28 +11,27 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef NEARGYE_MAGIC_ENUM_ALL_HPP
#define NEARGYE_MAGIC_ENUM_ALL_HPP
#include "magic_enum.hpp"
#include "../magic_enum_containers.hpp"
#include "../magic_enum_flags.hpp"
#include "../magic_enum_format.hpp"
@@ -40,5 +39,6 @@
#include "../magic_enum_iostream.hpp"
#include "../magic_enum_switch.hpp"
#include "../magic_enum_utility.hpp"
#include "magic_enum.hpp"
#endif // NEARGYE_MAGIC_ENUM_ALL_HPP
File diff suppressed because it is too large Load Diff
@@ -11,23 +11,23 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef NEARGYE_MAGIC_ENUM_FLAGS_HPP
#define NEARGYE_MAGIC_ENUM_FLAGS_HPP
@@ -35,12 +35,13 @@
#include "magic_enum.hpp"
#if defined(__clang__)
# pragma clang diagnostic push
#pragma clang diagnostic push
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored \
"-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
#elif defined(_MSC_VER)
# pragma warning(push)
#pragma warning(push)
#endif
namespace magic_enum {
@@ -49,7 +50,8 @@ namespace detail {
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
constexpr U values_ors() noexcept {
static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype.");
static_assert(S == enum_subtype::flags,
"magic_enum::detail::values_ors requires valid subtype.");
auto ors = U{0};
for (std::size_t i = 0; i < count_v<E, S>; ++i) {
@@ -59,21 +61,27 @@ constexpr U values_ors() noexcept {
return ors;
}
} // namespace magic_enum::detail
} // namespace detail
// Returns name from enum-flags value.
// If enum-flags value does not have name or value out of range, returns empty string.
// If enum-flags value does not have name or value out of range, returns empty
// string.
template <typename E>
[[nodiscard]] auto enum_flags_name(E value, char_type sep = static_cast<char_type>('|')) -> detail::enable_if_t<E, string> {
[[nodiscard]] auto enum_flags_name(E value,
char_type sep = static_cast<char_type>('|'))
-> detail::enable_if_t<E, string> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(
detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
string name;
auto check_value = U{0};
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (const auto v = static_cast<U>(enum_value<D, S>(i)); (static_cast<U>(value) & v) != 0) {
if (const auto v = static_cast<U>(enum_value<D, S>(i));
(static_cast<U>(value) & v) != 0) {
if (const auto n = detail::names_v<D, S>[i]; !n.empty()) {
check_value |= v;
if (!name.empty()) {
@@ -95,11 +103,15 @@ template <typename E>
// Obtains enum-flags value from integer value.
// Returns optional with enum-flags value.
template <typename E>
[[nodiscard]] constexpr auto enum_flags_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
[[nodiscard]] constexpr auto
enum_flags_cast(underlying_type_t<E> value) noexcept
-> detail::enable_if_t<E, optional<std::decay_t<E>>> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(
detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
@@ -108,7 +120,8 @@ template <typename E>
if constexpr (detail::is_sparse_v<D, S>) {
auto check_value = U{0};
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (const auto v = static_cast<U>(enum_value<D, S>(i)); (value & v) != 0) {
if (const auto v = static_cast<U>(enum_value<D, S>(i));
(value & v) != 0) {
check_value |= v;
}
}
@@ -131,11 +144,17 @@ template <typename E>
// Obtains enum-flags value from name.
// Returns optional with enum-flags value.
template <typename E, typename BinaryPredicate = std::equal_to<>>
[[nodiscard]] constexpr auto enum_flags_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
[[nodiscard]] constexpr auto enum_flags_cast(
string_view value,
[[maybe_unused]] BinaryPredicate p =
{}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>())
-> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(
detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
@@ -168,7 +187,8 @@ template <typename E, typename BinaryPredicate = std::equal_to<>>
// Checks whether enum-flags contains value with such value.
template <typename E>
[[nodiscard]] constexpr auto enum_flags_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
[[nodiscard]] constexpr auto enum_flags_contains(E value) noexcept
-> detail::enable_if_t<E, bool> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
@@ -177,7 +197,9 @@ template <typename E>
// Checks whether enum-flags contains value with such integer value.
template <typename E>
[[nodiscard]] constexpr auto enum_flags_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
[[nodiscard]] constexpr auto
enum_flags_contains(underlying_type_t<E> value) noexcept
-> detail::enable_if_t<E, bool> {
using D = std::decay_t<E>;
return static_cast<bool>(enum_flags_cast<D>(value));
@@ -185,7 +207,10 @@ template <typename E>
// Checks whether enum-flags contains enumerator with such name.
template <typename E, typename BinaryPredicate = std::equal_to<>>
[[nodiscard]] constexpr auto enum_flags_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
[[nodiscard]] constexpr auto
enum_flags_contains(string_view value, BinaryPredicate p = {}) noexcept(
detail::is_nothrow_invocable<BinaryPredicate>())
-> detail::enable_if_t<E, bool, BinaryPredicate> {
using D = std::decay_t<E>;
return static_cast<bool>(enum_flags_cast<D>(value, std::move(p)));
@@ -194,16 +219,21 @@ template <typename E, typename BinaryPredicate = std::equal_to<>>
// Checks whether `flags set` contains `flag`.
// Note: If `flag` equals 0, it returns false, as 0 is not a flag.
template <typename E>
constexpr auto enum_flags_test(E flags, E flag) noexcept -> detail::enable_if_t<E, bool> {
constexpr auto enum_flags_test(E flags, E flag) noexcept
-> detail::enable_if_t<E, bool> {
using U = underlying_type_t<E>;
return static_cast<U>(flag) && ((static_cast<U>(flags) & static_cast<U>(flag)) == static_cast<U>(flag));
return static_cast<U>(flag) &&
((static_cast<U>(flags) & static_cast<U>(flag)) ==
static_cast<U>(flag));
}
// Checks whether `lhs flags set` and `rhs flags set` have common flags.
// Note: If `lhs flags set` or `rhs flags set` equals 0, it returns false, as 0 is not a flag, and therfore cannot have any matching flag.
// Note: If `lhs flags set` or `rhs flags set` equals 0, it returns false, as 0
// is not a flag, and therfore cannot have any matching flag.
template <typename E>
constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t<E, bool> {
constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept
-> detail::enable_if_t<E, bool> {
using U = underlying_type_t<E>;
return (static_cast<U>(lhs) & static_cast<U>(rhs)) != 0;
@@ -212,11 +242,11 @@ constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t
} // namespace magic_enum
#if defined(__clang__)
# pragma clang diagnostic pop
#pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
# pragma warning(pop)
#pragma warning(pop)
#endif
#endif // NEARGYE_MAGIC_ENUM_FLAGS_HPP
@@ -11,23 +11,23 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef NEARGYE_MAGIC_ENUM_FORMAT_HPP
#define NEARGYE_MAGIC_ENUM_FORMAT_HPP
@@ -36,17 +36,16 @@
#include "magic_enum_flags.hpp"
#if !defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT)
# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT 1
# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE
#define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT 1
#define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE
#endif
namespace magic_enum::customize {
// customize enum to enable/disable automatic std::format
template <typename E>
constexpr bool enum_format_enabled() noexcept {
return MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT;
}
} // magic_enum::customize
// customize enum to enable/disable automatic std::format
template <typename E> constexpr bool enum_format_enabled() noexcept {
return MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT;
}
} // namespace magic_enum::customize
#if defined(__cpp_lib_format)
@@ -55,24 +54,33 @@ namespace magic_enum::customize {
#endif
template <typename E>
struct std::formatter<E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && magic_enum::customize::enum_format_enabled<E>(), char>> : std::formatter<std::string_view, char> {
template <class FormatContext>
auto format(E e, FormatContext& ctx) const {
static_assert(std::is_same_v<char, string_view::value_type>, "formatter requires string_view::value_type type same as char.");
struct std::formatter<
E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> &&
magic_enum::customize::enum_format_enabled<E>(),
char>> : std::formatter<std::string_view, char> {
template <class FormatContext> auto format(E e, FormatContext &ctx) const {
static_assert(
std::is_same_v<char, string_view::value_type>,
"formatter requires string_view::value_type type same as char.");
using D = std::decay_t<E>;
if constexpr (magic_enum::detail::supported<D>::value) {
if constexpr (magic_enum::detail::subtype_v<D> == magic_enum::detail::enum_subtype::flags) {
if (const auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
if constexpr (magic_enum::detail::subtype_v<D> ==
magic_enum::detail::enum_subtype::flags) {
if (const auto name = magic_enum::enum_flags_name<D>(e);
!name.empty()) {
return formatter<std::string_view, char>::format(
std::string_view{name.data(), name.size()}, ctx);
}
} else {
if (const auto name = magic_enum::enum_name<D>(e); !name.empty()) {
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
return formatter<std::string_view, char>::format(
std::string_view{name.data(), name.size()}, ctx);
}
}
}
return formatter<std::string_view, char>::format(std::to_string(magic_enum::enum_integer<D>(e)), ctx);
return formatter<std::string_view, char>::format(
std::to_string(magic_enum::enum_integer<D>(e)), ctx);
}
};
@@ -83,32 +91,41 @@ struct std::formatter<E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && mag
#include <fmt/format.h"
template <typename E>
struct fmt::formatter<E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && magic_enum::customize::enum_format_enabled<E>(), char>> : fmt::formatter<std::string_view> {
template <class FormatContext>
auto format(E e, FormatContext& ctx) const {
static_assert(std::is_same_v<char, string_view::value_type>, "formatter requires string_view::value_type type same as char.");
struct fmt::formatter<
E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> &&
magic_enum::customize::enum_format_enabled<E>(),
char>> : fmt::formatter<std::string_view> {
template <class FormatContext> auto format(E e, FormatContext &ctx) const {
static_assert(
std::is_same_v<char, string_view::value_type>,
"formatter requires string_view::value_type type same as char.");
using D = std::decay_t<E>;
if constexpr (magic_enum::detail::supported<D>::value) {
if constexpr (magic_enum::detail::subtype_v<D> == magic_enum::detail::enum_subtype::flags) {
if (const auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
if constexpr (magic_enum::detail::subtype_v<D> ==
magic_enum::detail::enum_subtype::flags) {
if (const auto name = magic_enum::enum_flags_name<D>(e);
!name.empty()) {
return formatter<std::string_view, char>::format(
std::string_view{name.data(), name.size()}, ctx);
}
} else {
if (const auto name = magic_enum::enum_name<D>(e); !name.empty()) {
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
return formatter<std::string_view, char>::format(
std::string_view{name.data(), name.size()}, ctx);
}
}
}
return formatter<std::string_view, char>::format(std::to_string(magic_enum::enum_integer<D>(e)), ctx);
return formatter<std::string_view, char>::format(
std::to_string(magic_enum::enum_integer<D>(e)), ctx);
}
};
#endif
#if defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE)
# undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT
# undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE
#undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT
#undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE
#endif
#endif // NEARGYE_MAGIC_ENUM_FORMAT_HPP
@@ -11,23 +11,23 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef NEARGYE_MAGIC_ENUM_FUSE_HPP
#define NEARGYE_MAGIC_ENUM_FUSE_HPP
@@ -39,7 +39,8 @@ namespace magic_enum {
namespace detail {
template <typename E>
constexpr optional<std::uintmax_t> fuse_one_enum(optional<std::uintmax_t> hash, E value) noexcept {
constexpr optional<std::uintmax_t> fuse_one_enum(optional<std::uintmax_t> hash,
E value) noexcept {
if (hash) {
if (const auto index = enum_index(value)) {
return (*hash << log2((enum_count<E>() << 1) - 1)) | *index;
@@ -68,14 +69,19 @@ constexpr auto typesafe_fuse_enum(Es... values) noexcept {
return optional<enum_fuse_t>{};
}
} // namespace magic_enum::detail
} // namespace detail
// Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements.
// Returns a bijective mix of several enum values. This can be used to emulate
// 2D switch/case statements.
template <typename... Es>
[[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept {
static_assert((std::is_enum_v<std::decay_t<Es>> && ...), "magic_enum::enum_fuse requires enum type.");
static_assert(sizeof...(Es) >= 2, "magic_enum::enum_fuse requires at least 2 values.");
static_assert((detail::log2(enum_count<std::decay_t<Es>>() + 1) + ...) <= (sizeof(std::uintmax_t) * 8), "magic_enum::enum_fuse does not work for large enums");
static_assert((std::is_enum_v<std::decay_t<Es>> && ...),
"magic_enum::enum_fuse requires enum type.");
static_assert(sizeof...(Es) >= 2,
"magic_enum::enum_fuse requires at least 2 values.");
static_assert((detail::log2(enum_count<std::decay_t<Es>>() + 1) + ...) <=
(sizeof(std::uintmax_t) * 8),
"magic_enum::enum_fuse does not work for large enums");
#if defined(MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE)
const auto fuse = detail::fuse_enum<std::decay_t<Es>...>(values...);
#else
@@ -11,23 +11,23 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef NEARGYE_MAGIC_ENUM_IOSTREAM_HPP
#define NEARGYE_MAGIC_ENUM_IOSTREAM_HPP
@@ -43,8 +43,10 @@ namespace magic_enum {
namespace ostream_operators {
template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, E value) {
template <typename Char, typename Traits, typename E,
detail::enable_if_t<E, int> = 0>
std::basic_ostream<Char, Traits> &
operator<<(std::basic_ostream<Char, Traits> &os, E value) {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
@@ -68,17 +70,21 @@ std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& o
return (os << static_cast<U>(value));
}
template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, optional<E> value) {
template <typename Char, typename Traits, typename E,
detail::enable_if_t<E, int> = 0>
std::basic_ostream<Char, Traits> &
operator<<(std::basic_ostream<Char, Traits> &os, optional<E> value) {
return value ? (os << *value) : os;
}
} // namespace magic_enum::ostream_operators
} // namespace ostream_operators
namespace istream_operators {
template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& is, E& value) {
template <typename Char, typename Traits, typename E,
detail::enable_if_t<E, int> = 0>
std::basic_istream<Char, Traits> &
operator>>(std::basic_istream<Char, Traits> &is, E &value) {
using D = std::decay_t<E>;
std::basic_string<Char, Traits> s;
@@ -103,14 +109,14 @@ std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& i
return is;
}
} // namespace magic_enum::istream_operators
} // namespace istream_operators
namespace iostream_operators {
using magic_enum::ostream_operators::operator<<;
using magic_enum::istream_operators::operator>>;
} // namespace magic_enum::iostream_operators
} // namespace iostream_operators
} // namespace magic_enum
@@ -11,23 +11,23 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef NEARGYE_MAGIC_ENUM_SWITCH_HPP
#define NEARGYE_MAGIC_ENUM_SWITCH_HPP
@@ -40,8 +40,7 @@ namespace detail {
struct default_result_type {};
template <typename T>
struct identity {
template <typename T> struct identity {
using type = T;
};
@@ -58,18 +57,21 @@ using invoke_result_t = typename invoke_result<F, V>::type;
template <typename E, enum_subtype S, typename F, std::size_t... I>
constexpr auto common_invocable(std::index_sequence<I...>) noexcept {
static_assert(std::is_enum_v<E>, "magic_enum::detail::invocable_index requires enum type.");
static_assert(std::is_enum_v<E>,
"magic_enum::detail::invocable_index requires enum type.");
if constexpr (count_v<E, S> == 0) {
return identity<nonesuch>{};
} else {
return std::common_type<invoke_result_t<F, enum_constant<values_v<E, S>[I]>>...>{};
return std::common_type<
invoke_result_t<F, enum_constant<values_v<E, S>[I]>>...>{};
}
}
template <typename E, enum_subtype S, typename Result, typename F>
constexpr auto result_type() noexcept {
static_assert(std::is_enum_v<E>, "magic_enum::detail::result_type requires enum type.");
static_assert(std::is_enum_v<E>,
"magic_enum::detail::result_type requires enum type.");
constexpr auto seq = std::make_index_sequence<count_v<E, S>>{};
using R = typename decltype(common_invocable<E, S, F>(seq))::type;
@@ -90,20 +92,25 @@ constexpr auto result_type() noexcept {
}
}
template <typename E, enum_subtype S, typename Result, typename F, typename D = std::decay_t<E>, typename R = typename decltype(result_type<D, S, Result, F>())::type>
using result_t = std::enable_if_t<std::is_enum_v<D> && !std::is_same_v<R, nonesuch>, R>;
template <typename E, enum_subtype S, typename Result, typename F,
typename D = std::decay_t<E>,
typename R = typename decltype(result_type<D, S, Result, F>())::type>
using result_t =
std::enable_if_t<std::is_enum_v<D> && !std::is_same_v<R, nonesuch>, R>;
#if !defined(MAGIC_ENUM_ENABLE_HASH) && !defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
template <typename T = void>
inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) { return T{}; };
inline constexpr auto default_result_type_lambda =
[]() noexcept(std::is_nothrow_default_constructible_v<T>) { return T{}; };
template <>
inline constexpr auto default_result_type_lambda<void> = []() noexcept {};
template <std::size_t I, std::size_t End, typename R, typename E, enum_subtype S, typename F, typename Def>
constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) {
if constexpr(I < End) {
template <std::size_t I, std::size_t End, typename R, typename E,
enum_subtype S, typename F, typename Def>
constexpr decltype(auto) constexpr_switch_impl(F &&f, E value, Def &&def) {
if constexpr (I < End) {
constexpr auto v = enum_constant<enum_value<E, I, S>()>{};
if (value == v) {
if constexpr (std::is_invocable_r_v<R, F, decltype(v)>) {
@@ -112,7 +119,8 @@ constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) {
return def();
}
} else {
return constexpr_switch_impl<I + 1, End, R, E, S>(std::forward<F>(f), value, std::forward<Def>(def));
return constexpr_switch_impl<I + 1, End, R, E, S>(
std::forward<F>(f), value, std::forward<Def>(def));
}
} else {
return def();
@@ -120,76 +128,92 @@ constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) {
}
template <typename R, typename E, enum_subtype S, typename F, typename Def>
constexpr decltype(auto) constexpr_switch(F&& f, E value, Def&& def) {
static_assert(is_enum_v<E>, "magic_enum::detail::constexpr_switch requires enum type.");
constexpr decltype(auto) constexpr_switch(F &&f, E value, Def &&def) {
static_assert(is_enum_v<E>,
"magic_enum::detail::constexpr_switch requires enum type.");
if constexpr (count_v<E, S> == 0) {
return def();
} else {
return constexpr_switch_impl<0, count_v<E, S>, R, E, S>(std::forward<F>(f), value, std::forward<Def>(def));
return constexpr_switch_impl<0, count_v<E, S>, R, E, S>(
std::forward<F>(f), value, std::forward<Def>(def));
}
}
#endif
} // namespace magic_enum::detail
} // namespace detail
template <typename Result = detail::default_result_type, typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F, typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F&& f, E value) {
template <typename Result = detail::default_result_type, typename E,
detail::enum_subtype S = detail::subtype_v<E>, typename F,
typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F &&f, E value) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(std::is_enum_v<D>,
"magic_enum::enum_switch requires enum type.");
static_assert(
detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
std::forward<F>(f),
value,
detail::default_result_type_lambda<R>);
return detail::constexpr_switch<&detail::values_v<D, S>,
detail::case_call_t::value>(
std::forward<F>(f), value, detail::default_result_type_lambda<R>);
#else
return detail::constexpr_switch<R, D, S>(
std::forward<F>(f),
value,
detail::default_result_type_lambda<R>);
std::forward<F>(f), value, detail::default_result_type_lambda<R>);
#endif
}
template <typename Result = detail::default_result_type, detail::enum_subtype S, typename E, typename F, typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F&& f, E value) {
template <typename Result = detail::default_result_type, detail::enum_subtype S,
typename E, typename F,
typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F &&f, E value) {
return enum_switch<Result, E, S>(std::forward<F>(f), value);
}
template <typename Result, typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F, typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
template <typename Result, typename E,
detail::enum_subtype S = detail::subtype_v<E>, typename F,
typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F &&f, E value, Result &&result) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(std::is_enum_v<D>,
"magic_enum::enum_switch requires enum type.");
static_assert(
detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
std::forward<F>(f),
value,
return detail::constexpr_switch<&detail::values_v<D, S>,
detail::case_call_t::value>(
std::forward<F>(f), value,
[&result]() -> R { return std::forward<Result>(result); });
#else
return detail::constexpr_switch<R, D, S>(
std::forward<F>(f),
value,
std::forward<F>(f), value,
[&result]() -> R { return std::forward<Result>(result); });
#endif
}
template <typename Result, detail::enum_subtype S, typename E, typename F, typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
return enum_switch<Result, E, S>(std::forward<F>(f), value, std::forward<Result>(result));
template <typename Result, detail::enum_subtype S, typename E, typename F,
typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F &&f, E value, Result &&result) {
return enum_switch<Result, E, S>(std::forward<F>(f), value,
std::forward<Result>(result));
}
} // namespace magic_enum
template <>
struct std::common_type<magic_enum::detail::nonesuch, magic_enum::detail::nonesuch> : magic_enum::detail::identity<magic_enum::detail::nonesuch> {};
struct std::common_type<magic_enum::detail::nonesuch,
magic_enum::detail::nonesuch>
: magic_enum::detail::identity<magic_enum::detail::nonesuch> {};
template <typename T>
struct std::common_type<T, magic_enum::detail::nonesuch> : magic_enum::detail::identity<T> {};
struct std::common_type<T, magic_enum::detail::nonesuch>
: magic_enum::detail::identity<T> {};
template <typename T>
struct std::common_type<magic_enum::detail::nonesuch, T> : magic_enum::detail::identity<T> {};
struct std::common_type<magic_enum::detail::nonesuch, T>
: magic_enum::detail::identity<T> {};
#endif // NEARGYE_MAGIC_ENUM_SWITCH_HPP
@@ -11,23 +11,23 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef NEARGYE_MAGIC_ENUM_UTILITY_HPP
#define NEARGYE_MAGIC_ENUM_UTILITY_HPP
@@ -39,20 +39,27 @@ namespace magic_enum {
namespace detail {
template <typename E, enum_subtype S, typename F, std::size_t... I>
constexpr auto for_each(F&& f, std::index_sequence<I...>) {
constexpr bool has_void_return = (std::is_void_v<std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> || ...);
constexpr bool all_same_return = (std::is_same_v<std::invoke_result_t<F, enum_constant<values_v<E, S>[0]>>, std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> && ...);
constexpr auto for_each(F &&f, std::index_sequence<I...>) {
constexpr bool has_void_return =
(std::is_void_v<
std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> ||
...);
constexpr bool all_same_return =
(std::is_same_v<
std::invoke_result_t<F, enum_constant<values_v<E, S>[0]>>,
std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> &&
...);
if constexpr (has_void_return) {
(f(enum_constant<values_v<E, S>[I]>{}), ...);
(f(enum_constant<values_v<E, S>[I]> {}), ...);
} else if constexpr (all_same_return) {
return std::array{f(enum_constant<values_v<E, S>[I]>{})...};
return std::array{f(enum_constant<values_v<E, S>[I]> {})...};
} else {
return std::tuple{f(enum_constant<values_v<E, S>[I]>{})...};
return std::tuple{f(enum_constant<values_v<E, S>[I]> {})...};
}
}
template <typename E, enum_subtype S, typename F,std::size_t... I>
template <typename E, enum_subtype S, typename F, std::size_t... I>
constexpr bool all_invocable(std::index_sequence<I...>) {
if constexpr (count_v<E, S> == 0) {
return false;
@@ -61,24 +68,32 @@ constexpr bool all_invocable(std::index_sequence<I...>) {
}
}
} // namespace magic_enum::detail
} // namespace detail
template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F, detail::enable_if_t<E, int> = 0>
constexpr auto enum_for_each(F&& f) {
template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F,
detail::enable_if_t<E, int> = 0>
constexpr auto enum_for_each(F &&f) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_for_each requires enum type.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(std::is_enum_v<D>,
"magic_enum::enum_for_each requires enum type.");
static_assert(
detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
constexpr auto sep = std::make_index_sequence<detail::count_v<D, S>>{};
if constexpr (detail::all_invocable<D, S, F>(sep)) {
return detail::for_each<D, S>(std::forward<F>(f), sep);
} else {
static_assert(detail::always_false_v<D>, "magic_enum::enum_for_each requires invocable of all enum value.");
static_assert(
detail::always_false_v<D>,
"magic_enum::enum_for_each requires invocable of all enum value.");
}
}
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_next_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
[[nodiscard]] constexpr auto enum_next_value(E value,
std::ptrdiff_t n = 1) noexcept
-> detail::enable_if_t<E, optional<std::decay_t<E>>> {
using D = std::decay_t<E>;
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
@@ -92,12 +107,15 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
}
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_next_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
[[nodiscard]] constexpr auto
enum_next_value_circular(E value, std::ptrdiff_t n = 1) noexcept
-> detail::enable_if_t<E, std::decay_t<E>> {
using D = std::decay_t<E>;
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
if (const auto i = enum_index<D, S>(value)) {
const std::ptrdiff_t index = ((((static_cast<std::ptrdiff_t>(*i) + n) % count) + count) % count);
const std::ptrdiff_t index =
((((static_cast<std::ptrdiff_t>(*i) + n) % count) + count) % count);
if (index >= 0 && index < count) {
return enum_value<D, S>(static_cast<std::size_t>(index));
}
@@ -106,7 +124,9 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
}
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_prev_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
[[nodiscard]] constexpr auto enum_prev_value(E value,
std::ptrdiff_t n = 1) noexcept
-> detail::enable_if_t<E, optional<std::decay_t<E>>> {
using D = std::decay_t<E>;
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
@@ -120,12 +140,15 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
}
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_prev_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
[[nodiscard]] constexpr auto
enum_prev_value_circular(E value, std::ptrdiff_t n = 1) noexcept
-> detail::enable_if_t<E, std::decay_t<E>> {
using D = std::decay_t<E>;
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
if (const auto i = enum_index<D, S>(value)) {
const std::ptrdiff_t index = ((((static_cast<std::ptrdiff_t>(*i) - n) % count) + count) % count);
const std::ptrdiff_t index =
((((static_cast<std::ptrdiff_t>(*i) - n) % count) + count) % count);
if (index >= 0 && index < count) {
return enum_value<D, S>(static_cast<std::size_t>(index));
}