Chromium Code Reviews| Index: chrome/browser/sync/util/immutable.h |
| diff --git a/chrome/browser/sync/util/immutable.h b/chrome/browser/sync/util/immutable.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b965ba81d499ea289bd8b8e0bafb546a7556f4b4 |
| --- /dev/null |
| +++ b/chrome/browser/sync/util/immutable.h |
| @@ -0,0 +1,258 @@ |
| +// Copyright (c) 2011 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 CHROME_BROWSER_SYNC_UTIL_IMMUTABLE_H_ |
| +#define CHROME_BROWSER_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: |
| + // container_ is always explicitly default-initialized to handle |
| + // primitive types. |
| + |
| + ImmutableCore() : container_() { |
| + Traits::CreateAndDefaultInitialize(&container_); |
| + } |
| + |
| + explicit ImmutableCore(T* t) : container_() { |
| + Traits::CreateAndDefaultInitialize(&container_); |
| + Traits::Swap(Traits::UnwrapMutable(&container_), t); |
| + } |
| + |
| + const T& Get() const { |
| + return Traits::Unwrap(container_); |
| + } |
| + |
| + private: |
| + ~ImmutableCore() { |
| + Traits::Destroy(&container_); |
| + } |
| + 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::Container container_; |
| + |
| + 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). For example, if you want to do this: |
|
Nicolas Zea
2011/09/15 23:39:46
I find the distinction between the immutable type
akalin
2011/09/16 00:59:59
Done.
|
| +// |
| +// 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* Container; |
| +// |
| +// static void CreateAndDefaultInitialize... |
| +// ... |
| +// }; |
| +// |
| +// typedef Immutable<SomeOtherType, ImmutableSomeOtherTypeTraits> |
| +// ImmutableSomeOtherType; |
| +// |
| +// ImmutableSomeOtherType foo_; |
| +// }; |
| +// |
| +// my_class.cc |
| +// ----------- |
| +// #include ".../some_other_type.h" |
| +// |
| +// void MyClass::ImmutableSomeOtherTypeTraits::CreateAndDefaultInitialize( |
| +// Container* t) { |
| +// *t = new SomeOtherType(); |
| +// } |
| +// |
| +// void MyClass::ImmutableSomeOtherTypeTraits::Destroy(Container* t) { |
| +// delete *t; |
| +// } |
| +// |
| +// ... |
| +// |
| +// Also note that this incurs an additional memory allocation when you |
| +// create an Immutable<SomeOtherType>. |
| + |
| +template <typename T> |
| +struct DefaultImmutableTraits { |
| + typedef T Container; |
| + |
| + // The container is already default-initialized, so do nothing. |
| + static void CreateAndDefaultInitialize(Container* container) {} |
| + |
| + // Since the container is automatically destroyed, no need to do |
| + // anything. |
| + static void Destroy(Container* container) {} |
| + |
| + static const T& Unwrap(const Container& container) { return container; } |
| + |
| + static T* UnwrapMutable(Container* container) { return container; } |
| + |
| + 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 // CHROME_BROWSER_SYNC_UTIL_IMMUTABLE_H_ |