summaryrefslogtreecommitdiffstats
path: root/chromium/sync/internal_api/public/util/immutable.h
blob: 683a5e612d39d0e325e2fe80788a1a444d1d1880 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Immutable<T> provides an easy, cheap, and thread-safe way to pass
// large immutable data around.
//
// For example, consider the following code:
//
//  typedef std::vector<LargeObject> LargeObjectList;
//
//   void ProcessStuff(const LargeObjectList& stuff) {
//     for (LargeObjectList::const_iterator it = stuff.begin();
//          it != stuff.end(); ++it) {
//       ... process it ...
//     }
//   }
//
//   ...
//
//   LargeObjectList my_stuff;
//   ... fill my_stuff with lots of LargeObjects ...
//   some_loop->PostTask(FROM_HERE, base::Bind(&ProcessStuff, my_stuff));
//
// The last line incurs the cost of copying my_stuff, which is
// undesirable.  Here's the above code re-written using Immutable<T>:
//
//   void ProcessStuff(const Immutable<LargeObjectList>& stuff) {
//     for (LargeObjectList::const_iterator it = stuff.Get().begin();
//          it != stuff.Get().end(); ++it) {
//       ... process it ...
//     }
//   }
//
//   ...
//
//   LargeObjectList my_stuff;
//   ... fill my_stuff with lots of LargeObjects ...
//   some_loop->PostTask(
//       FROM_HERE, base::Bind(&ProcessStuff, MakeImmutable(&my_stuff)));
//
// The last line, which resets my_stuff to a default-initialized
// state, incurs only the cost of a swap of LargeObjectLists, which is
// O(1) for most STL container implementations.  The data in my_stuff
// is ref-counted (thread-safely), so it is freed as soon as
// ProcessStuff is finished.
//
// NOTE: By default, Immutable<T> relies on ADL
// (http://en.wikipedia.org/wiki/Argument-dependent_name_lookup) to
// find a swap() function for T, falling back to std::swap() when
// necessary.  If you overload swap() for your type in its namespace,
// or if you specialize std::swap() for your type, (see
// http://stackoverflow.com/questions/11562/how-to-overload-stdswap
// for discussion) Immutable<T> should be able to find it.
//
// Alternatively, you could explicitly control which swap function is
// used by providing your own traits class or using one of the
// pre-defined ones below.  See comments on traits below for details.
//
// NOTE: Some complexity is necessary in order to use Immutable<T>
// with forward-declared types.  See comments on traits below for
// details.

#ifndef SYNC_UTIL_IMMUTABLE_H_
#define SYNC_UTIL_IMMUTABLE_H_

// For std::swap().
#include <algorithm>

#include "base/basictypes.h"
#include "base/memory/ref_counted.h"

namespace syncer {

namespace internal {
// This class is part of the Immutable implementation.  DO NOT USE
// THIS CLASS DIRECTLY YOURSELF.

template <typename T, typename Traits>
class ImmutableCore
    : public base::RefCountedThreadSafe<ImmutableCore<T, Traits> > {
 public:
  // wrapper_ is always explicitly default-initialized to handle
  // primitive types and the case where Traits::Wrapper == T.

  ImmutableCore() : wrapper_() {
    Traits::InitializeWrapper(&wrapper_);
  }

  explicit ImmutableCore(T* t) : wrapper_() {
    Traits::InitializeWrapper(&wrapper_);
    Traits::Swap(Traits::UnwrapMutable(&wrapper_), t);
  }

  const T& Get() const {
    return Traits::Unwrap(wrapper_);
  }

 private:
  ~ImmutableCore() {
    Traits::DestroyWrapper(&wrapper_);
  }
  friend class base::RefCountedThreadSafe<ImmutableCore<T, Traits> >;

  // This is semantically const, but we can't mark it a such as we
  // modify it in the constructor.
  typename Traits::Wrapper wrapper_;

  DISALLOW_COPY_AND_ASSIGN(ImmutableCore);
};

}  // namespace internal

// Traits usage notes
// ------------------
// The most common reason to use your own traits class is to provide
// your own swap method.  First, consider the pre-defined traits
// classes HasSwapMemFn{ByRef,ByPtr} below.  If neither of those work,
// then define your own traits class inheriting from
// DefaultImmutableTraits<YourType> (to pick up the defaults for
// everything else) and provide your own Swap() method.
//
// Another reason to use your own traits class is to be able to use
// Immutable<T> with a forward-declared type (important for protobuf
// classes, when you want to avoid headers pulling in generated
// headers).  (This is why the Traits::Wrapper type exists; normally,
// Traits::Wrapper is just T itself, but that needs to be changed for
// forward-declared types.)
//
// For example, if you want to do this:
//
//   my_class.h
//   ----------
//   #include ".../immutable.h"
//
//   // Forward declaration.
//   class SomeOtherType;
//
//   class MyClass {
//     ...
//    private:
//     // Doesn't work, as defaults traits class needs SomeOtherType's
//     // definition to be visible.
//     Immutable<SomeOtherType> foo_;
//   };
//
// You'll have to do this:
//
//   my_class.h
//   ----------
//   #include ".../immutable.h"
//
//   // Forward declaration.
//   class SomeOtherType;
//
//   class MyClass {
//     ...
//    private:
//     struct ImmutableSomeOtherTypeTraits {
//       // scoped_ptr<SomeOtherType> won't work here, either.
//       typedef SomeOtherType* Wrapper;
//
//       static void InitializeWrapper(Wrapper* wrapper);
//
//       static void DestroyWrapper(Wrapper* wrapper);
//       ...
//     };
//
//     typedef Immutable<SomeOtherType, ImmutableSomeOtherTypeTraits>
//         ImmutableSomeOtherType;
//
//     ImmutableSomeOtherType foo_;
//   };
//
//   my_class.cc
//   -----------
//   #include ".../some_other_type.h"
//
//   void MyClass::ImmutableSomeOtherTypeTraits::InitializeWrapper(
//       Wrapper* wrapper) {
//     *wrapper = new SomeOtherType();
//   }
//
//   void MyClass::ImmutableSomeOtherTypeTraits::DestroyWrapper(
//       Wrapper* wrapper) {
//     delete *wrapper;
//   }
//
//   ...
//
// Also note that this incurs an additional memory allocation when you
// create an Immutable<SomeOtherType>.

template <typename T>
struct DefaultImmutableTraits {
  typedef T Wrapper;

  static void InitializeWrapper(Wrapper* wrapper) {}

  static void DestroyWrapper(Wrapper* wrapper) {}

  static const T& Unwrap(const Wrapper& wrapper) { return wrapper; }

  static T* UnwrapMutable(Wrapper* wrapper) { return wrapper; }

  static void Swap(T* t1, T* t2) {
    // Uses ADL (see
    // http://en.wikipedia.org/wiki/Argument-dependent_name_lookup).
    using std::swap;
    swap(*t1, *t2);
  }
};

// Most STL containers have by-reference swap() member functions,
// although they usually already overload std::swap() to use those.
template <typename T>
struct HasSwapMemFnByRef : public DefaultImmutableTraits<T> {
  static void Swap(T* t1, T* t2) {
    t1->swap(*t2);
  }
};

// Most Google-style objects have by-pointer Swap() member functions
// (for example, generated protocol buffer classes).
template <typename T>
struct HasSwapMemFnByPtr : public DefaultImmutableTraits<T> {
  static void Swap(T* t1, T* t2) {
    t1->Swap(t2);
  }
};

template <typename T, typename Traits = DefaultImmutableTraits<T> >
class Immutable {
 public:
  // Puts the underlying object in a default-initialized state.
  Immutable() : core_(new internal::ImmutableCore<T, Traits>()) {}

  // Copy constructor and assignment welcome.

  // Resets |t| to a default-initialized state.
  explicit Immutable(T* t)
      : core_(new internal::ImmutableCore<T, Traits>(t)) {}

  const T& Get() const {
    return core_->Get();
  }

 private:
  scoped_refptr<const internal::ImmutableCore<T, Traits> > core_;
};

// Helper function to avoid having to write out template arguments.
template <typename T>
Immutable<T> MakeImmutable(T* t) {
  return Immutable<T>(t);
}

}  // namespace syncer

#endif  // SYNC_UTIL_IMMUTABLE_H_