Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ref simpleobjects #41

Merged
merged 5 commits into from
Aug 8, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions autowiring/AutoSelfUpdate.h
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#pragma once
#include "NewAutoFilter.h"
#include "shared_object.h"
#include "atomic_object.h"

///<summary>
///Enables an automatic self-update when a packet is decorated with the object type.
///Provides the prior object (the last decorated instance) to all subsequent packets.
///</summary>
///<remarks>
///In order to ensure that this method will be consistent with any other AutoFilter calls,
///the object inherits from shared_object, which implements basic locking functionality.
///the object inherits from atomic_object, which implements basic locking functionality.
///</remarks>
template<class object, class lock = std::mutex>
template<class object_type, class lock_type = std::mutex>
class AutoSelfUpdate:
public shared_object<object, lock> {
protected:
using shared_object<object, lock>::get_lock;
using shared_object<object, lock>::get_object;

public atomic_object<object_type, lock_type> {
public:
typedef atomic_object<object_type, lock_type> atomic;
typedef typename atomic::object object;
typedef typename atomic::lock lock;
typedef typename atomic::unlock unlock;
typedef typename atomic::shared shared;

AutoSelfUpdate() {}
AutoSelfUpdate(const shared_object<object, lock>& source) : shared_object<object, lock>(source) {}
AutoSelfUpdate(const object& source) : shared_object<object, lock>(source) {}
using shared_object<object, lock>::operator =;
using shared_object<object, lock>::operator object;
AutoSelfUpdate(const atomic_object<object, lock>& source) : atomic_object<object, lock>(source) {}
AutoSelfUpdate(const object& source) : atomic_object<object, lock>(source) {}
using atomic_object<object, lock>::operator =;
using atomic_object<object, lock>::operator object;

//The distinct type assigned to the prior value of the object
class prior_object: public object {
Expand All @@ -33,8 +34,8 @@ public shared_object<object, lock> {

//Avoid intermediate copy by defining an explicit cast
operator prior_object() const {
std::lock_guard<lock> lock_this(get_lock());
return prior_object(get_object());
std::lock_guard<lock> lock_this(atomic_object<object, lock>::m_lock);
return prior_object(atomic_object<object, lock>::m_object);
}

//Decorates all packets with instances of prior_object
Expand All @@ -44,7 +45,7 @@ public shared_object<object, lock> {

//Updates this object
void AutoGather(const object& update) {
shared_object<object, lock>::operator = (update);
atomic_object<object, lock>::operator = (update);
}

NewAutoFilter<decltype(&AutoSelfUpdate<object>::AutoGather), &AutoSelfUpdate<object>::AutoGather> SelfUpdate;
Expand Down
121 changes: 16 additions & 105 deletions autowiring/atomic_object.h
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
// Copyright (c) 2010 - 2014 Leap Motion. All rights reserved. Proprietary and confidential.
#pragma once
#include MUTEX_HEADER

template<class object, class lock> class shared_object;
#include "unlock_object.h"
template<class object, class lock> class unlock_object;

///<summary>
///This class provides a standard thread-safe wrapper for data structures.
///Because instantiation may be separate from initialization, this class
///also tracks the initialization status.
///</summary>
///<remarks>
///This class supports two modes of use:
/// - Atomic assignments which can be used to create a mutable local copy,
/// or to modify the contents of shared_object.
/// - Held locks, via unlock_object, which will block all other interactions.
/// or to modify the contents of atomic_object.
/// - Held locks, via child classes that manipulate the protected lock member.
///</remarks>
template<class object, class lock = std::mutex>
template<class object_type, class lock_type = std::mutex>
class atomic_object {
friend class shared_object<object, lock>;
friend class unlock_object<object, lock>;
public:
friend class unlock_object<object_type, lock_type>;
typedef object_type object;
typedef lock_type lock;
typedef unlock_object<object, lock> unlock;
typedef std::shared_ptr<atomic_object<object, lock>> shared;

protected:
//CONTRACT: If !m_initialized then m_object == object();
mutable lock m_lock;
object m_object;
bool m_initialized;

public:
///<summary>
///Default constructor yielding initialized() == false.
///</summary>
atomic_object():
m_initialized(false) {};
atomic_object() {};

///<summary>
///Initialization yielding initialized() == source.initialized().
Expand All @@ -44,22 +44,21 @@ class atomic_object {
atomic_object(const atomic_object<object>& source) {
std::lock_guard<lock> lock_source(source.m_lock);
m_object = source.m_object;
m_initialized = source.m_initialized;
}

///<summary>
///Initialization yielding initialized() == true.
///</summary>
atomic_object(const object& source):
m_object(source),
m_initialized(true) {}
m_object(source)
{}

///<summary>
///Assignment yielding initialized() == source.initialized().
///</summary>
///<remarks>
///This method avoids deadlocks due to self-assignment, and intermediate
///copies due to implicit casting.
///This method avoids deadlocks due to self-assignment,
///and intermediate copies due to implicit casting.
///</remarks>
atomic_object<object, lock>& operator = (const atomic_object<object>& source) {
if (this == &source)
Expand All @@ -70,7 +69,6 @@ class atomic_object {
//could deadlock with its counterpart in source.
std::lock(m_lock, source.m_lock);
m_object = source.m_object;
m_initialized = source.m_initialized;
m_lock.unlock();
source.m_lock.unlock();
return *this;
Expand All @@ -81,7 +79,6 @@ class atomic_object {
///</summary>
atomic_object<object, lock>& operator = (const object& source) {
std::lock_guard<lock> lock_this(m_lock);
m_initialized = true;
m_object = source;
return *this;
}
Expand All @@ -93,90 +90,4 @@ class atomic_object {
std::lock_guard<lock> lock_this(m_lock);
return m_object;
}

///<summary>
///Reset using default constructor yielding initialized() == false.
///</summary>
///<return>True if the object was not assigned default values</return>
bool reset() {
std::lock_guard<lock> lock_this(m_lock);
bool was_initialized = m_initialized;
m_initialized = false;
m_object = object();
return was_initialized;
}

///<summary>
///Atomic copy of target to this object, only if initialized() == false.
///</summary>
///<return>True if the object was not assigned default values</return>
bool reset(const object& target) {
std::lock_guard<lock> lock_this(m_lock);
bool was_initialized = m_initialized;
if (!m_initialized)
m_object = target;
m_initialized = true;
return was_initialized;
}

///<return>True if the object was not assigned default values</return>
bool initialized() const {
std::lock_guard<lock> lock_this(m_lock);
return m_initialized;
}

///<summary>
///Atomic copy of this object to target, only if initialized() == true.
///</summary>
///<return>True if the object was not assigned default values</return>
bool initialized(object& target) const {
std::lock_guard<lock> lock_this(m_lock);
if (m_initialized)
target = m_object;
return m_initialized;
}

///<summary>
///If uninitialized uses target for initialization.
///If initialized assigns current value to target.
///</summary>
///<returns> Returns +1 for transfer from target to this, -1 for transfer from this to target</returns>
int transfer(object& target) {
std::lock_guard<lock> lock_this(m_lock);
int val = 0;
if (m_initialized) {
target = m_object;
val = +1;
} else {
m_object = target;
m_initialized = true;
val = -1;
}
return val;
}

///<summary>
///If neither this nor target are uninitialized, no transfer occurs.
///If this is uninitialized and target is not, then this is initialized by target.
///If target is uninitialized and this is, then target is initialized by this.
///If both this and target are initialized, no transfer occurs.
///</summary>
///<returns> Returns +1 for transfer from target to this, -1 for transfer from this to target, else 0</returns>
int transfer(atomic_object<object, lock>& target) {
std::lock(m_lock, target.m_lock);
int val = 0;
if (m_initialized && !target.m_initialized) {
target.m_object = m_object;
target.m_initialized = true;
val = -1;
}
if (!m_initialized && target.m_initialized) {
m_object = target.m_object;
m_initialized = true;
val = +1;
}
m_lock.unlock();
target.m_lock.unlock();
return val;
}
};
Loading