• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_UTIL_IMMUTABLE_H_
65 #define SYNC_UTIL_IMMUTABLE_H_
66 
67 // For std::swap().
68 #include <algorithm>
69 
70 #include "base/basictypes.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 
ImmutableCore()86   ImmutableCore() : wrapper_() {
87     Traits::InitializeWrapper(&wrapper_);
88   }
89 
ImmutableCore(T * t)90   explicit ImmutableCore(T* t) : wrapper_() {
91     Traits::InitializeWrapper(&wrapper_);
92     Traits::Swap(Traits::UnwrapMutable(&wrapper_), t);
93   }
94 
Get()95   const T& Get() const {
96     return Traits::Unwrap(wrapper_);
97   }
98 
99  private:
~ImmutableCore()100   ~ImmutableCore() {
101     Traits::DestroyWrapper(&wrapper_);
102   }
103   friend class base::RefCountedThreadSafe<ImmutableCore<T, Traits> >;
104 
105   // This is semantically const, but we can't mark it a such as we
106   // modify it in the constructor.
107   typename Traits::Wrapper wrapper_;
108 
109   DISALLOW_COPY_AND_ASSIGN(ImmutableCore);
110 };
111 
112 }  // namespace internal
113 
114 // Traits usage notes
115 // ------------------
116 // The most common reason to use your own traits class is to provide
117 // your own swap method.  First, consider the pre-defined traits
118 // classes HasSwapMemFn{ByRef,ByPtr} below.  If neither of those work,
119 // then define your own traits class inheriting from
120 // DefaultImmutableTraits<YourType> (to pick up the defaults for
121 // everything else) and provide your own Swap() method.
122 //
123 // Another reason to use your own traits class is to be able to use
124 // Immutable<T> with a forward-declared type (important for protobuf
125 // classes, when you want to avoid headers pulling in generated
126 // headers).  (This is why the Traits::Wrapper type exists; normally,
127 // Traits::Wrapper is just T itself, but that needs to be changed for
128 // forward-declared types.)
129 //
130 // For example, if you want to do this:
131 //
132 //   my_class.h
133 //   ----------
134 //   #include ".../immutable.h"
135 //
136 //   // Forward declaration.
137 //   class SomeOtherType;
138 //
139 //   class MyClass {
140 //     ...
141 //    private:
142 //     // Doesn't work, as defaults traits class needs SomeOtherType's
143 //     // definition to be visible.
144 //     Immutable<SomeOtherType> foo_;
145 //   };
146 //
147 // You'll have to do this:
148 //
149 //   my_class.h
150 //   ----------
151 //   #include ".../immutable.h"
152 //
153 //   // Forward declaration.
154 //   class SomeOtherType;
155 //
156 //   class MyClass {
157 //     ...
158 //    private:
159 //     struct ImmutableSomeOtherTypeTraits {
160 //       // scoped_ptr<SomeOtherType> won't work here, either.
161 //       typedef SomeOtherType* Wrapper;
162 //
163 //       static void InitializeWrapper(Wrapper* wrapper);
164 //
165 //       static void DestroyWrapper(Wrapper* wrapper);
166 //       ...
167 //     };
168 //
169 //     typedef Immutable<SomeOtherType, ImmutableSomeOtherTypeTraits>
170 //         ImmutableSomeOtherType;
171 //
172 //     ImmutableSomeOtherType foo_;
173 //   };
174 //
175 //   my_class.cc
176 //   -----------
177 //   #include ".../some_other_type.h"
178 //
179 //   void MyClass::ImmutableSomeOtherTypeTraits::InitializeWrapper(
180 //       Wrapper* wrapper) {
181 //     *wrapper = new SomeOtherType();
182 //   }
183 //
184 //   void MyClass::ImmutableSomeOtherTypeTraits::DestroyWrapper(
185 //       Wrapper* wrapper) {
186 //     delete *wrapper;
187 //   }
188 //
189 //   ...
190 //
191 // Also note that this incurs an additional memory allocation when you
192 // create an Immutable<SomeOtherType>.
193 
194 template <typename T>
195 struct DefaultImmutableTraits {
196   typedef T Wrapper;
197 
InitializeWrapperDefaultImmutableTraits198   static void InitializeWrapper(Wrapper* wrapper) {}
199 
DestroyWrapperDefaultImmutableTraits200   static void DestroyWrapper(Wrapper* wrapper) {}
201 
UnwrapDefaultImmutableTraits202   static const T& Unwrap(const Wrapper& wrapper) { return wrapper; }
203 
UnwrapMutableDefaultImmutableTraits204   static T* UnwrapMutable(Wrapper* wrapper) { return wrapper; }
205 
SwapDefaultImmutableTraits206   static void Swap(T* t1, T* t2) {
207     // Uses ADL (see
208     // http://en.wikipedia.org/wiki/Argument-dependent_name_lookup).
209     using std::swap;
210     swap(*t1, *t2);
211   }
212 };
213 
214 // Most STL containers have by-reference swap() member functions,
215 // although they usually already overload std::swap() to use those.
216 template <typename T>
217 struct HasSwapMemFnByRef : public DefaultImmutableTraits<T> {
SwapHasSwapMemFnByRef218   static void Swap(T* t1, T* t2) {
219     t1->swap(*t2);
220   }
221 };
222 
223 // Most Google-style objects have by-pointer Swap() member functions
224 // (for example, generated protocol buffer classes).
225 template <typename T>
226 struct HasSwapMemFnByPtr : public DefaultImmutableTraits<T> {
SwapHasSwapMemFnByPtr227   static void Swap(T* t1, T* t2) {
228     t1->Swap(t2);
229   }
230 };
231 
232 template <typename T, typename Traits = DefaultImmutableTraits<T> >
233 class Immutable {
234  public:
235   // Puts the underlying object in a default-initialized state.
Immutable()236   Immutable() : core_(new internal::ImmutableCore<T, Traits>()) {}
237 
238   // Copy constructor and assignment welcome.
239 
240   // Resets |t| to a default-initialized state.
Immutable(T * t)241   explicit Immutable(T* t)
242       : core_(new internal::ImmutableCore<T, Traits>(t)) {}
243 
Get()244   const T& Get() const {
245     return core_->Get();
246   }
247 
248  private:
249   scoped_refptr<const internal::ImmutableCore<T, Traits> > core_;
250 };
251 
252 // Helper function to avoid having to write out template arguments.
253 template <typename T>
MakeImmutable(T * t)254 Immutable<T> MakeImmutable(T* t) {
255   return Immutable<T>(t);
256 }
257 
258 }  // namespace syncer
259 
260 #endif  // SYNC_UTIL_IMMUTABLE_H_
261