/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include namespace apache::thrift::detail::test { template BitSet makeBitSet(T& storage) { if constexpr (std::is_reference_v) { return BitSet{storage}; } else { return {}; } } template struct IntTest : ::testing::Test {}; using Ints = ::testing:: Types, std::atomic&>; TYPED_TEST_SUITE(IntTest, Ints); TYPED_TEST(IntTest, Traits) { static_assert(std::is_copy_constructible_v>); static_assert(std::is_nothrow_move_constructible_v>); static_assert(std::is_trivially_destructible_v>); if constexpr (std::is_reference_v) { static_assert(std::is_trivially_copy_constructible_v>); static_assert(std::is_trivially_move_constructible_v>); } else { // In this case `BitSet` will be data member in thrift struct. We // need to make sure thrift struct is copy/move assignable. static_assert(std::is_copy_assignable_v>); static_assert(std::is_move_assignable_v>); } } TYPED_TEST(IntTest, Basic) { std::remove_reference_t storage{0}; auto b = makeBitSet(storage); for (int i = 0; i < 8; i++) { b[i] = i % 3; } EXPECT_FALSE(b[0]); EXPECT_TRUE(b[1]); EXPECT_TRUE(b[2]); EXPECT_FALSE(b[3]); EXPECT_TRUE(b[4]); EXPECT_TRUE(b[5]); EXPECT_FALSE(b[6]); EXPECT_TRUE(b[7]); } template struct AtomicIntTest : ::testing::Test {}; using AtomicInts = ::testing::Types, std::atomic&>; TYPED_TEST_SUITE(AtomicIntTest, AtomicInts); TYPED_TEST(AtomicIntTest, Basic) { std::remove_reference_t storage{0}; auto b = makeBitSet(storage); std::thread t[8]; for (int i = 0; i < 8; i++) { t[i] = std::thread([&b, i] { b[i] = i % 3; }); } for (auto& i : t) { i.join(); } EXPECT_FALSE(b[0]); EXPECT_TRUE(b[1]); EXPECT_TRUE(b[2]); EXPECT_FALSE(b[3]); EXPECT_TRUE(b[4]); EXPECT_TRUE(b[5]); EXPECT_FALSE(b[6]); EXPECT_TRUE(b[7]); } template struct BitRefTest : ::testing::Test {}; using BitRefs = ::testing::Types, BitRef>; TYPED_TEST_SUITE(BitRefTest, BitRefs); TYPED_TEST(BitRefTest, Traits) { EXPECT_TRUE(std::is_trivially_copy_constructible_v); EXPECT_TRUE(std::is_trivially_move_constructible_v); EXPECT_TRUE(std::is_trivially_destructible_v); } TYPED_TEST(BitRefTest, Get) { uint8_t storage = 0b1001001; for (int i = 0; i < 8; i++) { TypeParam b(storage, i); EXPECT_EQ(bool(b), i % 3 == 0); } } TYPED_TEST(BitRefTest, AtomicGet) { std::atomic storage{0b1001001}; for (int i = 0; i < 8; i++) { TypeParam b(storage, i); EXPECT_EQ(bool(b), i % 3 == 0); } } TEST(BitRefTest, Set) { uint8_t storage = 0; for (int i = 0; i < 8; i++) { BitRef b(storage, i); b = i % 3 == 0; } EXPECT_EQ(storage, 0b1001001); } TEST(BitRefTest, AtomicSet) { std::atomic storage{0}; std::thread a[8]; for (int i = 0; i < 8; i++) { a[i] = std::thread([&storage, i] { BitRef b(storage, i); b = i % 3 == 0; }); } for (auto&& t : a) { t.join(); } EXPECT_EQ(storage, 0b1001001); } } // namespace apache::thrift::detail::test