diff --git a/.gitignore b/.gitignore
index f02396562..0dd1d95b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,3 +38,4 @@ lib/*.*
autowiring-*-*.zip
_CPack_Packages
win64/Autowiring.nuspec
+Autowiring.nuspec
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5900244f2..608d42b07 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -97,7 +97,9 @@ if(NOT WIN32 AND autowiring_BUILD_64)
endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
-include(CMakeModules/pch.cmake)
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules")
+include(AddPCH)
+include(ConditionalSources)
if(autowiring_BUILD_ARM)
# Currently cannot build Autonet for ARM, so default this off on that platform
diff --git a/CMakeModules/pch.cmake b/CMakeModules/pch.cmake
deleted file mode 100644
index 0fcf7767b..000000000
--- a/CMakeModules/pch.cmake
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-# Adds a precompiled header
-MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
- if(MSVC)
- set_source_files_properties(${PrecompiledSource}
- PROPERTIES
- COMPILE_FLAGS "/Yc${PrecompiledHeader}"
- )
- foreach( src_file ${${SourcesVar}} )
- set_source_files_properties(
- ${src_file}
- PROPERTIES
- COMPILE_FLAGS "/Yu${PrecompiledHeader}"
- )
- endforeach( src_file ${${SourcesVar}} )
- list(APPEND ${SourcesVar} ${PrecompiledHeader} ${PrecompiledSource})
- endif(MSVC)
-ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)
-
-function(ADD_MSVC_DISABLED_FILES SourceGroupName SourcesVar ...)
- if(WIN32)
- set_source_files_properties( ${ARGN} PROPERTIES HEADER_FILE_ONLY TRUE )
- source_group(${SourceGroupName} FILES ${ARGN})
- set(${SourcesVar} ${${SourcesVar}} ${ARGN} PARENT_SCOPE)
- endif(WIN32)
-endfunction(ADD_MSVC_DISABLED_FILES)
\ No newline at end of file
diff --git a/autowiring/AnySharedPointer.h b/autowiring/AnySharedPointer.h
index d53876586..62220129f 100644
--- a/autowiring/AnySharedPointer.h
+++ b/autowiring/AnySharedPointer.h
@@ -72,12 +72,19 @@ struct AnySharedPointer {
return **this = *rhs;
}
+ ///
+ /// Convenience overload for slot assignment
+ ///
+ SharedPointerSlot& operator=(const SharedPointerSlot& rhs) {
+ return *slot() = rhs;
+ }
+
///
/// Convenience overload for shared pointer assignment
///
template
- SharedPointerSlotT& operator=(const std::shared_ptr& rhs) {
- return **this = rhs;
+ void operator=(const std::shared_ptr& rhs) {
+ **this = rhs;
}
};
@@ -97,7 +104,7 @@ class AnySharedPointerT:
SharedPointerSlotT* slot(void) { return (SharedPointerSlotT*) m_space; }
const SharedPointerSlotT* slot(void) const { return (const SharedPointerSlotT*) m_space; }
- T& operator*(void) { return **slot(); }
+ T& operator*(void) { return *slot()->get(); }
const T& operator*(void) const { return **slot(); }
T* operator->(void) { return slot()->get().get(); }
diff --git a/autowiring/AutoCheckout.h b/autowiring/AutoCheckout.h
index 1dd136a29..1d6adc4a0 100644
--- a/autowiring/AutoCheckout.h
+++ b/autowiring/AutoCheckout.h
@@ -1,5 +1,6 @@
// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#pragma once
+#include "auto_id.h"
#include
#include MEMORY_HEADER
@@ -8,21 +9,19 @@ class AutoPacket;
template
class AutoCheckout {
public:
- typedef void (AutoPacket::*t_completion)(bool, const std::type_info&, const std::type_info&);
+ typedef void (AutoPacket::*t_completion)(bool, const std::type_info&);
AutoCheckout(void) :
m_parent(nullptr),
m_val(nullptr),
m_ready(false),
- m_source(&typeid(void)),
completion(nullptr)
{}
- AutoCheckout(AutoPacket& parent, const std::shared_ptr& val, t_completion completion, const std::type_info& source = typeid(void)) :
+ AutoCheckout(AutoPacket& parent, const std::shared_ptr& val, t_completion completion) :
m_parent(&parent),
m_val(val),
m_ready(false),
- m_source(&source),
completion(completion)
{}
@@ -30,7 +29,6 @@ class AutoCheckout {
m_parent(rhs.m_parent),
m_val(rhs.m_val),
m_ready(rhs.m_ready),
- m_source(rhs.m_source),
completion(rhs.completion)
{
rhs.m_parent = nullptr;
@@ -40,7 +38,7 @@ class AutoCheckout {
~AutoCheckout(void) {
if(m_val)
- (m_parent->*completion)(m_ready, typeid(T), *m_source);
+ (m_parent->*completion)(m_ready, typeid(auto_id));
}
private:
@@ -50,7 +48,6 @@ class AutoCheckout {
AutoPacket* m_parent;
std::shared_ptr m_val;
mutable bool m_ready;
- const std::type_info* m_source;
t_completion completion;
public:
@@ -73,7 +70,6 @@ class AutoCheckout {
m_parent = rhs.m_parent;
m_val = rhs.m_val;
m_ready = rhs.m_ready;
- m_source = rhs.m_source;
completion = rhs.completion;
rhs.m_parent = nullptr;
diff --git a/autowiring/AutoConfig.h b/autowiring/AutoConfig.h
new file mode 100644
index 000000000..15004e8e5
--- /dev/null
+++ b/autowiring/AutoConfig.h
@@ -0,0 +1,76 @@
+// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
+#pragma once
+#include "Autowired.h"
+#include "AutoConfigManager.h"
+#include "ConfigRegistry.h"
+
+#include
+#include TYPE_INDEX_HEADER
+
+struct AnySharedPointer;
+
+///
+/// Utility base type for configuration members
+///
+class AutoConfigBase
+{
+public:
+ AutoConfigBase(const std::type_info& tiName);
+
+ // Key used to identify this config value
+ const std::string m_key;
+};
+
+///
+/// Register an attribute with the AutoConfig system. For example
+///
+/// AutoConfig m_myVal;
+/// defines the key "MyNamespace.MyKey"
+///
+/// The Namespace field is optional, so
+/// AutoConfig 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
+///
+template
+class AutoConfig:
+ public AutoConfigBase
+{
+public:
+ static_assert(sizeof...(TKey)==1 || sizeof...(TKey)==2, "Must provide a key and optional namespace");
+
+ AutoConfig(void) :
+ AutoConfigBase(typeid(ConfigTypeExtractor))
+ {
+ // Register with config registry
+ (void)RegConfig::r;
+ }
+
+protected:
+ AutoRequired m_manager;
+
+public:
+ const T& operator*() const {
+ return *m_manager->Get(m_key).template as().get();
+ }
+
+ const T* operator->(void) const {
+ return m_manager->Get(m_key)->template as().get();
+ }
+
+ ///
+ /// True if this configurable field has been satisfied with a value
+ ///
+ bool IsConfigured(void) const {
+ return m_manager->IsConfigured(m_key);
+ }
+
+ // Add a callback for when this config value changes
+ void operator+=(std::function&& fx) {
+ m_manager->AddCallback(m_key, [fx](const AnySharedPointer& val){
+ fx(*val.template as().get());
+ });
+ }
+};
diff --git a/autowiring/AutoConfigManager.h b/autowiring/AutoConfigManager.h
new file mode 100644
index 000000000..7b0b93e9e
--- /dev/null
+++ b/autowiring/AutoConfigManager.h
@@ -0,0 +1,119 @@
+// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
+#pragma once
+#include "autowiring_error.h"
+#include "ConfigRegistry.h"
+#include
+#include
+#include
+#include STL_UNORDERED_MAP
+#include STL_UNORDERED_SET
+#include MEMORY_HEADER
+
+struct AnySharedPointer;
+
+class AutoConfigManager:
+ public ContextMember
+{
+public:
+ AutoConfigManager();
+ virtual ~AutoConfigManager();
+
+ // Callback function type
+ typedef std::function t_callback;
+
+ // Validator function type
+ typedef std::function t_validator;
+
+private:
+ // local map of the config registry
+ static const std::unordered_map s_registry;
+
+ // map of validators registered for a key
+ static const std::unordered_map> s_validators;
+
+ // lock for all members
+ std::mutex m_lock;
+
+ // Values of AutoConfigs in this context
+ std::unordered_map m_values;
+
+ // Set of keys for values set from this context
+ std::unordered_set m_setHere;
+
+ // map of callbacks registered for a key
+ std::unordered_map> m_callbacks;
+
+public:
+ ///
+ /// Check if this key has been set
+ ///
+ bool IsConfigured(const std::string& key);
+
+ ///
+ /// Check if this key was inherited from an ancestor context
+ ///
+ bool IsInherited(const std::string& key);
+
+ ///
+ /// Get a reference to where the config value is stored
+ ///
+ ///
+ /// This method will throw an exception if the specified name cannot be found as a configurable value
+ /// in the application, or if the specified value type does not match the type expected by this field
+ ///
+ AnySharedPointer& Get(const std::string& key);
+
+ ///
+ /// Assigns the specified value to an AnySharedPointer slot
+ ///
+ ///
+ /// This method will throw an exception if the specified name cannot be found as a configurable value
+ /// in the application, or if the specified value type does not match the type expected by this field
+ ///
+ template
+ void Set(const std::string& key, const T& value) {
+
+ if (!s_registry.count(key)) {
+ std::stringstream ss;
+ ss << "No configuration found for key '" << key << "'";
+ throw autowiring_error(ss.str());
+ }
+
+ if (!s_registry.find(key)->second->verifyType(typeid(T))) {
+ std::stringstream ss;
+ ss << "Attempting to set config '" << key << "' with incorrect type '"
+ << autowiring::demangle(typeid(T)) << "'";
+ throw autowiring_error(ss.str());
+ }
+
+ // Set value in this AutoConfigManager
+ SetRecursive(key, AnySharedPointer(std::make_shared(value)));
+ }
+
+ ///
+ /// Overload for c-style string. Converts to std::string
+ ///
+ void Set(const std::string& key, const char* value);
+
+ ///
+ /// Coerces the string representation of the specified field to the correct value type
+ ///
+ ///
+ /// This method will throw an exception if there is no string converter available on this type
+ ///
+ ///
+ /// True if value successfully set, False if key not found.
+ ///
+ bool SetParsed(const std::string& key, const std::string& value);
+
+ // Add a callback for when key is changed in this context
+ void AddCallback(const std::string& key, t_callback&& fx);
+
+private:
+ // Handles setting a value recursivly to all child contexts
+ void SetRecursive(const std::string& key, AnySharedPointer value);
+
+ // Set a value in this manager, call callbacks
+ // Must hold m_lock when calling this
+ void SetInternal(const std::string& key, const AnySharedPointer& value);
+};
diff --git a/autowiring/AutoFilterDescriptor.h b/autowiring/AutoFilterDescriptor.h
index 0d1ebc65f..1ee3e8090 100644
--- a/autowiring/AutoFilterDescriptor.h
+++ b/autowiring/AutoFilterDescriptor.h
@@ -4,7 +4,6 @@
#include "AutoPacket.h"
#include "auto_arg.h"
#include "CallExtractor.h"
-#include "DataFlow.h"
#include "Decompose.h"
#include "has_autofilter.h"
#include "is_shared_ptr.h"
@@ -23,23 +22,20 @@ struct AutoFilterDescriptorInput {
AutoFilterDescriptorInput(void) :
is_input(false),
is_output(false),
- is_optional(false),
is_shared(false),
ti(nullptr)
{}
template
- AutoFilterDescriptorInput(auto_arg&& traits) :
+ AutoFilterDescriptorInput(auto_arg*) :
is_input(auto_arg::is_input),
is_output(auto_arg::is_output),
- is_optional(auto_arg::is_optional),
is_shared(auto_arg::is_shared),
ti(&typeid(typename auto_arg::id_type))
{}
const bool is_input;
const bool is_output;
- const bool is_optional;
const bool is_shared;
const std::type_info* const ti;
@@ -50,7 +46,7 @@ struct AutoFilterDescriptorInput {
template
struct rebind {
operator AutoFilterDescriptorInput() {
- return auto_arg();
+ return AutoFilterDescriptorInput((auto_arg*)nullptr);
}
};
};
@@ -65,18 +61,15 @@ struct AutoFilterDescriptorStub {
m_deferred(false),
m_arity(0),
m_requiredCount(0),
- m_optionalCount(0),
m_pCall(nullptr)
{}
AutoFilterDescriptorStub(const AutoFilterDescriptorStub& rhs) :
m_pType(rhs.m_pType),
m_pArgs(rhs.m_pArgs),
- m_dataMap(rhs.m_dataMap),
m_deferred(rhs.m_deferred),
m_arity(rhs.m_arity),
m_requiredCount(rhs.m_requiredCount),
- m_optionalCount(rhs.m_optionalCount),
m_pCall(rhs.m_pCall)
{}
@@ -94,24 +87,13 @@ struct AutoFilterDescriptorStub {
m_deferred(deferred),
m_arity(0),
m_requiredCount(0),
- m_optionalCount(0),
m_pCall(pCall)
{
for(auto pArg = m_pArgs; *pArg; pArg++) {
m_arity++;
- autowiring::DataFlow& data = m_dataMap[*pArg->ti];
-
- // DEFAULT: All data is broadcast
- data.broadcast = true;
- data.input = pArg->is_input;
- data.output = pArg->is_output;
- if (pArg->is_input) {
- if (pArg->is_optional) {
- ++m_optionalCount;
- continue;
- }
+
+ if (pArg->is_input)
++m_requiredCount;
- }
}
}
@@ -121,10 +103,8 @@ struct AutoFilterDescriptorStub {
// This subscriber's argument types
// NOTE: This is a reference to a static generated list,
- // therefor it MUST be const and MUST be shallow-copied.
+ // therefore it MUST be const and MUST be shallow-copied.
const AutoFilterDescriptorInput* m_pArgs;
- typedef std::unordered_map FlowMap;
- FlowMap m_dataMap;
// Set if this is a deferred subscriber. Deferred subscribers cannot receive immediate-style
// decorations, and have additional handling considerations when dealing with non-copyable
@@ -136,12 +116,9 @@ struct AutoFilterDescriptorStub {
// correctly.
size_t m_arity;
- // The number of argumetns declared to be required:
+ // The number of arguments declared to be required:
size_t m_requiredCount;
- // The number of arguments declared to be optional:
- size_t m_optionalCount;
-
// The first argument of this static global is void*, but it is expected that the argument
// that will actually be passed is of a type corresponding to the member function bound
// by this operation. Strong guarantees must be made that the types passed into this routine
@@ -153,7 +130,6 @@ struct AutoFilterDescriptorStub {
const std::type_info* GetType() const { return m_pType; }
size_t GetArity(void) const { return m_arity; }
size_t GetRequiredCount(void) const { return m_requiredCount; }
- size_t GetOptionalCount(void) const { return m_optionalCount; }
const AutoFilterDescriptorInput* GetAutoFilterInput(void) const { return m_pArgs; }
bool IsDeferred(void) const { return m_deferred; }
const std::type_info* GetAutoFilterTypeInfo(void) const { return m_pType; }
@@ -173,18 +149,6 @@ struct AutoFilterDescriptorStub {
return nullptr;
}
- ///
- /// Copies the data flow information for the argument type to the flow argument.
- ///
- /// true when the argument type is found
- autowiring::DataFlow GetDataFlow(const std::type_info* argType) const {
- FlowMap::const_iterator data = m_dataMap.find(*argType);
- if (data != m_dataMap.end()) {
- return data->second;
- }
- return autowiring::DataFlow(); //DEFAULT: No flow
- }
-
/// A call lambda wrapping the associated subscriber
///
/// Parameters for the associated subscriber are obtained by querying the packet.
@@ -192,44 +156,6 @@ struct AutoFilterDescriptorStub {
/// subscribers, or an exception will be thrown.
///
t_extractedCall GetCall(void) const { return m_pCall; }
-
- ///
- /// Sends or receives broadcast instances of the input or output type.
- ///
- ///
- /// The dataType must declared by the AutoFilter method for this call to have an effect.
- ///
- /// specifies the data type (input or output) to broadcast
- /// when false disables broadcasting
- void Broadcast(const std::type_info* dataType, bool enable = true) {
- FlowMap::iterator flowFind = m_dataMap.find(*dataType);
- if (flowFind == m_dataMap.end())
- return;
- autowiring::DataFlow& flow = flowFind->second;
- flow.broadcast = enable;
- }
-
- ///
- /// Creates a data half-pipe from this node to the target node for the specifed data.
- ///
- ///
- /// A complete pipe requires that both the input and output nodes are modified.
- /// This method only modifies this node - the other half-pipe requires a call to the other node.
- /// The dataType must declared by the AutoFilter method for this call to have an effect.
- ///
- /// specifies the data type (input or output) to pipe
- /// determines the target node that will receive the data
- /// when false removes a pipe, if it exists
- void HalfPipe(const std::type_info* dataType, const std::type_info* nodeType, bool enable = true) {
- FlowMap::iterator flowFind = m_dataMap.find(*dataType);
- if (flowFind == m_dataMap.end())
- return;
- autowiring::DataFlow& flow = flowFind->second;
- if (enable)
- flow.halfpipes.insert(*nodeType);
- else
- flow.halfpipes.erase(*nodeType);
- }
};
///
@@ -339,22 +265,19 @@ struct AutoFilterDescriptor:
// capture it in a template processing context. Hopefully this can be changed
// once MSVC adopts constexpr.
AnySharedPointer(
- std::shared_ptr(
- pfn,
- [](decltype(pfn)){}
+ std::shared_ptr(
+ (void*)pfn,
+ [](void*){}
)
),
// The remainder is fairly straightforward
- CallExtractor(),
- &CallExtractor::Call
- )
- {}
+ &typeid(pfn),
- // Convenience overload:
- template
- AutoFilterDescriptor(RetType(&pfn)(Args...)):
- AutoFilterDescriptor(&pfn)
+ CallExtractor::template Enumerate::types,
+ false,
+ CallExtractor::Call
+ )
{}
protected:
diff --git a/autowiring/AutoMerge.h b/autowiring/AutoMerge.h
deleted file mode 100644
index 35767a6d0..000000000
--- a/autowiring/AutoMerge.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
-#pragma once
-
-#include "AutoPacket.h"
-#include STL_UNORDERED_SET
-
-///
-/// Extracts all instances of a type from a slave-context on each execution of that context.
-///
-///
-/// It is expected that the merged data is desired in another context.
-/// This process is facilitated the AutoStile and AutoMergeStile.
-///
-template
-class AutoMerge
-{
-protected:
- Autowired m_factory;
-
-public:
- typedef std::unordered_map> merge_data;
- typedef std::function merge_call;
-
- /// Final call in slave context to extract all data of the specified type
- ///
- /// This will only gather data that is directed to this source, identified by the gather type.
- ///
- void AutoFilter(const AutoPacket& packet, const merge_call& call) {
- if (!call)
- return;
-
- // Gather relevant data of the specified type
- merge_data unordered = packet.GetAll(typeid(typename SelectTypeUnifier>::type));
- merge_data broadcast = packet.GetAll(typeid(void));
- unordered.insert(broadcast.begin(), broadcast.end());
-
- // Merge with prior merged data
- if (packet.Has()) {
- merge_data priordata = packet.Get();
- unordered.insert(priordata.begin(), priordata.end());
- }
-
- // Call the master function decorating this packet
- call(unordered);
- }
-
- /// Enables a pipe from source to AutoMerge, and disables broadcasting by source.
- /// Removes pipe and reinstates broadcast when false
- ///
- /// Parameters have the same meaning as in AutoPacketFactory PipeData and BroadcastData
- ///
- template
- void PipeToMerge(const std::type_info* dataType = nullptr, bool enable = true) {
- if (!m_factory)
- return;
- m_factory->BroadcastDataOut