1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sync/internal_api/public/util/immutable.h"
15 #include "base/basictypes.h"
16 #include "base/memory/ref_counted.h"
17 #include "testing/gtest/include/gtest/gtest.h"
21 // Helper class that keeps track of the token passed in at
22 // construction and how many times that token is copied.
23 class TokenCore
: public base::RefCounted
<TokenCore
> {
25 explicit TokenCore(const char* token
) : token_(token
), copy_count_(0) {}
27 const char* GetToken() const { return token_
; }
29 void RecordCopy() { ++copy_count_
; }
31 int GetCopyCount() const { return copy_count_
; }
34 friend class base::RefCounted
<TokenCore
>;
38 const char* const token_
;
44 USE_FAST_SWAP_VIA_ADL
,
45 USE_FAST_SWAP_VIA_SPECIALIZATION
48 const char kEmptyToken
[] = "<empty token>";
50 // Base class for various token classes, differing in swap behavior.
51 template <SwapBehavior
>
54 TokenBase() : core_(new TokenCore(kEmptyToken
)) {}
56 explicit TokenBase(const char* token
) : core_(new TokenCore(token
)) {}
58 TokenBase(const TokenBase
& other
) : core_(other
.core_
) {
62 TokenBase
& operator=(const TokenBase
& other
) {
68 const char* GetToken() const {
69 return core_
->GetToken();
72 int GetCopyCount() const {
73 return core_
->GetCopyCount();
76 // For associative containers.
77 bool operator<(const TokenBase
& other
) const {
78 return std::string(GetToken()) < std::string(other
.GetToken());
82 void swap(TokenBase
& other
) {
84 swap(other
.core_
, core_
);
88 void Swap(TokenBase
* other
) {
90 swap(other
->core_
, core_
);
94 scoped_refptr
<TokenCore
> core_
;
97 typedef TokenBase
<USE_DEFAULT_SWAP
> Token
;
98 typedef TokenBase
<USE_FAST_SWAP_VIA_ADL
> ADLToken
;
99 typedef TokenBase
<USE_FAST_SWAP_VIA_SPECIALIZATION
> SpecializationToken
;
101 void swap(ADLToken
& t1
, ADLToken
& t2
) {
105 } // namespace syncer
107 // Allowed by the standard (17.4.3.1/1).
111 void swap(syncer::SpecializationToken
& t1
,
112 syncer::SpecializationToken
& t2
) {
121 class ImmutableTest
: public ::testing::Test
{};
123 TEST_F(ImmutableTest
, Int
) {
125 Immutable
<int> ix(&x
);
126 EXPECT_EQ(5, ix
.Get());
130 TEST_F(ImmutableTest
, IntCopy
) {
132 Immutable
<int> ix
= Immutable
<int>(&x
);
133 EXPECT_EQ(5, ix
.Get());
137 TEST_F(ImmutableTest
, IntAssign
) {
140 EXPECT_EQ(0, ix
.Get());
141 ix
= Immutable
<int>(&x
);
142 EXPECT_EQ(5, ix
.Get());
146 TEST_F(ImmutableTest
, IntMakeImmutable
) {
148 Immutable
<int> ix
= MakeImmutable(&x
);
149 EXPECT_EQ(5, ix
.Get());
153 template <typename T
, typename ImmutableT
>
154 void RunTokenTest(const char* token
, bool expect_copies
) {
157 EXPECT_EQ(token
, t
.GetToken());
158 EXPECT_EQ(0, t
.GetCopyCount());
160 ImmutableT
immutable_t(&t
);
161 EXPECT_EQ(token
, immutable_t
.Get().GetToken());
162 EXPECT_EQ(kEmptyToken
, t
.GetToken());
163 EXPECT_EQ(expect_copies
, immutable_t
.Get().GetCopyCount() > 0);
164 EXPECT_EQ(expect_copies
, t
.GetCopyCount() > 0);
167 TEST_F(ImmutableTest
, Token
) {
168 RunTokenTest
<Token
, Immutable
<Token
> >("Token", true /* expect_copies */);
171 TEST_F(ImmutableTest
, TokenSwapMemFnByRef
) {
172 RunTokenTest
<Token
, Immutable
<Token
, HasSwapMemFnByRef
<Token
> > >(
173 "TokenSwapMemFnByRef", false /* expect_copies */);
176 TEST_F(ImmutableTest
, TokenSwapMemFnByPtr
) {
177 RunTokenTest
<Token
, Immutable
<Token
, HasSwapMemFnByPtr
<Token
> > >(
178 "TokenSwapMemFnByPtr", false /* expect_copies */);
181 TEST_F(ImmutableTest
, ADLToken
) {
182 RunTokenTest
<ADLToken
, Immutable
<ADLToken
> >(
183 "ADLToken", false /* expect_copies */);
186 TEST_F(ImmutableTest
, SpecializationToken
) {
187 RunTokenTest
<SpecializationToken
, Immutable
<SpecializationToken
> >(
188 "SpecializationToken", false /* expect_copies */);
191 template <typename C
, typename ImmutableC
>
192 void RunTokenContainerTest(const char* token
) {
194 const Token tokens
[] = { Token(), Token(token
) };
195 const size_t token_count
= arraysize(tokens
);
196 C
c(tokens
, tokens
+ token_count
);
197 const int copy_count
= c
.begin()->GetCopyCount();
198 EXPECT_GT(copy_count
, 0);
199 for (typename
C::const_iterator it
= c
.begin(); it
!= c
.end(); ++it
) {
200 EXPECT_EQ(copy_count
, it
->GetCopyCount());
203 // Make sure that making the container immutable doesn't incur any
204 // copies of the tokens.
205 ImmutableC
immutable_c(&c
);
206 EXPECT_TRUE(c
.empty());
207 ASSERT_EQ(token_count
, immutable_c
.Get().size());
209 for (typename
C::const_iterator it
= c
.begin(); it
!= c
.end(); ++it
) {
210 EXPECT_EQ(tokens
[i
].GetToken(), it
->GetToken());
211 EXPECT_EQ(copy_count
, it
->GetCopyCount());
216 TEST_F(ImmutableTest
, Vector
) {
217 RunTokenContainerTest
<std::vector
<Token
>, Immutable
<std::vector
<Token
> > >(
221 TEST_F(ImmutableTest
, VectorSwapMemFnByRef
) {
222 RunTokenContainerTest
<
224 Immutable
<std::vector
<Token
>, HasSwapMemFnByRef
<std::vector
<Token
> > > >(
225 "VectorSwapMemFnByRef");
228 TEST_F(ImmutableTest
, Deque
) {
229 RunTokenContainerTest
<std::deque
<Token
>, Immutable
<std::deque
<Token
> > >(
233 TEST_F(ImmutableTest
, List
) {
234 RunTokenContainerTest
<std::list
<Token
>, Immutable
<std::list
<Token
> > >(
238 TEST_F(ImmutableTest
, Set
) {
239 RunTokenContainerTest
<std::set
<Token
>, Immutable
<std::set
<Token
> > >(
244 } // namespace syncer