2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <folly/CachelinePadded.h>
19 #include <type_traits>
21 #include <folly/portability/GTest.h>
23 using folly::CachelinePadded;
26 std::is_standard_layout<CachelinePadded<int>>::value,
27 "CachelinePadded<T> must be standard-layout if T is.");
29 const int kCachelineSize = folly::detail::CacheLocality::kFalseSharingRange;
31 template <int dataSize>
34 for (unsigned i = 0; i < dataSize; ++i) {
39 void doModifications() {
40 for (unsigned i = 0; i < dataSize; ++i) {
41 EXPECT_EQ(static_cast<unsigned char>(i), data[i]);
47 for (unsigned i = 0; i < dataSize; ++i) {
48 EXPECT_EQ(static_cast<unsigned char>(i + 1), data[i]);
52 unsigned char data[dataSize];
55 using ExactlyCachelineSized = SizedData<kCachelineSize>;
56 using DoubleCachelineSized = SizedData<2 * kCachelineSize>;
57 using BelowCachelineSized = SizedData<kCachelineSize / 2>;
58 using AboveCachelineSized = SizedData<kCachelineSize + kCachelineSize / 2>;
60 TEST(CachelinePadded, Exact) {
61 EXPECT_EQ(kCachelineSize, sizeof(CachelinePadded<ExactlyCachelineSized>));
62 CachelinePadded<ExactlyCachelineSized> item;
63 item.get()->doModifications();
65 reinterpret_cast<CachelinePadded<ExactlyCachelineSized>*>(item.get()) ==
69 TEST(CachelinePadded, Double) {
70 EXPECT_EQ(2 * kCachelineSize, sizeof(CachelinePadded<DoubleCachelineSized>));
71 CachelinePadded<DoubleCachelineSized> item;
72 item.get()->doModifications();
74 reinterpret_cast<CachelinePadded<DoubleCachelineSized>*>(item.get()) ==
78 TEST(CachelinePadded, Below) {
79 EXPECT_EQ(kCachelineSize, sizeof(CachelinePadded<BelowCachelineSized>));
80 CachelinePadded<BelowCachelineSized> item;
81 item.get()->doModifications();
83 reinterpret_cast<CachelinePadded<BelowCachelineSized>*>(item.get()) ==
87 TEST(CachelinePadded, Above) {
88 EXPECT_EQ(2 * kCachelineSize, sizeof(CachelinePadded<AboveCachelineSized>));
89 CachelinePadded<AboveCachelineSized> item;
90 item.get()->doModifications();
92 reinterpret_cast<CachelinePadded<AboveCachelineSized>*>(item.get()) ==
96 TEST(CachelinePadded, CanBeCastedBack) {
97 CachelinePadded<int> padded;
98 CachelinePadded<int>* ptr =
99 reinterpret_cast<CachelinePadded<int>*>(padded.get());
100 EXPECT_EQ(&padded, ptr);
103 TEST(CachelinePadded, PtrOperator) {
104 CachelinePadded<int> padded;
105 EXPECT_TRUE(padded.get() == padded.operator->());
106 EXPECT_TRUE(&*padded == padded.get());
107 const CachelinePadded<int> constPadded;
108 EXPECT_TRUE(constPadded.get() == constPadded.operator->());
109 EXPECT_TRUE(constPadded.get() == &*constPadded.get());
112 TEST(CachelinePadded, PropagatesConstness) {
113 struct OverloadedOnConst {
114 void assign(int* dst) {
117 void assign(int* dst) const {
122 CachelinePadded<OverloadedOnConst> padded;
128 const CachelinePadded<OverloadedOnConst> constPadded;
129 constPadded->assign(&i);
130 EXPECT_EQ(271828, i);
133 TEST(CachelinePadded, ConstructsAndDestructs) {
134 enum LifetimeStatus {
139 struct WriteOnLifetimeOp {
140 explicit WriteOnLifetimeOp(LifetimeStatus* dst) : dst_(dst) {
143 ~WriteOnLifetimeOp() {
146 LifetimeStatus* dst_;
148 LifetimeStatus status = kNone;
149 CachelinePadded<WriteOnLifetimeOp>* ptr =
150 new CachelinePadded<WriteOnLifetimeOp>(&status);
151 EXPECT_EQ(kConstructed, status);
153 EXPECT_EQ(kDestroyed, status);
156 TEST(CachelinePadded, ConstructsAndDestructsArrays) {
157 static thread_local int numConstructions;
158 static thread_local int numDestructions;
159 numConstructions = 0;
161 struct LifetimeCountingClass {
162 LifetimeCountingClass() {
165 ~LifetimeCountingClass() {
169 const static int kNumItems = 123;
170 CachelinePadded<LifetimeCountingClass>* ptr =
171 new CachelinePadded<LifetimeCountingClass>[kNumItems];
172 EXPECT_EQ(kNumItems, numConstructions);
174 EXPECT_EQ(kNumItems, numDestructions);
177 TEST(CachelinePadded, ForwardsCorrectly) {
178 struct RvalueOverloadedConstructor {
179 RvalueOverloadedConstructor(int* dst, int& /* ignored */) {
182 RvalueOverloadedConstructor(int* dst, int&& /* ignored */) {
186 int shouldBeZero = 12345;
187 int shouldBeOne = 67890;
190 CachelinePadded<RvalueOverloadedConstructor> padded1(
191 &shouldBeZero, ignored);
192 CachelinePadded<RvalueOverloadedConstructor> padded2(
193 &shouldBeOne, static_cast<int&&>(ignored));
195 EXPECT_EQ(0, shouldBeZero);
196 EXPECT_EQ(1, shouldBeOne);