Skip to content

Commit 8347698

Browse files
committed
Add float functions from endian byte values
1 parent c0e67fc commit 8347698

File tree

3 files changed

+106
-19
lines changed

3 files changed

+106
-19
lines changed

num/__private/float_macros.h

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <concepts>
2020

21+
#include "containers/array.h"
2122
#include "marker/unsafe.h"
2223
#include "num/__private/float_ordering.h"
2324
#include "num/__private/intrinsics.h"
@@ -695,23 +696,56 @@
695696
return r; \
696697
}
697698

698-
// from_be_bytes, from_le_bytes, from_ne_bytes
699+
#define _sus__float_endian(T, PrimitiveT, UnsignedIntT) \
700+
/** Create a floating point value from its representation as a byte array in \
701+
* big endian. \
702+
* \
703+
* See `##T##::from_bits()` for why this function is not constexpr. \
704+
*/ \
705+
static T from_be_bytes( \
706+
const ::sus::Array<u8, sizeof(PrimitiveT)>& bytes) noexcept { \
707+
return T::from_bits(UnsignedIntT::from_be_bytes(bytes)); \
708+
} \
709+
/** Create a floating point value from its representation as a byte array in \
710+
* big endian. \
711+
* \
712+
* See `##T##::from_bits()` for why this function is not constexpr. \
713+
*/ \
714+
static T from_le_bytes( \
715+
const ::sus::Array<u8, sizeof(PrimitiveT)>& bytes) noexcept { \
716+
return T::from_bits(UnsignedIntT::from_le_bytes(bytes)); \
717+
} \
718+
/** Create a floating point value from its representation as a byte array in \
719+
* native endian. \
720+
* \
721+
* As the target platform’s native endianness is used, portable code likely \
722+
* wants to use `from_be_bytes()` or `from_le_bytes()`, as appropriate \
723+
* instead. \
724+
* \
725+
* See `##T##::from_bits()` for why this function is not constexpr. \
726+
*/ \
727+
static T from_ne_bytes( \
728+
const ::sus::Array<u8, sizeof(PrimitiveT)>& bytes) noexcept { \
729+
return T::from_bits(UnsignedIntT::from_ne_bytes(bytes)); \
730+
}
731+
699732
// to_be_bytes, to_le_bytes, to_ne_bytes
700733

701-
#define _sus__float(T, PrimitiveT, UnsignedIntT) \
702-
_sus__float_storage(PrimitiveT); \
703-
_sus__float_constants(T, PrimitiveT); \
704-
_sus__float_construct(T, PrimitiveT); \
705-
_sus__float_comparison(T); \
706-
_sus__float_unary_ops(T); \
707-
_sus__float_binary_ops(T); \
708-
_sus__float_mutable_ops(T); \
709-
_sus__float_abs(T, PrimitiveT); \
710-
_sus__float_math(T, PrimitiveT); \
711-
_sus__float_fract_trunc(T); \
712-
_sus__float_convert_to(T, PrimitiveT); \
713-
_sus__float_bytes(T, UnsignedIntT); \
714-
_sus__float_category(T); \
715-
_sus__float_clamp(T); \
716-
_sus__float_euclid(T, PrimitiveT); \
734+
#define _sus__float(T, PrimitiveT, UnsignedIntT) \
735+
_sus__float_storage(PrimitiveT); \
736+
_sus__float_constants(T, PrimitiveT); \
737+
_sus__float_construct(T, PrimitiveT); \
738+
_sus__float_comparison(T); \
739+
_sus__float_unary_ops(T); \
740+
_sus__float_binary_ops(T); \
741+
_sus__float_mutable_ops(T); \
742+
_sus__float_abs(T, PrimitiveT); \
743+
_sus__float_math(T, PrimitiveT); \
744+
_sus__float_fract_trunc(T); \
745+
_sus__float_convert_to(T, PrimitiveT); \
746+
_sus__float_bytes(T, UnsignedIntT); \
747+
_sus__float_category(T); \
748+
_sus__float_clamp(T); \
749+
_sus__float_euclid(T, PrimitiveT); \
750+
_sus__float_endian(T, PrimitiveT, UnsignedIntT); \
717751
static_assert(true)

num/f32_unittest.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <bit>
1818
#include <limits>
1919

20+
#include "construct/into.h"
2021
#include "num/__private/intrinsics.h"
2122
#include "num/float.h"
2223
#include "third_party/googletest/googletest/include/gtest/gtest.h"
@@ -975,4 +976,28 @@ TEST(f32, RemEuclid) {
975976
EXPECT_NE((-f32::EPSILON()).rem_euclid(3_f32), 0_f32);
976977
}
977978

979+
TEST(f32, FromBeBytes) {
980+
auto value = f32::from_be_bytes(
981+
sus::Array<u8, 4>::with_values(0x41_u8, 0x48_u8, 0x00_u8, 0x00_u8));
982+
EXPECT_EQ(value, 12.5_f32);
983+
}
984+
985+
TEST(f32, FromLeBytes) {
986+
auto value = f32::from_le_bytes(
987+
sus::Array<u8, 4>::with_values(0x00_u8, 0x00_u8, 0x48_u8, 0x41_u8));
988+
EXPECT_EQ(value, 12.5_f32);
989+
}
990+
991+
TEST(f32, FromNeBytes) {
992+
if constexpr (sus::assertions::is_big_endian()) {
993+
auto value = f32::from_ne_bytes(
994+
sus::Array<u8, 4>::with_values(0x41_u8, 0x48_u8, 0x00_u8, 0x00_u8));
995+
EXPECT_EQ(value, 12.5_f32);
996+
} else {
997+
auto value = f32::from_ne_bytes(
998+
sus::Array<u8, 4>::with_values(0x00_u8, 0x00_u8, 0x48_u8, 0x41_u8));
999+
EXPECT_EQ(value, 12.5_f32);
1000+
}
1001+
}
1002+
9781003
} // namespace

num/f64_unittest.cc

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ TEST(f64, TotalCmp) {
242242
sus::num::__private::float_is_nan_quiet(signaling_nan2.primitive_value));
243243

244244
const auto neg_quiet_nan = std::bit_cast<f64>(uint64_t{0xfff8000000000000});
245-
const auto neg_signaling_nan = std::bit_cast<f64>(uint64_t{0xfff0000000000001});
245+
const auto neg_signaling_nan =
246+
std::bit_cast<f64>(uint64_t{0xfff0000000000001});
246247
EXPECT_EQ(::fpclassify(neg_quiet_nan.primitive_value), FP_NAN);
247248
EXPECT_EQ(::fpclassify(neg_signaling_nan.primitive_value), FP_NAN);
248249
EXPECT_TRUE(
@@ -251,7 +252,8 @@ TEST(f64, TotalCmp) {
251252
neg_signaling_nan.primitive_value));
252253

253254
const auto neg_quiet_nan2 = std::bit_cast<f64>(uint64_t{0xfff8000000000001});
254-
const auto neg_signaling_nan2 = std::bit_cast<f64>(uint64_t{0xfff0000000000002});
255+
const auto neg_signaling_nan2 =
256+
std::bit_cast<f64>(uint64_t{0xfff0000000000002});
255257
EXPECT_EQ(::fpclassify(neg_quiet_nan2.primitive_value), FP_NAN);
256258
EXPECT_EQ(::fpclassify(neg_signaling_nan2.primitive_value), FP_NAN);
257259
EXPECT_TRUE(
@@ -964,4 +966,30 @@ TEST(f64, RemEuclid) {
964966
EXPECT_NE((-f64::EPSILON()).rem_euclid(3_f64), 0_f64);
965967
}
966968

969+
TEST(f64, FromBeBytes) {
970+
auto value = f64::from_be_bytes(sus::Array<u8, 8>::with_values(
971+
0x40_u8, 0x29_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8));
972+
EXPECT_EQ(value, 12.5_f64);
973+
}
974+
975+
TEST(f64, FromLeBytes) {
976+
auto value = f64::from_le_bytes(sus::Array<u8, 8>::with_values(
977+
0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x29_u8, 0x40_u8));
978+
EXPECT_EQ(value, 12.5_f64);
979+
}
980+
981+
TEST(f64, FromNeBytes) {
982+
if constexpr (sus::assertions::is_big_endian()) {
983+
auto value = f64::from_ne_bytes(
984+
sus::Array<u8, 8>::with_values(0x40_u8, 0x29_u8, 0x00_u8, 0x00_u8,
985+
0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8));
986+
EXPECT_EQ(value, 12.5_f64);
987+
} else {
988+
auto value = f64::from_ne_bytes(
989+
sus::Array<u8, 8>::with_values(0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8,
990+
0x00_u8, 0x00_u8, 0x29_u8, 0x40_u8));
991+
EXPECT_EQ(value, 12.5_f64);
992+
}
993+
}
994+
967995
} // namespace

0 commit comments

Comments
 (0)