| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #ifndef SYNC_INTERNAL_API_PUBLIC_UTIL_PROTO_VALUE_PTR_H_ | |
| 6 #define SYNC_INTERNAL_API_PUBLIC_UTIL_PROTO_VALUE_PTR_H_ | |
| 7 | |
| 8 #include "base/gtest_prod_util.h" | |
| 9 #include "base/memory/ref_counted.h" | |
| 10 | |
| 11 namespace syncer_v2 { | |
| 12 struct EntityData; | |
| 13 class ProcessorEntityTracker; | |
| 14 } // namespace syncer_v2 | |
| 15 | |
| 16 namespace syncer { | |
| 17 | |
| 18 namespace syncable { | |
| 19 struct EntryKernel; | |
| 20 } // namespace syncable | |
| 21 | |
| 22 // Default traits struct for ProtoValuePtr - adapts a | |
| 23 // ::google::protobuf::MessageLite derived type to be used with ProtoValuePtr. | |
| 24 template <typename T> | |
| 25 struct DefaultProtoValuePtrTraits { | |
| 26 // Deep copy the value from |src| to |dest|. | |
| 27 static void CopyValue(T* dest, const T& src) { dest->CopyFrom(src); } | |
| 28 // Swap the value with the source (to avoid deep copying). | |
| 29 static void SwapValue(T* dest, T* src) { dest->Swap(src); } | |
| 30 // Parse the value from BLOB. | |
| 31 static void ParseFromBlob(T* dest, const void* blob, int length) { | |
| 32 dest->ParseFromArray(blob, length); | |
| 33 } | |
| 34 // True if the |value| is a non-default value. | |
| 35 static bool HasValue(const T& value) { return value.ByteSize() > 0; } | |
| 36 // Default value for the type. | |
| 37 static const T& DefaultValue() { return T::default_instance(); } | |
| 38 }; | |
| 39 | |
| 40 // This is a smart pointer to a ::google::protobuf::MessageLite derived type | |
| 41 // that implements immutable, shareable, copy-on-write semantics. | |
| 42 // | |
| 43 // Additionally this class helps to avoid storing multiple copies of default | |
| 44 // instances of the wrapped type. | |
| 45 // | |
| 46 // Copying ProtoValuePtr results in ref-counted sharing of the | |
| 47 // underlying wrapper and the value contained in the wrapper. | |
| 48 // | |
| 49 // The public interface includes only immutable access to the wrapped value. | |
| 50 // The only way to assign a value to ProtoValuePtr is through a | |
| 51 // private SetValue function which is called from EntryKernel. That results | |
| 52 // in stopping sharing the previous value and creating a wrapper to the new | |
| 53 // value. | |
| 54 template <typename T, typename Traits = DefaultProtoValuePtrTraits<T>> | |
| 55 class ProtoValuePtr { | |
| 56 private: | |
| 57 // Immutable shareable ref-counted wrapper that embeds the value. | |
| 58 class Wrapper : public base::RefCountedThreadSafe<Wrapper> { | |
| 59 public: | |
| 60 explicit Wrapper(const T& value) { Traits::CopyValue(&value_, value); } | |
| 61 explicit Wrapper(T* value) { Traits::SwapValue(&value_, value); } | |
| 62 | |
| 63 const T& value() const { return value_; } | |
| 64 // Create wrapper by deserializing a BLOB. | |
| 65 static Wrapper* ParseFromBlob(const void* blob, int length) { | |
| 66 Wrapper* wrapper = new Wrapper; | |
| 67 Traits::ParseFromBlob(&wrapper->value_, blob, length); | |
| 68 return wrapper; | |
| 69 } | |
| 70 | |
| 71 private: | |
| 72 friend class base::RefCountedThreadSafe<Wrapper>; | |
| 73 Wrapper() {} | |
| 74 ~Wrapper() {} | |
| 75 | |
| 76 T value_; | |
| 77 }; | |
| 78 | |
| 79 public: | |
| 80 ProtoValuePtr() {} | |
| 81 ~ProtoValuePtr() {} | |
| 82 | |
| 83 const T& value() const { | |
| 84 return wrapper_ ? wrapper_->value() : Traits::DefaultValue(); | |
| 85 } | |
| 86 | |
| 87 const T* operator->() const { | |
| 88 const T& wrapped_instance = value(); | |
| 89 return &wrapped_instance; | |
| 90 } | |
| 91 | |
| 92 private: | |
| 93 friend struct syncable::EntryKernel; | |
| 94 friend struct syncer_v2::EntityData; | |
| 95 friend class syncer_v2::ProcessorEntityTracker; | |
| 96 FRIEND_TEST_ALL_PREFIXES(ProtoValuePtrTest, ValueAssignment); | |
| 97 FRIEND_TEST_ALL_PREFIXES(ProtoValuePtrTest, ValueSwap); | |
| 98 FRIEND_TEST_ALL_PREFIXES(ProtoValuePtrTest, SharingTest); | |
| 99 FRIEND_TEST_ALL_PREFIXES(ProtoValuePtrTest, ParsingTest); | |
| 100 | |
| 101 // set the value to copy of |new_value|. | |
| 102 void set_value(const T& new_value) { | |
| 103 if (Traits::HasValue(new_value)) { | |
| 104 wrapper_ = new Wrapper(new_value); | |
| 105 } else { | |
| 106 // Don't store default value. | |
| 107 reset(); | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 void reset() { wrapper_ = nullptr; } | |
| 112 | |
| 113 // Take over |src| value (swap). | |
| 114 void swap_value(T* src) { | |
| 115 if (Traits::HasValue(*src)) { | |
| 116 wrapper_ = new Wrapper(src); | |
| 117 } else { | |
| 118 // Don't store default value. | |
| 119 reset(); | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 void load(const void* blob, int length) { | |
| 124 wrapper_ = Wrapper::ParseFromBlob(blob, length); | |
| 125 } | |
| 126 | |
| 127 scoped_refptr<Wrapper> wrapper_; | |
| 128 }; | |
| 129 | |
| 130 } // namespace syncer | |
| 131 | |
| 132 #endif // SYNC_INTERNAL_API_PUBLIC_UTIL_PROTO_VALUE_PTR_H_ | |
| OLD | NEW |