Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
codemercenary committed Apr 22, 2015
2 parents 51186d8 + 01bb10d commit 9cc8722
Show file tree
Hide file tree
Showing 60 changed files with 2,137 additions and 996 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Expand Up @@ -52,9 +52,9 @@ endif()

message(STATUS "Compiler version ${CMAKE_CXX_COMPILER_VERSION}")

# Always use c++11 compiler
# Always use c++11 compiler with hidden visibility
if(NOT WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fvisibility=hidden")
endif()

# Clang needs special additional flags to build with C++11
Expand Down
35 changes: 0 additions & 35 deletions CONTRIBUTORS.txt
Expand Up @@ -117,38 +117,3 @@

======================================================

1. Jared Deckard
Github account: deckar01
Email: jared.deckard@gmail.com

2. Stu Kabakoff
Github account: sakabako
Email: sakabako@gmail.com

3. Yoshihiro Iwanaga
Github account: iwanaga
Email: iwanaga.blackie@gmail.com

4. ARJUNKUMAR KRISHNAMOORTHY
Github account: tk120404
Email: Arjunkumartk@gmail.com

5. Rob Witoff
Github account: witoff
Email: leap@pspct.com

6. Richard Pearson
Github account: catdevnull
Email: github@catdevnull.co.uk

7. Ben Nortier
Github account: bjnortier
Email: bjnortier@gmail.com

8. Andrew Kennedy
Github account: akenn
Email: andrew@akenn.org

9. Victor Norgren
Github account: logotype
Email: victor@logotype.se
2 changes: 1 addition & 1 deletion Doxyfile
Expand Up @@ -32,7 +32,7 @@ PROJECT_NAME = Autowiring
# This could be handy for archiving the generated documentation or
# if some version control system is used.

PROJECT_NUMBER = "0.5.1"
PROJECT_NUMBER = "0.5.2"

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
Expand Down
208 changes: 147 additions & 61 deletions autowiring/AutoConfig.h
@@ -1,93 +1,179 @@
// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#pragma once
#include "AutoConfigBase.h"
#include "Autowired.h"
#include "AutoConfigManager.h"
#include "ConfigRegistry.h"

#include <string>
#include TYPE_INDEX_HEADER

struct AnySharedPointer;

/// \internal
/// <summary>
/// Utility base type for configuration members
/// </summary>
class AutoConfigBase
{
public:
AutoConfigBase(const std::type_info& tiName);

// Key used to identify this config value
const std::string m_key;
};

/// The type underlying the AutoConfig System.
/// Represents a unique type created by the combination of the type and a set of sigils.
/// Responsible for tracking changes to the underlying value and triggering signals,
/// making sure values are inherited correctly from enclosing contexts, and providing
/// a primitive polymorphic get/set interface (void*)
/// <summary>
/// Register an attribute with the AutoConfig system. For example
///
/// AutoConfig<int, struct MyNamespace, struct MyKey> m_myVal;
/// defines the key "MyNamespace.MyKey"
///
/// The Namespace field is optional, so
/// AutoConfig<int, struct MyKey> m_myVal;
/// defines the key "MyKey"
///
/// AutoConfig values can be set from the AutoConfigManager. The string key
/// is used as the identifier for the value
/// </summary>

template<class T, class... TKey>
class AutoConfig:
public AutoConfigBase
class AutoConfigVar:
public AutoConfigVarBase
{
public:
static_assert(sizeof...(TKey) >= 1, "Must provide a key and optionally at least one namespace");
static_assert(sizeof...(TKey) >= 1, "Must provide a key and optionally a set of namespaces");

template<typename t_Arg, typename ...t_Args>
AutoConfig(t_Arg &&arg, t_Args&&... args) :
AutoConfigBase(typeid(ConfigTypeExtractor<TKey...>))
AutoConfigVar(t_Arg &&arg, t_Args&&... args) :
AutoConfigVarBase(typeid(ConfigTypeExtractor<TKey...>), true),
m_value(std::forward<t_Arg>(arg), std::forward<t_Args>(args)...)
{
// Register with config registry
(void)RegConfig<T, TKey...>::r;
(void)AutoConfigVar<T, TKey...>::RegistryEntry;

if (!IsConfigured()){
m_manager->Set(m_key, T(std::forward<t_Arg>(arg), std::forward<t_Args>(args)...));
if (RegistryEntry.m_hasValidator) {
if (!RegistryEntry.validatorInternal()(m_value)) {
throw autowiring_error("Cannot construct AutoConfigVar with a value that fails validation");
}
}

onChangedSignal(*this);
}

AutoConfig() :
AutoConfigBase(typeid(ConfigTypeExtractor<TKey...>))
AutoConfigVar() :
AutoConfigVarBase(typeid(ConfigTypeExtractor<TKey...>)),
m_value()
{
// Register with config registry
(void)RegConfig<T, TKey...>::r;
}
(void)AutoConfigVar<T, TKey...>::RegistryEntry;

const auto ctxt = m_context.lock();
if (!ctxt)
return;

protected:
AutoRequired<AutoConfigManager> m_manager;
//This will wind up being recursive
auto parent = ctxt->GetParentContext();
if (parent != nullptr) {
auto parentVar = parent->template Inject<AutoConfigVar<T, TKey...>>();

public:
const T& operator*() const {
return *m_manager->Get(m_key).template as<T>().get();
}
//Only copy the value if it's initalized. Base::AutoInit will take care of
//the various listing notifications.
if (parentVar->IsConfigured()) {
m_isConfigured = true;
m_value = parentVar->m_value;
}

const T* operator->(void) const {
return m_manager->Get(m_key)->template as<T>().get();
m_parentRegistration = *parentVar += [this](const T& val){
RunValidation(val);
SetInternal(val);
};
}
}

public:

operator const T&() const { return m_value; }
const T* operator->() const { return &m_value; }

void operator=(const T& newValue) {
return m_manager->Set(m_key, newValue);
RunValidation(newValue);

if (m_parentRegistration) {
auto parent_ctxt = m_context.lock()->GetParentContext();
AutowiredFast<AutoConfigVar<T, TKey...>> parentVar(parent_ctxt);
*parentVar -= m_parentRegistration;
m_parentRegistration = nullptr;
OnSetLocally();
}

SetInternal(newValue);
}

/// <returns>
/// True if this configurable field has been satisfied with a value
/// </returns>
bool IsConfigured(void) const {
return m_manager->IsConfigured(m_key);
void Get(void* pValue) const override { *reinterpret_cast<T*>(pValue) = m_value; }
void Set(const void* pValue) override { *this = *reinterpret_cast<const T*>(pValue); }

void SetParsed(const std::string& value) override {
*this = RegistryEntry.template parseInternal<T>(value);
}

// Add a callback for when this config value changes
void operator+=(std::function<void(const T&)>&& fx) {
m_manager->AddCallback(m_key, [fx](const AnySharedPointer& val){
fx(*val.template as<T>().get());
});
t_OnChangedSignal::registration_t* operator+=(std::function<void(const T&)>&& fx) {
return onChangedSignal += [fx](const AutoConfigVarBase& var){
fx(reinterpret_cast<const AutoConfigVar<T,TKey...>*>(&var)->m_value);
};
}

void operator-=(t_OnChangedSignal::registration_t* node) { onChangedSignal -= node; }

private:
T m_value;

void RunValidation(const T& val) {
if (RegistryEntry.m_hasValidator) {
if (!RegistryEntry.validatorInternal()(val)) {
throw autowiring_error("Validator rejected set for config value");
}
}
}

void SetInternal(const T& val) {
m_isConfigured = true;
m_value = val;
onChangedSignal(*this);
}

public:
static std::shared_ptr<AutoConfigVarBase> Inject(const std::shared_ptr<CoreContext>& ctxt, const void* value) {
if (!value)
return ctxt->Inject<AutoConfigVar<T, TKey...>>();
else
return ctxt->Inject<AutoConfigVar<T, TKey...>>(*reinterpret_cast<const T*>(value));
}

static const ConfigRegistryEntryT<T, TKey...> RegistryEntry;
};

template<class T, class... TKey>
const ConfigRegistryEntryT<T, TKey...> AutoConfigVar<T, TKey...>::RegistryEntry(&AutoConfigVar<T, TKey...>::Inject);


/// <summary>
/// Register an attribute with the AutoConfig system. For example
///
/// AutoConfig<int, struct MyNamespace, struct MyKey> m_myVal;
/// defines the key "MyNamespace.MyKey"
///
/// The Namespace field is optional, so
/// AutoConfig<int, struct MyKey> m_myVal;
/// defines the key "MyKey"
///
/// AutoConfig values can also be set from the AutoConfigListing in the same context. The string key
/// is used as the identifier for the value.
/// </summary>
template<class T, class... TKeys>
class AutoConfig : public AutoRequired<AutoConfigVar<T, TKeys...>> {
public:
typedef AutoConfigVar<T, TKeys...> t_Var;

using AutoRequired<t_Var>::operator*;

AutoConfig(const std::shared_ptr<CoreContext>& ctxt = CoreContext::CurrentContext()) :
AutoRequired<t_Var>(ctxt)
{
}

AutoConfig(T&& initialValue, const std::shared_ptr<CoreContext>& ctxt = CoreContext::CurrentContext()) :
AutoRequired<t_Var>(ctxt, std::move(initialValue))
{
if (!(*this)->IsLocal()) {
**this = std::move(initialValue);
}
}

template<typename t_Arg, typename ...t_Args>
explicit AutoConfig(t_Arg&& arg, t_Args&&... args) :
AutoRequired<t_Var>(CoreContext::CurrentContext(), std::forward<t_Arg>(arg), std::forward<t_Args>(args)...)
{
//If we wind up being a reference to an existing value, we may still want to set it...
if (!(*this)->IsLocal()) {
**this = T(std::forward<t_Arg>(arg), std::forward<t_Args>(args)...);
}
}

};
43 changes: 43 additions & 0 deletions autowiring/AutoConfigBase.h
@@ -0,0 +1,43 @@
// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#pragma once
#include "ContextMember.h"
#include "auto_signal.h"

#include <string>
#include "C++11/cpp11.h"
#include TYPE_INDEX_HEADER

struct AnySharedPointer;

/// \internal
/// <summary>
/// Utility base type & interface for configuration members
/// </summary>
class AutoConfigVarBase : public ContextMember
{
public:
AutoConfigVarBase(const std::type_info& tiName, bool configured = false);
void AutoInit();

// Key used to identify this config value
const std::string m_key;

// True if this config was set at all
bool IsConfigured() const { return m_isConfigured; }
bool IsInherited() const { return m_parentRegistration != nullptr; }
//True if the config was set from within this context (isn't inherited)
bool IsLocal() const { return IsConfigured() && !IsInherited(); }

typedef autowiring::signal<void(const AutoConfigVarBase& val)> t_OnChangedSignal;
t_OnChangedSignal onChangedSignal;

virtual void Get(void* pValue) const = 0;
virtual void Set(const void* pValue) = 0;
virtual void SetParsed(const std::string& value) = 0;

protected:
void OnSetLocally();

bool m_isConfigured;
t_OnChangedSignal::registration_t* m_parentRegistration;
};

0 comments on commit 9cc8722

Please sign in to comment.