OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ | 5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ |
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ | 6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ |
7 | 7 |
8 #include <assert.h> | 8 #include <assert.h> |
9 | 9 |
10 #include "base/threading/thread_checker.h" | 10 #include "base/threading/thread_checker.h" |
11 #include "mojo/public/cpp/system/macros.h" | 11 #include "mojo/public/cpp/system/macros.h" |
12 | 12 |
13 namespace mojo { | 13 namespace mojo { |
14 namespace internal { | 14 namespace internal { |
15 | 15 |
16 // Used to allocate an instance of T that can be shared via reference counting. | 16 // Used to allocate an instance of T that can be shared via reference counting. |
| 17 // |
| 18 // A default constructed SharedData does not have a Holder until it is set, |
| 19 // either by assignment, or by accessing the value. As a result, it is not tied |
| 20 // to any thread. The Holder is lazily allocated on first access. The complexity |
| 21 // is due to the behaviour around copying. If a default constructed SharedData |
| 22 // is copied into another, the two share the same empty state, and changing the |
| 23 // value of one will affect the other. |
17 template <typename T> | 24 template <typename T> |
18 class SharedData { | 25 class SharedData { |
19 public: | 26 public: |
20 ~SharedData() { holder_->Release(); } | 27 ~SharedData() { |
| 28 if (holder_) |
| 29 holder_->Release(); |
| 30 } |
21 | 31 |
22 SharedData() : holder_(new Holder()) {} | 32 SharedData() : holder_(nullptr) {} |
23 | 33 |
24 explicit SharedData(const T& value) : holder_(new Holder(value)) {} | 34 explicit SharedData(const T& value) : holder_(new Holder(value)) {} |
25 | 35 |
26 SharedData(const SharedData<T>& other) : holder_(other.holder_) { | 36 SharedData(const SharedData<T>& other) { |
| 37 other.LazyInit(); |
| 38 holder_ = other.holder_; |
27 holder_->Retain(); | 39 holder_->Retain(); |
28 } | 40 } |
29 | 41 |
30 SharedData<T>& operator=(const SharedData<T>& other) { | 42 SharedData<T>& operator=(const SharedData<T>& other) { |
| 43 other.LazyInit(); |
31 if (other.holder_ == holder_) | 44 if (other.holder_ == holder_) |
32 return *this; | 45 return *this; |
33 holder_->Release(); | 46 if (holder_) |
| 47 holder_->Release(); |
34 holder_ = other.holder_; | 48 holder_ = other.holder_; |
35 holder_->Retain(); | 49 holder_->Retain(); |
36 return *this; | 50 return *this; |
37 } | 51 } |
38 | 52 |
39 void reset() { | 53 void reset() { |
40 holder_->Release(); | 54 if (holder_) |
41 holder_ = new Holder(); | 55 holder_->Release(); |
| 56 holder_ = nullptr; |
42 } | 57 } |
43 | 58 |
44 void reset(const T& value) { | 59 void reset(const T& value) { |
45 holder_->Release(); | 60 if (holder_) |
| 61 holder_->Release(); |
46 holder_ = new Holder(value); | 62 holder_ = new Holder(value); |
47 } | 63 } |
48 | 64 |
49 void set_value(const T& value) { holder_->value = value; } | 65 void set_value(const T& value) { |
50 T* mutable_value() { return &holder_->value; } | 66 LazyInit(); |
51 const T& value() const { return holder_->value; } | 67 holder_->value = value; |
| 68 } |
| 69 T* mutable_value() { |
| 70 LazyInit(); |
| 71 return &holder_->value; |
| 72 } |
| 73 const T& value() const { |
| 74 LazyInit(); |
| 75 return holder_->value; |
| 76 } |
52 | 77 |
53 private: | 78 private: |
54 class Holder { | 79 class Holder { |
55 public: | 80 public: |
56 Holder() : value(), ref_count_(1) {} | 81 Holder() : value(), ref_count_(1) {} |
57 Holder(const T& value) : value(value), ref_count_(1) {} | 82 Holder(const T& value) : value(value), ref_count_(1) {} |
58 | 83 |
59 void Retain() { | 84 void Retain() { |
60 assert(thread_checker_.CalledOnValidThread()); | 85 assert(thread_checker_.CalledOnValidThread()); |
61 ++ref_count_; | 86 ++ref_count_; |
62 } | 87 } |
63 void Release() { | 88 void Release() { |
64 assert(thread_checker_.CalledOnValidThread()); | 89 assert(thread_checker_.CalledOnValidThread()); |
65 if (--ref_count_ == 0) | 90 if (--ref_count_ == 0) |
66 delete this; | 91 delete this; |
67 } | 92 } |
68 | 93 |
69 T value; | 94 T value; |
70 | 95 |
71 private: | 96 private: |
72 int ref_count_; | 97 int ref_count_; |
73 base::ThreadChecker thread_checker_; | 98 base::ThreadChecker thread_checker_; |
74 MOJO_DISALLOW_COPY_AND_ASSIGN(Holder); | 99 MOJO_DISALLOW_COPY_AND_ASSIGN(Holder); |
75 }; | 100 }; |
76 | 101 |
77 Holder* holder_; | 102 void LazyInit() const { |
| 103 if (!holder_) |
| 104 holder_ = new Holder(); |
| 105 } |
| 106 |
| 107 mutable Holder* holder_; |
78 }; | 108 }; |
79 | 109 |
80 } // namespace internal | 110 } // namespace internal |
81 } // namespace mojo | 111 } // namespace mojo |
82 | 112 |
83 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ | 113 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ |
OLD | NEW |