#ifndef CEF_LIBCEF_COMMON_VALUE_BASE_H_
#define CEF_LIBCEF_COMMON_VALUE_BASE_H_
#pragma once
#include <map>
#include <set>
#include "include/cef_base.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/notreached.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "base/threading/platform_thread.h"
class CefValueController
: public base::RefCountedThreadSafe<CefValueController> {
public:
class Object {
public:
virtual ~Object() {}
virtual void OnControlRemoved() = 0;
};
class AutoLock {
public:
explicit AutoLock(CefValueController* impl)
: impl_(impl), verified_(impl && impl->VerifyThread()) {
DCHECK(impl);
if (verified_)
impl_->lock();
}
AutoLock(const AutoLock&) = delete;
AutoLock& operator=(const AutoLock&) = delete;
~AutoLock() {
if (verified_)
impl_->unlock();
}
inline bool verified() { return verified_; }
private:
scoped_refptr<CefValueController> impl_;
bool verified_;
};
CefValueController();
CefValueController(const CefValueController&) = delete;
CefValueController& operator=(const CefValueController&) = delete;
virtual bool thread_safe() = 0;
virtual bool on_correct_thread() = 0;
virtual void lock() = 0;
virtual void unlock() = 0;
virtual bool locked() = 0;
virtual void AssertLockAcquired() = 0;
inline bool VerifyThread() {
if (!thread_safe() && !on_correct_thread()) {
NOTREACHED() << "object accessed from incorrect thread.";
return false;
}
return true;
}
void SetOwner(void* value, Object* object);
void AddReference(void* value, Object* object);
void Remove(void* value, bool notify_object);
Object* Get(void* value);
void AddDependency(void* parent, void* child);
void RemoveDependencies(void* value);
void TakeFrom(CefValueController* other);
void Swap(void* old_value, void* new_value);
protected:
friend class base::RefCountedThreadSafe<CefValueController>;
virtual ~CefValueController();
private:
void* owner_value_;
Object* owner_object_;
using ReferenceMap = std::map<void*, Object*>;
ReferenceMap reference_map_;
using DependencySet = std::set<void*>;
using DependencyMap = std::map<void*, DependencySet>;
DependencyMap dependency_map_;
};
class CefValueControllerThreadSafe : public CefValueController {
public:
explicit CefValueControllerThreadSafe() : locked_thread_id_(0) {}
CefValueControllerThreadSafe(const CefValueControllerThreadSafe&) = delete;
CefValueControllerThreadSafe& operator=(const CefValueControllerThreadSafe&) =
delete;
bool thread_safe() override { return true; }
bool on_correct_thread() override { return true; }
void lock() override NO_THREAD_SAFETY_ANALYSIS {
lock_.Acquire();
locked_thread_id_ = base::PlatformThread::CurrentId();
}
void unlock() override NO_THREAD_SAFETY_ANALYSIS {
locked_thread_id_ = 0;
lock_.Release();
}
bool locked() override {
return (locked_thread_id_ == base::PlatformThread::CurrentId());
}
void AssertLockAcquired() override { lock_.AssertAcquired(); }
private:
base::Lock lock_;
base::PlatformThreadId locked_thread_id_;
};
class CefValueControllerNonThreadSafe : public CefValueController {
public:
explicit CefValueControllerNonThreadSafe()
: thread_id_(base::PlatformThread::CurrentId()) {}
CefValueControllerNonThreadSafe(const CefValueControllerNonThreadSafe&) =
delete;
CefValueControllerNonThreadSafe& operator=(
const CefValueControllerNonThreadSafe&) = delete;
bool thread_safe() override { return false; }
bool on_correct_thread() override {
return (thread_id_ == base::PlatformThread::CurrentId());
}
void lock() override {}
void unlock() override {}
bool locked() override { return on_correct_thread(); }
void AssertLockAcquired() override { DCHECK(locked()); }
private:
base::PlatformThreadId thread_id_;
};
#define CEF_VALUE_VERIFY_RETURN_VOID_EX(object, modify) \
if (!VerifyAttached()) \
return; \
AutoLock auto_lock(object, modify); \
if (!auto_lock.verified()) \
return;
#define CEF_VALUE_VERIFY_RETURN_VOID(modify) \
CEF_VALUE_VERIFY_RETURN_VOID_EX(this, modify)
#define CEF_VALUE_VERIFY_RETURN_EX(object, modify, error_val) \
if (!VerifyAttached()) \
return error_val; \
AutoLock auto_lock(object, modify); \
if (!auto_lock.verified()) \
return error_val;
#define CEF_VALUE_VERIFY_RETURN(modify, error_val) \
CEF_VALUE_VERIFY_RETURN_EX(this, modify, error_val)
template <class CefType, class ValueType>
class CefValueBase : public CefType, public CefValueController::Object {
public:
enum ValueMode {
kReference,
kOwnerWillDelete,
kOwnerNoDelete,
};
CefValueBase(ValueType* value,
void* parent_value,
ValueMode value_mode,
bool read_only,
CefValueController* controller)
: value_(value),
value_mode_(value_mode),
read_only_(read_only),
controller_(controller) {
DCHECK(value_);
DCHECK(!(!reference() && parent_value));
if (!reference() && !controller_.get()) {
controller_ = new CefValueControllerThreadSafe();
SetOwnsController();
}
DCHECK(controller_.get());
if (reference()) {
controller_->AddReference(value_, this);
if (parent_value)
controller_->AddDependency(parent_value, value_);
}
}
CefValueBase(const CefValueBase&) = delete;
CefValueBase& operator=(const CefValueBase&) = delete;
~CefValueBase() override {
if (controller_.get() && value_)
Delete();
}
inline bool reference() const { return (value_mode_ == kReference); }
inline bool will_delete() const { return (value_mode_ == kOwnerWillDelete); }
inline bool read_only() const { return read_only_; }
inline bool detached() { return !controller_.get(); }
inline CefValueController* controller() { return controller_.get(); }
void Delete() {
CEF_VALUE_VERIFY_RETURN_VOID(false);
controller()->Remove(value_, false);
if (will_delete()) {
controller()->RemoveDependencies(value_);
DeleteValue(value_);
}
controller_ = nullptr;
value_ = nullptr;
}
ValueType* Detach(CefValueController* new_controller) WARN_UNUSED_RESULT {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
if (new_controller && !reference()) {
new_controller->TakeFrom(controller());
}
controller()->Remove(value_, false);
controller_ = nullptr;
ValueType* old_val = value_;
value_ = nullptr;
return old_val;
}
inline bool VerifyAttached() {
if (detached()) {
NOTREACHED() << "object accessed after being detached.";
return false;
}
return true;
}
protected:
void OnControlRemoved() override {
DCHECK(controller()->locked());
DCHECK(reference());
controller_ = nullptr;
value_ = nullptr;
}
virtual void DeleteValue(ValueType* value) { delete value; }
inline ValueType* mutable_value() {
DCHECK(value_);
DCHECK(!read_only_);
DCHECK(controller()->locked());
return value_;
}
inline const ValueType& const_value() {
DCHECK(value_);
DCHECK(controller()->locked());
return *value_;
}
inline bool VerifyAccess(bool modify) {
DCHECK(controller()->locked());
if (read_only() && modify) {
NOTREACHED() << "mutation attempted on read-only object.";
return false;
}
return true;
}
inline void SetOwnsController() {
CefValueController::AutoLock lock_scope(controller_.get());
if (lock_scope.verified())
controller_->SetOwner(value_, this);
}
class AutoLock {
public:
explicit AutoLock(CefValueBase* impl, bool modify)
: auto_lock_(impl->controller()) {
verified_ = (auto_lock_.verified() && impl->VerifyAccess(modify));
}
AutoLock(const AutoLock&) = delete;
AutoLock& operator=(const AutoLock&) = delete;
inline bool verified() { return verified_; }
private:
CefValueController::AutoLock auto_lock_;
bool verified_;
};
private:
ValueType* value_;
ValueMode value_mode_;
bool read_only_;
scoped_refptr<CefValueController> controller_;
IMPLEMENT_REFCOUNTING(CefValueBase);
};
#endif