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"
16 // Default traits struct for ProtoValuePtr - adapts a
17 // ::google::protobuf::MessageLite derived type to be used with ProtoValuePtr.
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
46 template <typename T
, typename Traits
= DefaultProtoValuePtrTraits
<T
>>
49 // Immutable shareable ref-counted wrapper that embeds the value.
50 class Wrapper
: public base::RefCountedThreadSafe
<Wrapper
> {
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
);
62 friend class base::RefCountedThreadSafe
<Wrapper
>;
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
;
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
);
92 // Don't store default value.
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_