// 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); } } } }