summaryrefslogtreecommitdiffstats
path: root/sync/internal_api/public/util/immutable.h
diff options
context:
space:
mode:
Diffstat (limited to 'sync/internal_api/public/util/immutable.h')
-rw-r--r--sync/internal_api/public/util/immutable.h262
1 files changed, 262 insertions, 0 deletions
diff --git a/sync/internal_api/public/util/immutable.h b/sync/internal_api/public/util/immutable.h
new file mode 100644
index 0000000..6624b90
--- /dev/null
+++ b/sync/internal_api/public/util/immutable.h
@@ -0,0 +1,262 @@
+// 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_