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 // Immutable<T> provides an easy, cheap, and thread-safe way to pass
6 // large immutable data around.
8 // For example, consider the following code:
10 // typedef std::vector<LargeObject> LargeObjectList;
12 // void ProcessStuff(const LargeObjectList& stuff) {
13 // for (LargeObjectList::const_iterator it = stuff.begin();
14 // it != stuff.end(); ++it) {
21 // LargeObjectList my_stuff;
22 // ... fill my_stuff with lots of LargeObjects ...
23 // some_loop->PostTask(FROM_HERE, base::Bind(&ProcessStuff, my_stuff));
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>:
28 // void ProcessStuff(const Immutable<LargeObjectList>& stuff) {
29 // for (LargeObjectList::const_iterator it = stuff.Get().begin();
30 // it != stuff.Get().end(); ++it) {
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)));
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.
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.
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.
60 // NOTE: Some complexity is necessary in order to use Immutable<T>
61 // with forward-declared types. See comments on traits below for
64 #ifndef SYNC_UTIL_IMMUTABLE_H_
65 #define SYNC_UTIL_IMMUTABLE_H_
70 #include "base/basictypes.h"
71 #include "base/memory/ref_counted.h"
76 // This class is part of the Immutable implementation. DO NOT USE
77 // THIS CLASS DIRECTLY YOURSELF.
79 template <typename T
, typename Traits
>
81 : public base::RefCountedThreadSafe
<ImmutableCore
<T
, Traits
> > {
83 // wrapper_ is always explicitly default-initialized to handle
84 // primitive types and the case where Traits::Wrapper == T.
86 ImmutableCore() : wrapper_() {
87 Traits::InitializeWrapper(&wrapper_
);
90 explicit ImmutableCore(T
* t
) : wrapper_() {
91 Traits::InitializeWrapper(&wrapper_
);
92 Traits::Swap(Traits::UnwrapMutable(&wrapper_
), t
);
95 const T
& Get() const {
96 return Traits::Unwrap(wrapper_
);
101 Traits::DestroyWrapper(&wrapper_
);
103 friend class base::RefCountedThreadSafe
<ImmutableCore
<T
, Traits
> >;
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_
;
109 DISALLOW_COPY_AND_ASSIGN(ImmutableCore
);
112 } // namespace internal
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.
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.)
130 // For example, if you want to do this:
134 // #include ".../immutable.h"
136 // // Forward declaration.
137 // class SomeOtherType;
142 // // Doesn't work, as defaults traits class needs SomeOtherType's
143 // // definition to be visible.
144 // Immutable<SomeOtherType> foo_;
147 // You'll have to do this:
151 // #include ".../immutable.h"
153 // // Forward declaration.
154 // class SomeOtherType;
159 // struct ImmutableSomeOtherTypeTraits {
160 // // scoped_ptr<SomeOtherType> won't work here, either.
161 // typedef SomeOtherType* Wrapper;
163 // static void InitializeWrapper(Wrapper* wrapper);
165 // static void DestroyWrapper(Wrapper* wrapper);
169 // typedef Immutable<SomeOtherType, ImmutableSomeOtherTypeTraits>
170 // ImmutableSomeOtherType;
172 // ImmutableSomeOtherType foo_;
177 // #include ".../some_other_type.h"
179 // void MyClass::ImmutableSomeOtherTypeTraits::InitializeWrapper(
180 // Wrapper* wrapper) {
181 // *wrapper = new SomeOtherType();
184 // void MyClass::ImmutableSomeOtherTypeTraits::DestroyWrapper(
185 // Wrapper* wrapper) {
191 // Also note that this incurs an additional memory allocation when you
192 // create an Immutable<SomeOtherType>.
194 template <typename T
>
195 struct DefaultImmutableTraits
{
198 static void InitializeWrapper(Wrapper
* wrapper
) {}
200 static void DestroyWrapper(Wrapper
* wrapper
) {}
202 static const T
& Unwrap(const Wrapper
& wrapper
) { return wrapper
; }
204 static T
* UnwrapMutable(Wrapper
* wrapper
) { return wrapper
; }
206 static void Swap(T
* t1
, T
* t2
) {
208 // http://en.wikipedia.org/wiki/Argument-dependent_name_lookup).
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
> {
218 static void Swap(T
* t1
, T
* t2
) {
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
> {
227 static void Swap(T
* t1
, T
* t2
) {
232 template <typename T
, typename Traits
= DefaultImmutableTraits
<T
> >
235 // Puts the underlying object in a default-initialized state.
236 Immutable() : core_(new internal::ImmutableCore
<T
, Traits
>()) {}
238 // Copy constructor and assignment welcome.
240 // Resets |t| to a default-initialized state.
241 explicit Immutable(T
* t
)
242 : core_(new internal::ImmutableCore
<T
, Traits
>(t
)) {}
244 const T
& Get() const {
249 scoped_refptr
<const internal::ImmutableCore
<T
, Traits
> > core_
;
252 // Helper function to avoid having to write out template arguments.
253 template <typename T
>
254 Immutable
<T
> MakeImmutable(T
* t
) {
255 return Immutable
<T
>(t
);
258 } // namespace syncer
260 #endif // SYNC_UTIL_IMMUTABLE_H_