Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Side by Side Diff: sync/internal_api/public/util/immutable.h

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 // Immutable<T> provides an easy, cheap, and thread-safe way to pass
6 // large immutable data around.
7 //
8 // For example, consider the following code:
9 //
10 // typedef std::vector<LargeObject> LargeObjectList;
11 //
12 // void ProcessStuff(const LargeObjectList& stuff) {
13 // for (LargeObjectList::const_iterator it = stuff.begin();
14 // it != stuff.end(); ++it) {
15 // ... process it ...
16 // }
17 // }
18 //
19 // ...
20 //
21 // LargeObjectList my_stuff;
22 // ... fill my_stuff with lots of LargeObjects ...
23 // some_loop->PostTask(FROM_HERE, base::Bind(&ProcessStuff, my_stuff));
24 //
25 // The last line incurs the cost of copying my_stuff, which is
26 // undesirable. Here's the above code re-written using Immutable<T>:
27 //
28 // void ProcessStuff(const Immutable<LargeObjectList>& stuff) {
29 // for (LargeObjectList::const_iterator it = stuff.Get().begin();
30 // it != stuff.Get().end(); ++it) {
31 // ... process it ...
32 // }
33 // }
34 //
35 // ...
36 //
37 // LargeObjectList my_stuff;
38 // ... fill my_stuff with lots of LargeObjects ...
39 // some_loop->PostTask(
40 // FROM_HERE, base::Bind(&ProcessStuff, MakeImmutable(&my_stuff)));
41 //
42 // The last line, which resets my_stuff to a default-initialized
43 // state, incurs only the cost of a swap of LargeObjectLists, which is
44 // O(1) for most STL container implementations. The data in my_stuff
45 // is ref-counted (thread-safely), so it is freed as soon as
46 // ProcessStuff is finished.
47 //
48 // NOTE: By default, Immutable<T> relies on ADL
49 // (http://en.wikipedia.org/wiki/Argument-dependent_name_lookup) to
50 // find a swap() function for T, falling back to std::swap() when
51 // necessary. If you overload swap() for your type in its namespace,
52 // or if you specialize std::swap() for your type, (see
53 // http://stackoverflow.com/questions/11562/how-to-overload-stdswap
54 // for discussion) Immutable<T> should be able to find it.
55 //
56 // Alternatively, you could explicitly control which swap function is
57 // used by providing your own traits class or using one of the
58 // pre-defined ones below. See comments on traits below for details.
59 //
60 // NOTE: Some complexity is necessary in order to use Immutable<T>
61 // with forward-declared types. See comments on traits below for
62 // details.
63
64 #ifndef SYNC_INTERNAL_API_PUBLIC_UTIL_IMMUTABLE_H_
65 #define SYNC_INTERNAL_API_PUBLIC_UTIL_IMMUTABLE_H_
66
67 // For std::swap().
68 #include <algorithm>
69
70 #include "base/macros.h"
71 #include "base/memory/ref_counted.h"
72
73 namespace syncer {
74
75 namespace internal {
76 // This class is part of the Immutable implementation. DO NOT USE
77 // THIS CLASS DIRECTLY YOURSELF.
78
79 template <typename T, typename Traits>
80 class ImmutableCore
81 : public base::RefCountedThreadSafe<ImmutableCore<T, Traits> > {
82 public:
83 // wrapper_ is always explicitly default-initialized to handle
84 // primitive types and the case where Traits::Wrapper == T.
85
86 ImmutableCore() : wrapper_() {
87 Traits::InitializeWrapper(&wrapper_);
88 }
89
90 explicit ImmutableCore(T* t) : wrapper_() {
91 Traits::InitializeWrapper(&wrapper_);
92 Traits::Swap(Traits::UnwrapMutable(&wrapper_), t);
93 }
94
95 const T& Get() const {
96 return Traits::Unwrap(wrapper_);
97 }
98
99 private:
100 friend class base::RefCountedThreadSafe<ImmutableCore<T, Traits>>;
101
102 ~ImmutableCore() {
103 Traits::DestroyWrapper(&wrapper_);
104 }
105
106 // This is semantically const, but we can't mark it a such as we
107 // modify it in the constructor.
108 typename Traits::Wrapper wrapper_;
109
110 DISALLOW_COPY_AND_ASSIGN(ImmutableCore);
111 };
112
113 } // namespace internal
114
115 // Traits usage notes
116 // ------------------
117 // The most common reason to use your own traits class is to provide
118 // your own swap method. First, consider the pre-defined traits
119 // classes HasSwapMemFn{ByRef,ByPtr} below. If neither of those work,
120 // then define your own traits class inheriting from
121 // DefaultImmutableTraits<YourType> (to pick up the defaults for
122 // everything else) and provide your own Swap() method.
123 //
124 // Another reason to use your own traits class is to be able to use
125 // Immutable<T> with a forward-declared type (important for protobuf
126 // classes, when you want to avoid headers pulling in generated
127 // headers). (This is why the Traits::Wrapper type exists; normally,
128 // Traits::Wrapper is just T itself, but that needs to be changed for
129 // forward-declared types.)
130 //
131 // For example, if you want to do this:
132 //
133 // my_class.h
134 // ----------
135 // #include ".../immutable.h"
136 //
137 // // Forward declaration.
138 // class SomeOtherType;
139 //
140 // class MyClass {
141 // ...
142 // private:
143 // // Doesn't work, as defaults traits class needs SomeOtherType's
144 // // definition to be visible.
145 // Immutable<SomeOtherType> foo_;
146 // };
147 //
148 // You'll have to do this:
149 //
150 // my_class.h
151 // ----------
152 // #include ".../immutable.h"
153 //
154 // // Forward declaration.
155 // class SomeOtherType;
156 //
157 // class MyClass {
158 // ...
159 // private:
160 // struct ImmutableSomeOtherTypeTraits {
161 // // std::unique_ptr<SomeOtherType> won't work here, either.
162 // typedef SomeOtherType* Wrapper;
163 //
164 // static void InitializeWrapper(Wrapper* wrapper);
165 //
166 // static void DestroyWrapper(Wrapper* wrapper);
167 // ...
168 // };
169 //
170 // typedef Immutable<SomeOtherType, ImmutableSomeOtherTypeTraits>
171 // ImmutableSomeOtherType;
172 //
173 // ImmutableSomeOtherType foo_;
174 // };
175 //
176 // my_class.cc
177 // -----------
178 // #include ".../some_other_type.h"
179 //
180 // void MyClass::ImmutableSomeOtherTypeTraits::InitializeWrapper(
181 // Wrapper* wrapper) {
182 // *wrapper = new SomeOtherType();
183 // }
184 //
185 // void MyClass::ImmutableSomeOtherTypeTraits::DestroyWrapper(
186 // Wrapper* wrapper) {
187 // delete *wrapper;
188 // }
189 //
190 // ...
191 //
192 // Also note that this incurs an additional memory allocation when you
193 // create an Immutable<SomeOtherType>.
194
195 template <typename T>
196 struct DefaultImmutableTraits {
197 typedef T Wrapper;
198
199 static void InitializeWrapper(Wrapper* wrapper) {}
200
201 static void DestroyWrapper(Wrapper* wrapper) {}
202
203 static const T& Unwrap(const Wrapper& wrapper) { return wrapper; }
204
205 static T* UnwrapMutable(Wrapper* wrapper) { return wrapper; }
206
207 static void Swap(T* t1, T* t2) {
208 // Uses ADL (see
209 // http://en.wikipedia.org/wiki/Argument-dependent_name_lookup).
210 using std::swap;
211 swap(*t1, *t2);
212 }
213 };
214
215 // Most STL containers have by-reference swap() member functions,
216 // although they usually already overload std::swap() to use those.
217 template <typename T>
218 struct HasSwapMemFnByRef : public DefaultImmutableTraits<T> {
219 static void Swap(T* t1, T* t2) {
220 t1->swap(*t2);
221 }
222 };
223
224 // Most Google-style objects have by-pointer Swap() member functions
225 // (for example, generated protocol buffer classes).
226 template <typename T>
227 struct HasSwapMemFnByPtr : public DefaultImmutableTraits<T> {
228 static void Swap(T* t1, T* t2) {
229 t1->Swap(t2);
230 }
231 };
232
233 template <typename T, typename Traits = DefaultImmutableTraits<T> >
234 class Immutable {
235 public:
236 // Puts the underlying object in a default-initialized state.
237 Immutable() : core_(new internal::ImmutableCore<T, Traits>()) {}
238
239 // Copy constructor and assignment welcome.
240
241 // Resets |t| to a default-initialized state.
242 explicit Immutable(T* t)
243 : core_(new internal::ImmutableCore<T, Traits>(t)) {}
244
245 const T& Get() const {
246 return core_->Get();
247 }
248
249 private:
250 scoped_refptr<const internal::ImmutableCore<T, Traits> > core_;
251 };
252
253 // Helper function to avoid having to write out template arguments.
254 template <typename T>
255 Immutable<T> MakeImmutable(T* t) {
256 return Immutable<T>(t);
257 }
258
259 } // namespace syncer
260
261 #endif // SYNC_INTERNAL_API_PUBLIC_UTIL_IMMUTABLE_H_
OLDNEW
« no previous file with comments | « sync/internal_api/public/util/experiments.h ('k') | sync/internal_api/public/util/immutable_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698