Introduce bit_cast() backport (#2991)

This commit is contained in:
Oxan van Leeuwen 2022-01-04 10:14:57 +01:00 committed by GitHub
parent 26dd1f8532
commit e5775cf812
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 13 deletions

View file

@ -255,7 +255,7 @@ uint32_t fnv1_hash(const std::string &str);
/// @name STL backports /// @name STL backports
///@{ ///@{
// std::to_string() from C++11, available from libstdc++/g++ 8+ // std::to_string() from C++11, available from libstdc++/g++ 8
// See https://github.com/espressif/esp-idf/issues/1445 // See https://github.com/espressif/esp-idf/issues/1445
#if _GLIBCXX_RELEASE >= 8 #if _GLIBCXX_RELEASE >= 8
using std::to_string; using std::to_string;
@ -271,6 +271,32 @@ inline std::string to_string(double value) { return str_snprintf("%f", 32, value
inline std::string to_string(long double value) { return str_snprintf("%Lf", 32, value); } inline std::string to_string(long double value) { return str_snprintf("%Lf", 32, value); }
#endif #endif
// std::is_trivially_copyable from C++11, implemented in libstdc++/g++ 5.1 (but minor releases can't be detected)
#if _GLIBCXX_RELEASE >= 6
using std::is_trivially_copyable;
#else
// Implementing this is impossible without compiler intrinsics, so don't bother. Invalid usage will be detected on
// other variants that use a newer compiler anyway.
// NOLINTNEXTLINE(readability-identifier-naming)
template<typename T> struct is_trivially_copyable : public std::integral_constant<bool, true> {};
#endif
// std::bit_cast from C++20
#if __cpp_lib_bit_cast >= 201806
using std::bit_cast;
#else
/// Convert data between types, without aliasing issues or undefined behaviour.
template<
typename To, typename From,
enable_if_t<sizeof(To) == sizeof(From) && is_trivially_copyable<From>::value && is_trivially_copyable<To>::value,
int> = 0>
To bit_cast(const From &src) {
To dst;
memcpy(&dst, &src, sizeof(To));
return dst;
}
#endif
// std::byteswap is from C++23 and technically should be a template, but this will do for now. // std::byteswap is from C++23 and technically should be a template, but this will do for now.
constexpr uint8_t byteswap(uint8_t n) { return n; } constexpr uint8_t byteswap(uint8_t n) { return n; }
constexpr uint16_t byteswap(uint16_t n) { return __builtin_bswap16(n); } constexpr uint16_t byteswap(uint16_t n) { return __builtin_bswap16(n); }

View file

@ -2,7 +2,8 @@
#include <cstring> #include <cstring>
#include <cstdint> #include <cstdint>
#include <type_traits>
#include "esphome/core/helpers.h"
namespace esphome { namespace esphome {
@ -45,20 +46,12 @@ class ESPPreferences {
*/ */
virtual bool sync() = 0; virtual bool sync() = 0;
#ifndef USE_ESP8266 template<typename T, enable_if_t<is_trivially_copyable<T>::value, bool> = true>
template<typename T, typename std::enable_if<std::is_trivially_copyable<T>::value, bool>::type = true>
#else
// esp8266 toolchain doesn't have is_trivially_copyable
template<typename T>
#endif
ESPPreferenceObject make_preference(uint32_t type, bool in_flash) { ESPPreferenceObject make_preference(uint32_t type, bool in_flash) {
return this->make_preference(sizeof(T), type, in_flash); return this->make_preference(sizeof(T), type, in_flash);
} }
#ifndef USE_ESP8266
template<typename T, typename std::enable_if<std::is_trivially_copyable<T>::value, bool>::type = true> template<typename T, enable_if_t<is_trivially_copyable<T>::value, bool> = true>
#else
template<typename T>
#endif
ESPPreferenceObject make_preference(uint32_t type) { ESPPreferenceObject make_preference(uint32_t type) {
return this->make_preference(sizeof(T), type); return this->make_preference(sizeof(T), type);
} }