1 // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "libcef/common/value_base.h"
6
CefValueController()7 CefValueController::CefValueController()
8 : owner_value_(nullptr), owner_object_(nullptr) {}
9
~CefValueController()10 CefValueController::~CefValueController() {
11 // Everything should already have been removed.
12 DCHECK(!owner_value_ && !owner_object_);
13 DCHECK(reference_map_.empty());
14 DCHECK(dependency_map_.empty());
15 }
16
SetOwner(void * value,Object * object)17 void CefValueController::SetOwner(void* value, Object* object) {
18 DCHECK(value && object);
19
20 // Controller should already be locked.
21 DCHECK(locked());
22
23 // Owner should only be set once.
24 DCHECK(!owner_value_ && !owner_object_);
25
26 owner_value_ = value;
27 owner_object_ = object;
28 }
29
AddReference(void * value,Object * object)30 void CefValueController::AddReference(void* value, Object* object) {
31 DCHECK(value && object);
32
33 // Controller should already be locked.
34 DCHECK(locked());
35
36 // Controller should currently have an owner.
37 DCHECK(owner_value_);
38
39 // Values should only be added once.
40 DCHECK(reference_map_.find(value) == reference_map_.end());
41 DCHECK(value != owner_value_);
42
43 reference_map_.insert(std::make_pair(value, object));
44 }
45
Remove(void * value,bool notify_object)46 void CefValueController::Remove(void* value, bool notify_object) {
47 DCHECK(value);
48
49 // Controller should already be locked.
50 DCHECK(locked());
51
52 // Controller should currently have an owner.
53 DCHECK(owner_value_);
54
55 if (value == owner_value_) {
56 // Should never notify when removing the owner object.
57 DCHECK(!notify_object);
58
59 owner_value_ = nullptr;
60 owner_object_ = nullptr;
61
62 // Remove all references.
63 if (reference_map_.size() > 0) {
64 ReferenceMap::iterator it = reference_map_.begin();
65 for (; it != reference_map_.end(); ++it)
66 it->second->OnControlRemoved();
67 reference_map_.clear();
68 }
69
70 // Remove all dependencies.
71 dependency_map_.clear();
72 } else {
73 ReferenceMap::iterator it = reference_map_.find(value);
74 if (it != reference_map_.end()) {
75 // Remove the reference.
76 if (notify_object)
77 it->second->OnControlRemoved();
78 reference_map_.erase(it);
79 }
80 }
81 }
82
Get(void * value)83 CefValueController::Object* CefValueController::Get(void* value) {
84 DCHECK(value);
85
86 // Controller should already be locked.
87 DCHECK(locked());
88
89 if (value == owner_value_) {
90 return owner_object_;
91 } else {
92 ReferenceMap::iterator it = reference_map_.find(value);
93 if (it != reference_map_.end())
94 return it->second;
95 return nullptr;
96 }
97 }
98
AddDependency(void * parent,void * child)99 void CefValueController::AddDependency(void* parent, void* child) {
100 DCHECK(parent && child && parent != child);
101
102 // Controller should already be locked.
103 DCHECK(locked());
104
105 DependencyMap::iterator it = dependency_map_.find(parent);
106 if (it == dependency_map_.end()) {
107 // New set.
108 DependencySet set;
109 set.insert(child);
110 dependency_map_.insert(std::make_pair(parent, set));
111 } else if (it->second.find(child) == it->second.end()) {
112 // Update existing set.
113 it->second.insert(child);
114 }
115 }
116
RemoveDependencies(void * value)117 void CefValueController::RemoveDependencies(void* value) {
118 DCHECK(value);
119
120 // Controller should already be locked.
121 DCHECK(locked());
122
123 if (dependency_map_.empty())
124 return;
125
126 DependencyMap::iterator it_dependency = dependency_map_.find(value);
127 if (it_dependency == dependency_map_.end())
128 return;
129
130 // Start with the set of dependencies for the current value.
131 DependencySet remove_set = it_dependency->second;
132 dependency_map_.erase(it_dependency);
133
134 DependencySet::iterator it_value;
135 ReferenceMap::iterator it_reference;
136
137 while (remove_set.size() > 0) {
138 it_value = remove_set.begin();
139 value = *it_value;
140 remove_set.erase(it_value);
141
142 // Does the current value have dependencies?
143 it_dependency = dependency_map_.find(value);
144 if (it_dependency != dependency_map_.end()) {
145 // Append the dependency set to the remove set.
146 remove_set.insert(it_dependency->second.begin(),
147 it_dependency->second.end());
148 dependency_map_.erase(it_dependency);
149 }
150
151 // Does the current value have a reference?
152 it_reference = reference_map_.find(value);
153 if (it_reference != reference_map_.end()) {
154 // Remove the reference.
155 it_reference->second->OnControlRemoved();
156 reference_map_.erase(it_reference);
157 }
158 }
159 }
160
TakeFrom(CefValueController * other)161 void CefValueController::TakeFrom(CefValueController* other) {
162 DCHECK(other);
163
164 // Both controllers should already be locked.
165 DCHECK(locked());
166 DCHECK(other->locked());
167
168 if (!other->reference_map_.empty()) {
169 // Transfer references from the other to this.
170 ReferenceMap::iterator it = other->reference_map_.begin();
171 for (; it != other->reference_map_.end(); ++it) {
172 // References should only be added once.
173 DCHECK(reference_map_.find(it->first) == reference_map_.end());
174 reference_map_.insert(std::make_pair(it->first, it->second));
175 }
176 other->reference_map_.clear();
177 }
178
179 if (!other->dependency_map_.empty()) {
180 // Transfer dependencies from the other to this.
181 DependencyMap::iterator it_other = other->dependency_map_.begin();
182 for (; it_other != other->dependency_map_.end(); ++it_other) {
183 DependencyMap::iterator it_me = dependency_map_.find(it_other->first);
184 if (it_me == dependency_map_.end()) {
185 // All children are new.
186 dependency_map_.insert(
187 std::make_pair(it_other->first, it_other->second));
188 } else {
189 // Evaluate each child.
190 DependencySet::iterator it_other_set = it_other->second.begin();
191 for (; it_other_set != it_other->second.end(); ++it_other_set) {
192 if (it_me->second.find(*it_other_set) == it_me->second.end())
193 it_me->second.insert(*it_other_set);
194 }
195 }
196 }
197 }
198 }
199
Swap(void * old_value,void * new_value)200 void CefValueController::Swap(void* old_value, void* new_value) {
201 DCHECK(old_value && new_value && old_value != new_value);
202
203 // Controller should already be locked.
204 DCHECK(locked());
205
206 if (owner_value_ == old_value)
207 owner_value_ = new_value;
208
209 if (!reference_map_.empty()) {
210 ReferenceMap::iterator it = reference_map_.find(old_value);
211 if (it != reference_map_.end()) {
212 // References should only be added once.
213 DCHECK(reference_map_.find(new_value) == reference_map_.end());
214 reference_map_.insert(std::make_pair(new_value, it->second));
215 reference_map_.erase(it);
216 }
217 }
218
219 if (!dependency_map_.empty()) {
220 DependencyMap::iterator it = dependency_map_.find(old_value);
221 if (it != dependency_map_.end()) {
222 dependency_map_.insert(std::make_pair(new_value, it->second));
223 dependency_map_.erase(it);
224 }
225
226 it = dependency_map_.begin();
227 for (; it != dependency_map_.end(); ++it) {
228 DependencySet::iterator dit = it->second.find(old_value);
229 if (dit != it->second.end()) {
230 it->second.insert(new_value);
231 it->second.erase(dit);
232 }
233 }
234 }
235 }
236