Skip to content

Commit 6cb99b3

Browse files
committed
Add floating point methods to endian byte arrays
1 parent 8347698 commit 6cb99b3

File tree

3 files changed

+100
-32
lines changed

3 files changed

+100
-32
lines changed

containers/array.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,11 @@ class Array final {
9090
return a;
9191
}
9292

93-
public:
93+
/// Returns the number of elements in the array.
94+
constexpr const /* TODO: usize */ size_t len() const& noexcept {
95+
return N;
96+
}
97+
9498
constexpr const T& get(/* TODO: usize */ size_t i) const& noexcept
9599
requires(N > 0)
96100
{
@@ -119,6 +123,8 @@ class Array final {
119123
return storage_.data_;
120124
}
121125

126+
// TODO: Eq and Ord (like Option and Tuple).
127+
122128
private:
123129
enum WithInitializer { kWithInitializer };
124130
template <class F, size_t... Is>

num/__private/float_macros.h

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -696,37 +696,61 @@
696696
return r; \
697697
}
698698

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)); \
699+
#define _sus__float_endian(T, PrimitiveT, UnsignedIntT) \
700+
/** Return the memory representation of this floating point number as a byte \
701+
* array in big-endian (network) byte order. \
702+
*/ \
703+
constexpr ::sus::Array<u8, sizeof(PrimitiveT)> to_be_bytes() \
704+
const& noexcept { \
705+
return to_bits().to_be_bytes(); \
706+
} \
707+
/** Return the memory representation of this floating point number as a byte \
708+
* array in little-endian byte order. \
709+
*/ \
710+
constexpr ::sus::Array<u8, sizeof(PrimitiveT)> to_le_bytes() \
711+
const& noexcept { \
712+
return to_bits().to_le_bytes(); \
713+
} \
714+
/** Return the memory representation of this floating point number as a byte \
715+
* array in native byte order. \
716+
* \
717+
* As the target platform's native endianness is used, portable code should \
718+
* use `to_be_bytes()` or `to_le_bytes()`, as appropriate, instead. \
719+
*/ \
720+
constexpr ::sus::Array<u8, sizeof(PrimitiveT)> to_ne_bytes() \
721+
const& noexcept { \
722+
return to_bits().to_ne_bytes(); \
723+
} \
724+
/** Create a floating point value from its representation as a byte array in \
725+
* big endian. \
726+
* \
727+
* See `##T##::from_bits()` for why this function is not constexpr. \
728+
*/ \
729+
static T from_be_bytes( \
730+
const ::sus::Array<u8, sizeof(PrimitiveT)>& bytes) noexcept { \
731+
return T::from_bits(UnsignedIntT::from_be_bytes(bytes)); \
732+
} \
733+
/** Create a floating point value from its representation as a byte array in \
734+
* big endian. \
735+
* \
736+
* See `##T##::from_bits()` for why this function is not constexpr. \
737+
*/ \
738+
static T from_le_bytes( \
739+
const ::sus::Array<u8, sizeof(PrimitiveT)>& bytes) noexcept { \
740+
return T::from_bits(UnsignedIntT::from_le_bytes(bytes)); \
741+
} \
742+
/** Create a floating point value from its representation as a byte array in \
743+
* native endian. \
744+
* \
745+
* As the target platform's native endianness is used, portable code likely \
746+
* wants to use `from_be_bytes()` or `from_le_bytes()`, as appropriate \
747+
* instead. \
748+
* \
749+
* See `##T##::from_bits()` for why this function is not constexpr. \
750+
*/ \
751+
static T from_ne_bytes( \
752+
const ::sus::Array<u8, sizeof(PrimitiveT)>& bytes) noexcept { \
753+
return T::from_bits(UnsignedIntT::from_ne_bytes(bytes)); \
730754
}
731755

732756
// to_be_bytes, to_le_bytes, to_ne_bytes

num/f32_unittest.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,44 @@ TEST(f32, RemEuclid) {
976976
EXPECT_NE((-f32::EPSILON()).rem_euclid(3_f32), 0_f32);
977977
}
978978

979+
TEST(f32, ToBeBytes) {
980+
auto array = (12.5_f32).to_be_bytes();
981+
auto expected =
982+
sus::Array<u8, 4>::with_values(0x41_u8, 0x48_u8, 0x00_u8, 0x00_u8);
983+
// TODO: Use Array::operator== via EXPECT_EQ.
984+
EXPECT_EQ(array.len(), expected.len());
985+
for (size_t i = 0; i < array.len(); i += 1) {
986+
SCOPED_TRACE(i);
987+
EXPECT_EQ(array.get(i), expected.get(i));
988+
}
989+
}
990+
991+
TEST(f32, ToLeBytes) {
992+
auto array = (12.5_f32).to_le_bytes();
993+
auto expected =
994+
sus::Array<u8, 4>::with_values(0x00_u8, 0x00_u8, 0x48_u8, 0x41_u8);
995+
// TODO: Use Array::operator== via EXPECT_EQ.
996+
EXPECT_EQ(array.len(), expected.len());
997+
for (size_t i = 0; i < array.len(); i += 1) {
998+
SCOPED_TRACE(i);
999+
EXPECT_EQ(array.get(i), expected.get(i));
1000+
}
1001+
}
1002+
1003+
TEST(f32, ToNeBytes) {
1004+
auto array = (12.5_f32).to_ne_bytes();
1005+
auto expected =
1006+
sus::assertions::is_big_endian()
1007+
? sus::Array<u8, 4>::with_values(0x41_u8, 0x48_u8, 0x00_u8, 0x00_u8)
1008+
: sus::Array<u8, 4>::with_values(0x00_u8, 0x00_u8, 0x48_u8, 0x41_u8);
1009+
// TODO: Use Array::operator== via EXPECT_EQ.
1010+
EXPECT_EQ(array.len(), expected.len());
1011+
for (size_t i = 0; i < array.len(); i += 1) {
1012+
SCOPED_TRACE(i);
1013+
EXPECT_EQ(array.get(i), expected.get(i));
1014+
}
1015+
}
1016+
9791017
TEST(f32, FromBeBytes) {
9801018
auto value = f32::from_be_bytes(
9811019
sus::Array<u8, 4>::with_values(0x41_u8, 0x48_u8, 0x00_u8, 0x00_u8));

0 commit comments

Comments
 (0)