| // 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 browser_sync::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_ |
| #pragma once |
| |
| // For std::swap(). |
| #include <algorithm> |
| |
| #include "base/basictypes.h" |
| #include "base/memory/ref_counted.h" |
| |
| namespace browser_sync { |
| |
| 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 browser_sync |
| |
| #endif // SYNC_UTIL_IMMUTABLE_H_ |