#pragma once #include #include #include #include #include #include #include #ifdef _WIN32 # include #else # include #endif namespace scwx::awips { class Message { protected: explicit Message(); Message(const Message&) = delete; Message& operator=(const Message&) = delete; Message(Message&&) noexcept; Message& operator=(Message&&) noexcept; virtual bool ValidateMessage(std::istream& is, std::size_t bytesRead) const; public: virtual ~Message(); virtual std::size_t data_size() const = 0; virtual bool Parse(std::istream& is) = 0; static void ReadBoolean(std::istream& is, bool& value) { std::string data(4, ' '); is.read(reinterpret_cast(&data[0]), 4); value = (data.at(0) == 'T'); } static void ReadChar(std::istream& is, char& value) { std::string data(4, ' '); is.read(reinterpret_cast(&data[0]), 4); value = data.at(0); } static float SwapFloat(float f) { if constexpr (std::endian::native == std::endian::little) { // Variable is initialized by memcpy // NOLINTNEXTLINE(cppcoreguidelines-init-variables) std::uint32_t temp; std::memcpy(&temp, &f, sizeof(std::uint32_t)); temp = ntohl(temp); std::memcpy(&f, &temp, sizeof(float)); } return f; } static double SwapDouble(double d) { if constexpr (std::endian::native == std::endian::little) { // Variable is initialized by memcpy // NOLINTNEXTLINE(cppcoreguidelines-init-variables) std::uint64_t temp; std::memcpy(&temp, &d, sizeof(std::uint64_t)); temp = Swap64(temp); std::memcpy(&d, &temp, sizeof(float)); } return d; } static std::uint64_t Swap64(std::uint64_t value) { if constexpr (std::endian::native == std::endian::little) { // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) const std::uint32_t high = ntohl(static_cast(value >> 32)); const std::uint32_t low = ntohl(static_cast(value & 0xFFFFFFFFULL)); return (static_cast(low) << 32) | high; // NOLINTEND(cppcoreguidelines-avoid-magic-numbers) } else { return value; } } template static void SwapArray(std::array& arr, std::size_t size = kSize) { if constexpr (std::endian::native == std::endian::little) { std::transform(std::execution::par_unseq, arr.begin(), arr.begin() + size, arr.begin(), [](float f) { return SwapFloat(f); }); } } template static void SwapArray(std::array& arr, std::size_t size = kSize) { if constexpr (std::endian::native == std::endian::little) { std::transform(std::execution::par_unseq, arr.begin(), arr.begin() + size, arr.begin(), [](std::int16_t u) { return ntohs(u); }); } } template static void SwapArray(std::array& arr, std::size_t size = kSize) { if constexpr (std::endian::native == std::endian::little) { std::transform(std::execution::par_unseq, arr.begin(), arr.begin() + size, arr.begin(), [](std::uint16_t u) { return ntohs(u); }); } } template static void SwapArray(std::array& arr, std::size_t size = kSize) { if constexpr (std::endian::native == std::endian::little) { std::transform(std::execution::par_unseq, arr.begin(), arr.begin() + size, arr.begin(), [](std::uint32_t u) { return ntohl(u); }); } } template static void SwapMap(std::map& m) { if constexpr (std::endian::native == std::endian::little) { std::for_each(std::execution::par_unseq, m.begin(), m.end(), [](auto& p) { p.second = SwapFloat(p.second); }); } } template static void SwapVector(std::vector& v) { if constexpr (std::endian::native == std::endian::little) { std::transform( std::execution::par_unseq, v.begin(), v.end(), v.begin(), [](T u) { if constexpr (std::is_same_v || std::is_same_v) { return static_cast(ntohs(u)); } else if constexpr (std::is_same_v || std::is_same_v) { return static_cast(ntohl(u)); } else if constexpr (std::is_same_v || std::is_same_v) { return static_cast(Swap64(u)); } else if constexpr (std::is_same_v) { return SwapFloat(u); } else if constexpr (std::is_same_v) { return SwapDouble(u); } else { static_assert(std::is_same_v, "Unsupported type for SwapVector"); } }); } } private: class Impl; std::unique_ptr p; }; } // namespace scwx::awips