Skip to content

Commit 89828f9

Browse files
laramielcopybara-github
authored andcommitted
Add tests for type default construction
PiperOrigin-RevId: 837208398 Change-Id: I1b31e522e70b4606ae5d192f27c4c4c9e6ffd9fe
1 parent 0e074f5 commit 89828f9

File tree

5 files changed

+213
-89
lines changed

5 files changed

+213
-89
lines changed

tensorstore/util/bfloat16.h

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@
4343
// See the License for the specific language governing permissions and
4444
// limitations under the License.
4545

46+
// Strongly suggest to the compiler that these functions are inlined.
47+
#ifndef TENSORSTORE_BFLOATINLINE
48+
#if defined(_MSC_VER)
49+
#define TENSORSTORE_BFLOATINLINE __forceinline
50+
#else
51+
#define TENSORSTORE_BFLOATINLINE inline
52+
#endif
53+
#endif // TENSORSTORE_BFLOATINLINE
54+
4655
namespace tensorstore {
4756
class BFloat16;
4857
} // namespace tensorstore
@@ -123,29 +132,34 @@ class BFloat16 {
123132
/// `BFloat16` parameter and one integer parameter, we provide an
124133
/// implementation that converts the result back to `BFloat16` for
125134
/// consistency with the builtin floating point operations.
126-
#define TENSORSTORE_INTERNAL_BFLOAT16_ARITHMETIC_OP(OP) \
127-
friend BFloat16 operator OP(BFloat16 a, BFloat16 b) { \
128-
return BFloat16(static_cast<float>(a) OP static_cast<float>(b)); \
129-
} \
130-
template <typename T> \
131-
friend std::enable_if_t<std::numeric_limits<T>::is_integer, BFloat16> \
132-
operator OP(BFloat16 a, T b) { \
133-
return BFloat16(static_cast<float>(a) OP b); \
134-
} \
135-
template <typename T> \
136-
friend std::enable_if_t<std::numeric_limits<T>::is_integer, BFloat16> \
137-
operator OP(T a, BFloat16 b) { \
138-
return BFloat16(a OP static_cast<float>(b)); \
139-
} \
135+
#define TENSORSTORE_INTERNAL_BFLOAT16_ARITHMETIC_OP(OP) \
136+
friend TENSORSTORE_BFLOATINLINE BFloat16 operator OP(BFloat16 a, \
137+
BFloat16 b) { \
138+
return BFloat16(static_cast<float>(a) OP static_cast<float>(b)); \
139+
} \
140+
template <typename T> \
141+
friend TENSORSTORE_BFLOATINLINE \
142+
std::enable_if_t<std::numeric_limits<T>::is_integer, BFloat16> \
143+
operator OP(BFloat16 a, T b) { \
144+
return BFloat16(static_cast<float>(a) OP b); \
145+
} \
146+
template <typename T> \
147+
friend TENSORSTORE_BFLOATINLINE \
148+
std::enable_if_t<std::numeric_limits<T>::is_integer, BFloat16> \
149+
operator OP(T a, BFloat16 b) { \
150+
return BFloat16(a OP static_cast<float>(b)); \
151+
} \
140152
/**/
141153

142154
#define TENSORSTORE_INTERNAL_BFLOAT16_ARITHMETIC_ASSIGN_OP(OP) \
143-
friend BFloat16& operator OP##=(BFloat16 & a, BFloat16 b) { \
155+
friend TENSORSTORE_BFLOATINLINE BFloat16& operator OP## = \
156+
(BFloat16 & a, BFloat16 b) { \
144157
return a = BFloat16(static_cast<float>(a) OP static_cast<float>(b)); \
145158
} \
146159
template <typename T> \
147-
friend std::enable_if_t<std::numeric_limits<T>::is_integer, BFloat16&> \
148-
operator OP##=(BFloat16 & a, T b) { \
160+
friend TENSORSTORE_BFLOATINLINE \
161+
std::enable_if_t<std::numeric_limits<T>::is_integer, BFloat16&> \
162+
operator OP## = (BFloat16 & a, T b) { \
149163
return a = BFloat16(static_cast<float>(a) OP b); \
150164
} \
151165
/**/
@@ -199,7 +213,7 @@ class BFloat16 {
199213
///
200214
/// \membergroup Arithmetic operators
201215
/// \id negate
202-
friend BFloat16 operator-(BFloat16 a) {
216+
TENSORSTORE_BFLOATINLINE friend BFloat16 operator-(BFloat16 a) {
203217
BFloat16 result;
204218
result.rep_ = a.rep_ ^ 0x8000;
205219
return result;
@@ -209,7 +223,7 @@ class BFloat16 {
209223
///
210224
/// \membergroup Arithmetic operators
211225
/// \id unary
212-
friend BFloat16 operator+(BFloat16 a) { return a; }
226+
TENSORSTORE_BFLOATINLINE friend BFloat16 operator+(BFloat16 a) { return a; }
213227

214228
/// Pre-increment.
215229
///
@@ -829,8 +843,10 @@ struct numeric_limits<tensorstore::BFloat16> {
829843
static constexpr bool has_infinity = true;
830844
static constexpr bool has_quiet_NaN = true;
831845
static constexpr bool has_signaling_NaN = true;
846+
#if !defined(__cplusplus) || __cplusplus < 202302L
832847
static constexpr float_denorm_style has_denorm = std::denorm_present;
833848
static constexpr bool has_denorm_loss = false;
849+
#endif
834850
static constexpr std::float_round_style round_style =
835851
numeric_limits<float>::round_style;
836852
static constexpr bool is_iec559 = false;

tensorstore/util/bfloat16_test.cc

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,13 @@ void TestTruncate(float input, float expected_truncation,
8181
}
8282

8383
template <typename T>
84-
void TestRoundtrips() {
84+
class Bfloat16RoundtripTest : public ::testing::Test {};
85+
86+
using RoundtripTypes = ::testing::Types<float, double, bfloat16_t>;
87+
TYPED_TEST_SUITE(Bfloat16RoundtripTest, RoundtripTypes);
88+
89+
TYPED_TEST(Bfloat16RoundtripTest, Roundtrips) {
90+
using T = TypeParam;
8591
for (T value : {
8692
-std::numeric_limits<T>::infinity(),
8793
std::numeric_limits<T>::infinity(),
@@ -96,11 +102,22 @@ void TestRoundtrips() {
96102
}
97103
}
98104

99-
TEST(Bfloat16Test, FloatRoundtrips) { TestRoundtrips<float>(); }
105+
TEST(Bfloat16Test, DefaultConstruction) {
106+
using Float = bfloat16_t;
107+
const Float zero(0);
100108

101-
TEST(Bfloat16Test, DoubleRoundtrips) { TestRoundtrips<double>(); }
109+
// sd is static, so it must be zero initialized.
110+
static Float sd;
111+
EXPECT_EQ(sd, zero);
102112

103-
TEST(Bfloat16Test, Float16Roundtrips) { TestRoundtrips<bfloat16_t>(); }
113+
// z is zero initialized.
114+
Float z{};
115+
EXPECT_EQ(z, zero);
116+
117+
// v is value initialized to zero.
118+
Float v = Float();
119+
EXPECT_EQ(v, zero);
120+
}
104121

105122
TEST(Bfloat16Test, ConversionFromFloat) {
106123
EXPECT_THAT(bfloat16_t(1.0f), MatchesBits(0x3f80));
@@ -367,6 +384,19 @@ TEST(Bfloat16Test, NumericLimits) {
367384
EXPECT_GT(std::numeric_limits<bfloat16_t>::denorm_min(), bfloat16_t(0.f));
368385
EXPECT_EQ(std::numeric_limits<bfloat16_t>::denorm_min() / bfloat16_t(2),
369386
bfloat16_t(0.f));
387+
EXPECT_TRUE(isinf(std::numeric_limits<bfloat16_t>::infinity()));
388+
389+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::digits, 8);
390+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::digits10, 2);
391+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::max_digits10, 4);
392+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::min_exponent, -125);
393+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::min_exponent10, -37);
394+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::max_exponent, 128);
395+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::max_exponent10, 38);
396+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::is_iec559, false);
397+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::has_infinity, true);
398+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::has_quiet_NaN, true);
399+
EXPECT_EQ(std::numeric_limits<bfloat16_t>::has_signaling_NaN, true);
370400
}
371401

372402
TEST(Bfloat16Test, Arithmetic) {

tensorstore/util/float8_test.cc

Lines changed: 96 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -53,35 +53,34 @@ using std::isfinite;
5353
using std::isinf; // NOLINT
5454
using std::isnan; // NOLINT
5555

56-
template <typename Float8_>
57-
class Float8Test : public ::testing::Test {};
58-
5956
// Helper utility for prettier test names.
57+
template <typename T>
58+
std::string TypeToName() {
59+
if constexpr (std::is_same_v<T, Float8e3m4>) return "Float8e3m4";
60+
if constexpr (std::is_same_v<T, Float8e4m3fn>) return "Float8e4m3fn";
61+
if constexpr (std::is_same_v<T, Float8e4m3b11fnuz>)
62+
return "Float8e4m3b11fnuz";
63+
if constexpr (std::is_same_v<T, Float8e5m2>) return "Float8e5m2";
64+
if constexpr (std::is_same_v<T, Float8e4m3fnuz>) return "Float8e4m3fnuz";
65+
if constexpr (std::is_same_v<T, Float8e5m2fnuz>) return "Float8e5m2fnuz";
66+
if constexpr (std::is_same_v<T, long double>) return "long_double";
67+
if constexpr (std::is_same_v<T, double>) return "double";
68+
if constexpr (std::is_same_v<T, float>) return "float";
69+
if constexpr (std::is_same_v<T, tensorstore::BFloat16>) return "BFloat16";
70+
if constexpr (std::is_same_v<T, ::half_float::half>) return "float16";
71+
if constexpr (std::is_same_v<T, bool>) return "bool";
72+
if constexpr (std::is_same_v<T, int32_t>) return "int32_t";
73+
if constexpr (std::is_same_v<T, int64_t>) return "int64_t";
74+
return "unknown";
75+
}
76+
6077
struct Float8TestParamNames {
6178
template <typename TypeParam>
6279
static std::string GetName(int idx) {
63-
if constexpr (std::is_same_v<TypeParam, Float8e3m4>) {
64-
return "Float8e3m4";
65-
} else if constexpr (std::is_same_v<TypeParam, Float8e4m3fn>) {
66-
return "Float8e4m3fn";
67-
} else if constexpr (std::is_same_v<TypeParam, Float8e4m3b11fnuz>) {
68-
return "Float8e4m3b11fnuz";
69-
} else if constexpr (std::is_same_v<TypeParam, Float8e5m2>) {
70-
return "Float8e5m2";
71-
} else if constexpr (std::is_same_v<TypeParam, Float8e4m3fnuz>) {
72-
return "Float8e4m3fnuz";
73-
} else if constexpr (std::is_same_v<TypeParam, Float8e5m2fnuz>) {
74-
return "Float8e5m2fnuz";
75-
}
76-
return absl::StrCat(idx);
80+
return TypeToName<TypeParam>();
7781
}
7882
};
7983

80-
using Float8Types =
81-
::testing::Types<Float8e3m4, Float8e4m3fn, Float8e5m2, Float8e4m3b11fnuz,
82-
Float8e4m3fnuz, Float8e5m2fnuz>;
83-
TYPED_TEST_SUITE(Float8Test, Float8Types, Float8TestParamNames);
84-
8584
TEST(Float8E3m4Test, NumericLimits) {
8685
EXPECT_TRUE(isnan(std::numeric_limits<Float8e3m4>::quiet_NaN()));
8786
EXPECT_TRUE(isnan(std::numeric_limits<Float8e3m4>::signaling_NaN()));
@@ -260,6 +259,32 @@ TEST(Float8E5m2fnuzTest, NumericLimits) {
260259
EXPECT_EQ(std::numeric_limits<Float8e5m2fnuz>::has_signaling_NaN, false);
261260
}
262261

262+
template <typename Float8_>
263+
class Float8Test : public ::testing::Test {};
264+
265+
using Float8Types =
266+
::testing::Types<Float8e3m4, Float8e4m3fn, Float8e5m2, Float8e4m3b11fnuz,
267+
Float8e4m3fnuz, Float8e5m2fnuz>;
268+
269+
TYPED_TEST_SUITE(Float8Test, Float8Types, Float8TestParamNames);
270+
271+
TYPED_TEST(Float8Test, DefaultConstruction) {
272+
using Float = TypeParam;
273+
const Float zero(0);
274+
275+
// sd is static, so it must be zero initialized.
276+
static Float sd;
277+
EXPECT_EQ(sd, zero);
278+
279+
// z is zero initialized.
280+
Float z{};
281+
EXPECT_EQ(z, zero);
282+
283+
// v is value initialized to zero.
284+
Float v = Float();
285+
EXPECT_EQ(v, zero);
286+
}
287+
263288
TYPED_TEST(Float8Test, FromRep) {
264289
using Float8 = TypeParam;
265290
Float8 x = Float8::FromRep(0x4F);
@@ -742,12 +767,17 @@ TYPED_TEST(Float8Test, CallTheOperator) {
742767
EXPECT_THAT((c = a, c /= b),
743768
EqOrIsNan<Float8>(Float8{float{a} / float{b}}));
744769

745-
EXPECT_EQ(a == b, float{a} == float{b}) << float{a} << " vs " << float{b};
746-
EXPECT_EQ(a != b, float{a} != float{b});
747-
EXPECT_EQ(a < b, float{a} < float{b});
748-
EXPECT_EQ(a <= b, float{a} <= float{b});
749-
EXPECT_EQ(a > b, float{a} > float{b});
750-
EXPECT_EQ(a >= b, float{a} >= float{b});
770+
#define COMP(x) \
771+
EXPECT_EQ(a x b, float{a} x float{b}) \
772+
<< a << #x << b << " vs " << float{a} << #x << float{b}
773+
774+
COMP(==);
775+
COMP(!=);
776+
COMP(<); // NOLINT
777+
COMP(<=);
778+
COMP(>); // NOLINT
779+
COMP(>=);
780+
#undef COMP
751781
}
752782
}
753783
}
@@ -775,12 +805,17 @@ TYPED_TEST(Float8Test, CallTheConstOperator) {
775805
EXPECT_THAT((c = a, c /= b),
776806
EqOrIsNan<Float8>(Float8{float{a} / float{b}}));
777807

778-
EXPECT_EQ(a == b, float{a} == float{b}) << float{a} << " vs " << float{b};
779-
EXPECT_EQ(a != b, float{a} != float{b});
780-
EXPECT_EQ(a < b, float{a} < float{b}) << float{a} << " vs " << float{b};
781-
EXPECT_EQ(a <= b, float{a} <= float{b});
782-
EXPECT_EQ(a > b, float{a} > float{b}) << float{a} << " vs " << float{b};
783-
EXPECT_EQ(a >= b, float{a} >= float{b});
808+
#define COMP(x) \
809+
EXPECT_EQ(a x b, float{a} x float{b}) \
810+
<< a << #x << b << " vs " << float{a} << #x << float{b}
811+
812+
COMP(==);
813+
COMP(!=);
814+
COMP(<);
815+
COMP(<=);
816+
COMP(>);
817+
COMP(>=);
818+
#undef COMP
784819
}
785820
}
786821
}
@@ -809,29 +844,36 @@ struct Float8CastTestParamNames {
809844
static std::string GetName(int idx) {
810845
using first_type = typename TypeParam::first_type;
811846
using second_type = typename TypeParam::second_type;
812-
return absl::StrCat(::testing::internal::GetTypeName<first_type>(), "_",
813-
::testing::internal::GetTypeName<second_type>());
847+
return absl::StrCat(TypeToName<first_type>(), "_",
848+
TypeToName<second_type>());
814849
}
815850
};
816851

817-
#define GEN_LONG_DOUBLE_PAIR(Type) std::pair<Type, long double>,
818-
819-
#define GEN_DEST_TYPES(Type) \
820-
GEN_LONG_DOUBLE_PAIR(Type) \
821-
std::pair<Type, double>, std::pair<Type, float>, \
822-
std::pair<Type, tensorstore::BFloat16>, \
823-
std::pair<Type, ::half_float::half>, std::pair<Type, Float8e3m4>, \
824-
std::pair<Type, Float8e4m3fn>, std::pair<Type, Float8e4m3b11fnuz>, \
825-
std::pair<Type, Float8e4m3fnuz>, std::pair<Type, Float8e5m2fnuz>, \
826-
std::pair<Type, Float8e5m2>, std::pair<Type, bool>, \
827-
std::pair<Type, int32_t>, std::pair<Type, int64_t>
828-
829-
#define GEN_TYPE_PAIRS() \
830-
GEN_DEST_TYPES(Float8e3m4), GEN_DEST_TYPES(Float8e4m3fn), \
831-
GEN_DEST_TYPES(Float8e4m3b11fnuz), GEN_DEST_TYPES(Float8e5m2), \
832-
GEN_DEST_TYPES(Float8e4m3fnuz), GEN_DEST_TYPES(Float8e5m2fnuz)
833-
834-
using Float8CastTypePairs = ::testing::Types<GEN_TYPE_PAIRS()>;
852+
// clang-format off
853+
#define GEN_TYPE_PAIRS(T) \
854+
std::pair<T, long double>, \
855+
std::pair<T, double>, \
856+
std::pair<T, float>, \
857+
std::pair<T, tensorstore::BFloat16>, \
858+
std::pair<T, ::half_float::half>, \
859+
std::pair<T, Float8e3m4>, \
860+
std::pair<T, Float8e4m3fn>, \
861+
std::pair<T, Float8e4m3b11fnuz>, \
862+
std::pair<T, Float8e4m3fnuz>, \
863+
std::pair<T, Float8e5m2fnuz>, \
864+
std::pair<T, Float8e5m2>, \
865+
std::pair<T, bool>, \
866+
std::pair<T, int32_t>, \
867+
std::pair<T, int64_t>
868+
869+
using Float8CastTypePairs = ::testing::Types<
870+
GEN_TYPE_PAIRS(Float8e3m4),
871+
GEN_TYPE_PAIRS(Float8e4m3fn),
872+
GEN_TYPE_PAIRS(Float8e4m3b11fnuz),
873+
GEN_TYPE_PAIRS(Float8e5m2),
874+
GEN_TYPE_PAIRS(Float8e4m3fnuz),
875+
GEN_TYPE_PAIRS(Float8e5m2fnuz)>;
876+
// clang-format on
835877

836878
template <typename CastPair>
837879
class Float8CastTest : public ::testing::Test {};

tensorstore/util/int2_test.cc

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,34 @@ TEST(Int2Test, Int2ToInt8) {
5454
}
5555
}
5656

57-
template <typename X>
58-
void TestInt2ToXToInt2() {
57+
template <typename T>
58+
class Int2ToXToInt2Test : public ::testing::Test {};
59+
60+
using ToXToInt2Types = ::testing::Types<int32_t, float, double>;
61+
TYPED_TEST_SUITE(Int2ToXToInt2Test, ToXToInt2Types);
62+
63+
TYPED_TEST(Int2ToXToInt2Test, ToXToInt2) {
64+
using T = TypeParam;
5965
for (const auto& [i4, i8] : kInt2ToInt8) {
60-
EXPECT_EQ(static_cast<Int2>(static_cast<X>(i4)), i4);
66+
EXPECT_EQ(static_cast<Int2>(static_cast<T>(i4)), i4);
6167
}
6268
}
6369

64-
TEST(Int2Test, Int2ToInt32ToInt2) { TestInt2ToXToInt2<int32_t>(); }
65-
TEST(Int2Test, Int2ToFloatToInt2) { TestInt2ToXToInt2<float>(); }
66-
TEST(Int2Test, Int2ToDoubleToInt2) { TestInt2ToXToInt2<double>(); }
70+
TEST(Int2Test, DefaultConstruction) {
71+
const Int2 zero(0);
72+
73+
// sd is static, so it must be zero initialized.
74+
static Int2 sd;
75+
EXPECT_EQ(sd, zero);
76+
77+
// z is zero initialized.
78+
Int2 z{};
79+
EXPECT_EQ(z, zero);
80+
81+
// v is value initialized to zero.
82+
Int2 v = Int2();
83+
EXPECT_EQ(v, zero);
84+
}
6785

6886
TEST(Int2Test, Arithmetic) {
6987
EXPECT_EQ(Int2(1) + Int2(1), Int2(-2));

0 commit comments

Comments
 (0)