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