| // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights |
| // reserved. Use of this source code is governed by a BSD-style license that |
| // can be found in the LICENSE file. |
| |
| #include "libcef/common/value_base.h" |
| |
| CefValueController::CefValueController() |
| : owner_value_(nullptr), owner_object_(nullptr) {} |
| |
| CefValueController::~CefValueController() { |
| // Everything should already have been removed. |
| DCHECK(!owner_value_ && !owner_object_); |
| DCHECK(reference_map_.empty()); |
| DCHECK(dependency_map_.empty()); |
| } |
| |
| void CefValueController::SetOwner(void* value, Object* object) { |
| DCHECK(value && object); |
| |
| // Controller should already be locked. |
| DCHECK(locked()); |
| |
| // Owner should only be set once. |
| DCHECK(!owner_value_ && !owner_object_); |
| |
| owner_value_ = value; |
| owner_object_ = object; |
| } |
| |
| void CefValueController::AddReference(void* value, Object* object) { |
| DCHECK(value && object); |
| |
| // Controller should already be locked. |
| DCHECK(locked()); |
| |
| // Controller should currently have an owner. |
| DCHECK(owner_value_); |
| |
| // Values should only be added once. |
| DCHECK(reference_map_.find(value) == reference_map_.end()); |
| DCHECK(value != owner_value_); |
| |
| reference_map_.insert(std::make_pair(value, object)); |
| } |
| |
| void CefValueController::Remove(void* value, bool notify_object) { |
| DCHECK(value); |
| |
| // Controller should already be locked. |
| DCHECK(locked()); |
| |
| // Controller should currently have an owner. |
| DCHECK(owner_value_); |
| |
| if (value == owner_value_) { |
| // Should never notify when removing the owner object. |
| DCHECK(!notify_object); |
| |
| owner_value_ = nullptr; |
| owner_object_ = nullptr; |
| |
| // Remove all references. |
| if (reference_map_.size() > 0) { |
| ReferenceMap::iterator it = reference_map_.begin(); |
| for (; it != reference_map_.end(); ++it) |
| it->second->OnControlRemoved(); |
| reference_map_.clear(); |
| } |
| |
| // Remove all dependencies. |
| dependency_map_.clear(); |
| } else { |
| ReferenceMap::iterator it = reference_map_.find(value); |
| if (it != reference_map_.end()) { |
| // Remove the reference. |
| if (notify_object) |
| it->second->OnControlRemoved(); |
| reference_map_.erase(it); |
| } |
| } |
| } |
| |
| CefValueController::Object* CefValueController::Get(void* value) { |
| DCHECK(value); |
| |
| // Controller should already be locked. |
| DCHECK(locked()); |
| |
| if (value == owner_value_) { |
| return owner_object_; |
| } else { |
| ReferenceMap::iterator it = reference_map_.find(value); |
| if (it != reference_map_.end()) |
| return it->second; |
| return nullptr; |
| } |
| } |
| |
| void CefValueController::AddDependency(void* parent, void* child) { |
| DCHECK(parent && child && parent != child); |
| |
| // Controller should already be locked. |
| DCHECK(locked()); |
| |
| DependencyMap::iterator it = dependency_map_.find(parent); |
| if (it == dependency_map_.end()) { |
| // New set. |
| DependencySet set; |
| set.insert(child); |
| dependency_map_.insert(std::make_pair(parent, set)); |
| } else if (it->second.find(child) == it->second.end()) { |
| // Update existing set. |
| it->second.insert(child); |
| } |
| } |
| |
| void CefValueController::RemoveDependencies(void* value) { |
| DCHECK(value); |
| |
| // Controller should already be locked. |
| DCHECK(locked()); |
| |
| if (dependency_map_.empty()) |
| return; |
| |
| DependencyMap::iterator it_dependency = dependency_map_.find(value); |
| if (it_dependency == dependency_map_.end()) |
| return; |
| |
| // Start with the set of dependencies for the current value. |
| DependencySet remove_set = it_dependency->second; |
| dependency_map_.erase(it_dependency); |
| |
| DependencySet::iterator it_value; |
| ReferenceMap::iterator it_reference; |
| |
| while (remove_set.size() > 0) { |
| it_value = remove_set.begin(); |
| value = *it_value; |
| remove_set.erase(it_value); |
| |
| // Does the current value have dependencies? |
| it_dependency = dependency_map_.find(value); |
| if (it_dependency != dependency_map_.end()) { |
| // Append the dependency set to the remove set. |
| remove_set.insert(it_dependency->second.begin(), |
| it_dependency->second.end()); |
| dependency_map_.erase(it_dependency); |
| } |
| |
| // Does the current value have a reference? |
| it_reference = reference_map_.find(value); |
| if (it_reference != reference_map_.end()) { |
| // Remove the reference. |
| it_reference->second->OnControlRemoved(); |
| reference_map_.erase(it_reference); |
| } |
| } |
| } |
| |
| void CefValueController::TakeFrom(CefValueController* other) { |
| DCHECK(other); |
| |
| // Both controllers should already be locked. |
| DCHECK(locked()); |
| DCHECK(other->locked()); |
| |
| if (!other->reference_map_.empty()) { |
| // Transfer references from the other to this. |
| ReferenceMap::iterator it = other->reference_map_.begin(); |
| for (; it != other->reference_map_.end(); ++it) { |
| // References should only be added once. |
| DCHECK(reference_map_.find(it->first) == reference_map_.end()); |
| reference_map_.insert(std::make_pair(it->first, it->second)); |
| } |
| other->reference_map_.clear(); |
| } |
| |
| if (!other->dependency_map_.empty()) { |
| // Transfer dependencies from the other to this. |
| DependencyMap::iterator it_other = other->dependency_map_.begin(); |
| for (; it_other != other->dependency_map_.end(); ++it_other) { |
| DependencyMap::iterator it_me = dependency_map_.find(it_other->first); |
| if (it_me == dependency_map_.end()) { |
| // All children are new. |
| dependency_map_.insert( |
| std::make_pair(it_other->first, it_other->second)); |
| } else { |
| // Evaluate each child. |
| DependencySet::iterator it_other_set = it_other->second.begin(); |
| for (; it_other_set != it_other->second.end(); ++it_other_set) { |
| if (it_me->second.find(*it_other_set) == it_me->second.end()) |
| it_me->second.insert(*it_other_set); |
| } |
| } |
| } |
| } |
| } |
| |
| void CefValueController::Swap(void* old_value, void* new_value) { |
| DCHECK(old_value && new_value && old_value != new_value); |
| |
| // Controller should already be locked. |
| DCHECK(locked()); |
| |
| if (owner_value_ == old_value) |
| owner_value_ = new_value; |
| |
| if (!reference_map_.empty()) { |
| ReferenceMap::iterator it = reference_map_.find(old_value); |
| if (it != reference_map_.end()) { |
| // References should only be added once. |
| DCHECK(reference_map_.find(new_value) == reference_map_.end()); |
| reference_map_.insert(std::make_pair(new_value, it->second)); |
| reference_map_.erase(it); |
| } |
| } |
| |
| if (!dependency_map_.empty()) { |
| DependencyMap::iterator it = dependency_map_.find(old_value); |
| if (it != dependency_map_.end()) { |
| dependency_map_.insert(std::make_pair(new_value, it->second)); |
| dependency_map_.erase(it); |
| } |
| |
| it = dependency_map_.begin(); |
| for (; it != dependency_map_.end(); ++it) { |
| DependencySet::iterator dit = it->second.find(old_value); |
| if (dit != it->second.end()) { |
| it->second.insert(new_value); |
| it->second.erase(dit); |
| } |
| } |
| } |
| } |