/* * 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 #include namespace apache::thrift::test { std::mt19937 rng; template Type makeStructExtra() { auto obj = Type(); obj.extraInt32Def_ref() = 4000; obj.extraInt32Req_ref() = 5000; obj.extraInt32Opt_ref() = 6000; return obj; } template Type makeStructBasic() { auto obj = Type(); obj.int32Req_ref() = 2000; obj.int32Opt_ref() = 3000; obj.stringReq_ref() = "required"; obj.stringOpt_ref() = "optional"; obj.setReq_ref() = std::set{1, 2, 3}; obj.setOpt_ref() = std::set{4, 5, 6}; obj.listReq_ref() = {111, 222}; obj.listOpt_ref() = {333, 444}; obj.structOpt_ref() = makeStructExtra(); obj.structPackedOpt_ref() = makeStructExtra(); obj.structAtomicPackedOpt_ref() = makeStructExtra(); return obj; } template void randomTestWithSeed(int seed) { rng.seed(seed); auto obj1 = makeStructBasic(); auto obj2 = makeStructBasic(); std::vector> methods = { [&] { obj1.int32Req() = 2; obj2.int32Req_ref() = 2; EXPECT_EQ(obj1.int32Req(), obj2.int32Req_ref()); }, [&] { obj1.int32Opt() = 3; obj2.int32Opt_ref() = 3; EXPECT_EQ(obj1.int32Opt(), obj2.int32Opt_ref()); }, [&] { obj1.int32Opt().reset(); obj2.int32Opt_ref().reset(); EXPECT_EQ(obj1.int32Opt(), obj2.int32Opt_ref()); }, [&] { obj1.stringReq() = "a"; obj2.stringReq_ref() = "a"; EXPECT_EQ(obj1.stringReq(), obj2.stringReq_ref()); }, [&] { obj1.stringOpt() = "b"; obj2.stringOpt_ref() = "b"; EXPECT_EQ(obj1.stringOpt(), obj2.stringOpt_ref()); }, [&] { obj1.stringOpt().reset(); obj2.stringOpt_ref().reset(); EXPECT_EQ(obj1.stringOpt(), obj2.stringOpt_ref()); }, [&] { obj1.setReq() = {7, 8, 9}; obj2.setReq_ref() = {7, 8, 9}; EXPECT_EQ(obj1.setReq(), obj2.setReq_ref()); }, [&] { obj1.setOpt() = {7, 8, 9}; obj2.setOpt_ref() = {7, 8, 9}; EXPECT_EQ(obj1.setOpt(), obj2.setOpt_ref()); }, [&] { obj1.setOpt().reset(); obj2.setOpt_ref().reset(); EXPECT_EQ(obj1.setOpt(), obj2.setOpt_ref()); }, [&] { obj1.listReq() = {555}; obj2.listReq_ref() = {555}; EXPECT_EQ(obj1.listReq(), obj2.listReq_ref()); }, [&] { obj1.structOpt()->extraInt32Def() = 10; obj2.structOpt_ref()->extraInt32Def_ref() = 10; EXPECT_EQ(obj1.structOpt(), obj2.structOpt_ref()); }, [&] { obj1.structOpt()->extraInt32Req() = 20; obj2.structOpt_ref()->extraInt32Req_ref() = 20; EXPECT_EQ(obj1.structOpt(), obj2.structOpt_ref()); }, [&] { obj1.structOpt()->extraInt32Opt() = 30; obj2.structOpt_ref()->extraInt32Opt_ref() = 30; EXPECT_EQ(obj1.structOpt(), obj2.structOpt_ref()); }, [&] { obj1.structOpt()->extraInt32Opt().reset(); obj2.structOpt_ref()->extraInt32Opt_ref().reset(); EXPECT_EQ(obj1.structOpt(), obj2.structOpt_ref()); }, [&] { obj1.structPackedOpt()->extraInt32Def() = 40; obj2.structPackedOpt_ref()->extraInt32Def_ref() = 40; EXPECT_EQ(obj1.structPackedOpt(), obj2.structPackedOpt_ref()); }, [&] { obj1.structPackedOpt()->extraInt32Req() = 50; obj2.structPackedOpt_ref()->extraInt32Req_ref() = 50; EXPECT_EQ(obj1.structPackedOpt(), obj2.structPackedOpt_ref()); }, [&] { obj1.structPackedOpt()->extraInt32Opt() = 60; obj2.structPackedOpt_ref()->extraInt32Opt_ref() = 60; EXPECT_EQ(obj1.structPackedOpt(), obj2.structPackedOpt_ref()); }, [&] { obj1.structPackedOpt()->extraInt32Opt().reset(); obj2.structPackedOpt_ref()->extraInt32Opt_ref().reset(); EXPECT_EQ(obj1.structPackedOpt(), obj2.structPackedOpt_ref()); }, [&] { obj1.structAtomicPackedOpt()->extraInt32Def() = 40; obj2.structAtomicPackedOpt_ref()->extraInt32Def_ref() = 40; EXPECT_EQ( obj1.structAtomicPackedOpt(), obj2.structAtomicPackedOpt_ref()); }, [&] { obj1.structAtomicPackedOpt()->extraInt32Req() = 50; obj2.structAtomicPackedOpt_ref()->extraInt32Req_ref() = 50; EXPECT_EQ( obj1.structAtomicPackedOpt(), obj2.structAtomicPackedOpt_ref()); }, [&] { obj1.structAtomicPackedOpt()->extraInt32Opt() = 60; obj2.structAtomicPackedOpt_ref()->extraInt32Opt_ref() = 60; EXPECT_EQ( obj1.structAtomicPackedOpt(), obj2.structAtomicPackedOpt_ref()); }, [&] { obj1.structAtomicPackedOpt()->extraInt32Opt().reset(); obj2.structAtomicPackedOpt_ref()->extraInt32Opt_ref().reset(); EXPECT_EQ( obj1.structAtomicPackedOpt(), obj2.structAtomicPackedOpt_ref()); }, }; methods[rng() % methods.size()](); } TEST(BitPackTest, compare_size) { cpp2::A obj1; cpp2::A_bitpack obj2; cpp2::A_atomic_bitpack obj3; // size comparasion: 16 vs 9 -> 44% memory decreased after bitpacking static_assert(sizeof(cpp2::A) == 16); static_assert(sizeof(cpp2::A_bitpack) == 9); static_assert(sizeof(cpp2::A_atomic_bitpack) == 9); } template struct BitpacksTest : public ::testing::Test {}; using Types = ::testing::Types; TYPED_TEST_SUITE(BitpacksTest, Types); TYPED_TEST(BitpacksTest, compare_basic) { auto obj1 = makeStructBasic(); auto obj2 = makeStructBasic(); EXPECT_EQ(obj1.int32Req(), obj2.int32Req_ref()); EXPECT_EQ(obj1.int32Opt(), obj2.int32Opt_ref()); EXPECT_EQ(obj1.stringReq(), obj2.stringReq_ref()); EXPECT_EQ(obj1.stringOpt(), obj2.stringOpt_ref()); EXPECT_EQ(obj1.setReq(), obj2.setReq_ref()); EXPECT_EQ(obj1.setOpt(), obj2.setOpt_ref()); EXPECT_EQ(obj1.listReq(), obj2.listReq_ref()); EXPECT_EQ(obj1.listOpt(), obj2.listOpt_ref()); EXPECT_EQ(obj1.structOpt(), obj2.structOpt_ref()); EXPECT_EQ(obj1.structPackedOpt(), obj2.structPackedOpt_ref()); } class RandomTestWithSeed : public testing::TestWithParam {}; TEST_P(RandomTestWithSeed, test) { randomTestWithSeed(GetParam()); randomTestWithSeed(GetParam()); } INSTANTIATE_TEST_CASE_P( RandomTest, RandomTestWithSeed, testing::Range(0, folly::kIsDebug ? 100 : 10000)); TEST(AtomicBitpack, multithread) { cpp2::AtomicBitpack obj; std::vector v; v.emplace_back([&] { obj.int32Opt().emplace(); }); v.emplace_back([&] { obj.stringOpt().emplace(); }); v.emplace_back([&] { obj.setOpt().emplace(); }); v.emplace_back([&] { obj.listOpt().emplace(); }); v.emplace_back([&] { obj.structOpt().emplace(); }); v.emplace_back([&] { obj.structPackedOpt().emplace(); }); v.emplace_back([&] { obj.structAtomicPackedOpt().emplace(); }); for (auto&& t : v) { t.join(); } apache::thrift::for_each_field( obj, [](auto&&, auto&& ref) { EXPECT_TRUE(ref.has_value()); }); } } // namespace apache::thrift::test