重新设置代码格式
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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 {
|
||||
// HDOP(Horizontal Dilution of Precision) 描述的是 水平精度的衰减,即 GPS 系统的水平定位精度与卫星的几何布局有关。HDOP 数值越低,说明卫星的几何布局越好,定位精度越高。
|
||||
// 较低的 HDOP 值(例如 1-2)表示卫星信号较强,且卫星的分布较为理想,因此定位精度较高。
|
||||
// 较高的 HDOP 值(例如 5 或更高)表示卫星信号较弱,或卫星的分布较差,可能导致较差的定位精度。
|
||||
return double(HDOP) / 10.0;
|
||||
}
|
||||
[[nodiscard]] double get_HDOP() const {
|
||||
// HDOP(Horizontal 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(×tamp);
|
||||
//
|
||||
// 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(×tamp);
|
||||
//
|
||||
// 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
|
||||
|
||||
+523
-253
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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user