Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / sync / syncable / proto_value_ptr.h
blobdea3a68aeb3a57dc8126000c97df05489ec1cf87
1 // Copyright 2015 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.
5 #ifndef SYNC_SYNCABLE_ENTRY_PROTO_FIELD_PTR_H_
6 #define SYNC_SYNCABLE_ENTRY_PROTO_FIELD_PTR_H_
8 #include "base/gtest_prod_util.h"
9 #include "base/memory/ref_counted.h"
10 #include "sync/protocol/attachments.pb.h"
11 #include "sync/protocol/sync.pb.h"
13 namespace syncer {
14 namespace syncable {
16 // Default traits struct for ProtoValuePtr - adapts a
17 // ::google::protobuf::MessageLite derived type to be used with ProtoValuePtr.
18 template <typename T>
19 struct DefaultProtoValuePtrTraits {
20 // Deep copy the value from |src| to |dest|.
21 static void CopyValue(T* dest, const T& src) { dest->CopyFrom(src); }
22 // Parse the value from BLOB.
23 static void ParseFromBlob(T* dest, const void* blob, int length) {
24 dest->ParseFromArray(blob, length);
26 // True if the |value| is a non-default value.
27 static bool HasValue(const T& value) { return value.ByteSize() > 0; }
28 // Default value for the type.
29 static const T& DefaultValue() { return T::default_instance(); }
32 // This is a smart pointer to a ::google::protobuf::MessageLite derived type
33 // that implements immutable, shareable, copy-on-write semantics.
35 // Additionally this class helps to avoid storing multiple copies of default
36 // instances of the wrapped type.
38 // Copying ProtoValuePtr results in ref-counted sharing of the
39 // underlying wrapper and the value contained in the wrapper.
41 // The public interface includes only immutable access to the wrapped value.
42 // The only way to assign a value to ProtoValuePtr is through a
43 // private SetValue function which is called from EntryKernel. That results
44 // in stopping sharing the previous value and creating a wrapper to the new
45 // value.
46 template <typename T, typename Traits = DefaultProtoValuePtrTraits<T>>
47 class ProtoValuePtr {
48 private:
49 // Immutable shareable ref-counted wrapper that embeds the value.
50 class Wrapper : public base::RefCountedThreadSafe<Wrapper> {
51 public:
52 Wrapper(const T& value) { Traits::CopyValue(&value_, value); }
53 const T& value() const { return value_; }
54 // Create wrapper by deserializing a BLOB.
55 static Wrapper* ParseFromBlob(const void* blob, int length) {
56 Wrapper* wrapper = new Wrapper;
57 Traits::ParseFromBlob(&wrapper->value_, blob, length);
58 return wrapper;
61 private:
62 friend class base::RefCountedThreadSafe<Wrapper>;
63 Wrapper() {}
64 ~Wrapper() {}
66 T value_;
69 ProtoValuePtr() {}
70 ~ProtoValuePtr() {}
72 public:
73 const T& value() const {
74 return wrapper_ ? wrapper_->value() : Traits::DefaultValue();
77 const T* operator->() const {
78 const T& wrapped_instance = value();
79 return &wrapped_instance;
82 private:
83 friend struct EntryKernel;
84 FRIEND_TEST_ALL_PREFIXES(ProtoValuePtrTest, BasicTest);
85 FRIEND_TEST_ALL_PREFIXES(ProtoValuePtrTest, SharingTest);
86 FRIEND_TEST_ALL_PREFIXES(ProtoValuePtrTest, ParsingTest);
88 void set_value(const T& new_value) {
89 if (Traits::HasValue(new_value)) {
90 wrapper_ = new Wrapper(new_value);
91 } else {
92 // Don't store default value.
93 wrapper_ = nullptr;
97 void load(const void* blob, int length) {
98 wrapper_ = Wrapper::ParseFromBlob(blob, length);
101 scoped_refptr<Wrapper> wrapper_;
104 typedef ProtoValuePtr<sync_pb::EntitySpecifics> EntitySpecificsPtr;
105 typedef ProtoValuePtr<sync_pb::AttachmentMetadata> AttachmentMetadataPtr;
107 } // namespace syncable
108 } // namespace syncer
110 #endif // SYNC_SYNCABLE_ENTRY_PROTO_FIELD_PTR_H_