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 Oct 30, 2014
2 parents 846c69f + d705937 commit e06b78b
Show file tree
Hide file tree
Showing 25 changed files with 591 additions and 271 deletions.
2 changes: 1 addition & 1 deletion Autowiring.nuspec
Expand Up @@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>autowiring</id>
<version>0.2.4</version>
<version>0.2.5</version>
<authors>Leap Motion</authors>
<owners>Leap Motion</owners>
<projectUrl>http://autowiring.io</projectUrl>
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Expand Up @@ -43,6 +43,11 @@ if(USE_LIBCXX)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
message("GCC C++11")
endif()

# Also need position-independent code to make things work correctly on certain 64-bit machines
if(${CMAKE_SIZEOF_VOID_P} STREQUAL 8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
endif()
endif()

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
Expand Down
17 changes: 3 additions & 14 deletions autowiring/AnySharedPointer.h
Expand Up @@ -4,24 +4,16 @@

struct AnySharedPointer {
public:
AnySharedPointer(void) {
new (m_space) SharedPointerSlot;
}

explicit AnySharedPointer(const AnySharedPointer& rhs) {
new (m_space) SharedPointerSlot(*rhs.slot());
}
AnySharedPointer(void);
explicit AnySharedPointer(const AnySharedPointer& rhs);

template<class T>
explicit AnySharedPointer(const std::shared_ptr<T>& rhs) {
// Delegate the remainder to the assign operation:
new (m_space) SharedPointerSlotT<T>(rhs);
}

~AnySharedPointer(void) {
// Pass control to the *real* destructor:
slot()->~SharedPointerSlot();
}
~AnySharedPointer(void);

protected:
unsigned char m_space[sizeof(SharedPointerSlot)];
Expand Down Expand Up @@ -115,6 +107,3 @@ template<class T>
inline bool operator==(const std::shared_ptr<T>& lhs, const AnySharedPointer& rhs) {
return rhs == lhs;
}

static_assert(sizeof(AnySharedPointerT<int>) == sizeof(AnySharedPointer), "AnySharedPointer realization cannot have members");
static_assert(!std::is_polymorphic<AnySharedPointer>::value, "The shared pointer cannot be polymorphic, this prevents the root type from being aliased correctly");
36 changes: 31 additions & 5 deletions autowiring/C++11/boost_tuple.h
Expand Up @@ -2,10 +2,36 @@
#pragma once

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>

namespace std {
using boost::tuple;
using boost::get;
using boost::make_tuple;
using boost::tie;
}
template<typename... Ts>
class tuple {
public:
tuple(const Ts&... ele):
m_tuple(ele...)
{}
virtual ~tuple(void){}

bool operator==(const tuple<Ts...>& other) const {
return m_tuple == other.m_tuple;
}

bool operator<(const tuple<Ts...>& other) const {
return m_tuple < other.m_tuple;
}

boost::tuple<Ts...> m_tuple;
};

template<int I, typename... Ts>
auto get(const ::std::tuple<Ts...>& tup) -> decltype(boost::get<I>(tup.m_tuple)) {
return boost::get<I>(tup.m_tuple);
}

template<typename... Ts>
::std::tuple<Ts...> make_tuple(const Ts&... ele) {
return ::std::tuple<Ts...>(ele...);
}

}//namespace std
7 changes: 5 additions & 2 deletions autowiring/C++11/type_index.h
Expand Up @@ -11,8 +11,7 @@ class type_index {
public:
type_index(const type_info& info):
_info(&info)
{
}
{}

bool operator==(const type_index& rhs) const {
return *_info == *rhs._info;
Expand All @@ -22,6 +21,10 @@ class type_index {
return (_info->before(*rhs._info) != 0);
}

bool operator!=(const type_index& rhs) const {
return !operator==(rhs);
}

size_t hash_code() const {
return (size_t)_info;
}
Expand Down
145 changes: 112 additions & 33 deletions autowiring/CoreContext.h
@@ -1,7 +1,6 @@
// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#pragma once
#include "AnySharedPointer.h"
#include "ObjectTraits.h"
#include "AutoFilterDescriptor.h"
#include "AutowirableSlot.h"
#include "AutowiringEvents.h"
Expand All @@ -12,16 +11,18 @@
#include "ContextMember.h"
#include "CreationRules.h"
#include "CurrentContextPusher.h"
#include "EventOutputStream.h"
#include "EventInputStream.h"
#include "EventRegistry.h"
#include "ExceptionFilter.h"
#include "fast_pointer_cast.h"
#include "has_autoinit.h"
#include "InvokeRelay.h"
#include "result_or_default.h"
#include "JunctionBoxManager.h"
#include "EventOutputStream.h"
#include "EventInputStream.h"
#include "ExceptionFilter.h"
#include "member_new_type.h"
#include "ObjectTraits.h"
#include "result_or_default.h"
#include "TeardownNotifier.h"
#include "EventRegistry.h"
#include "TypeRegistry.h"
#include "TypeUnifier.h"

Expand Down Expand Up @@ -146,8 +147,22 @@ class CoreContext:
AnySharedPointer m_value;
};

/// <summary>
/// A proxy context member that knows how to create a factory for a particular type
/// </summary>
/// <remarks>
/// This is an internal routine! Don't try to use it yourself! If you would like to
/// register yourself as a factory producing a certain type, use the static new method
/// which has one of the signatures defined <see ref="factorytype">factorytype</see>
/// </remarks>
template<class T>
class AutoFactory;

template<class T, class Fn>
class AutoFactoryFn;

// This is a list of concrete types, indexed by the true type of each element.
std::vector<ObjectTraits> m_concreteTypes;
std::list<ObjectTraits> m_concreteTypes;

// This is a memoization map used to memoize any already-detected interfaces.
mutable std::unordered_map<std::type_index, MemoEntry> m_typeMemos;
Expand Down Expand Up @@ -177,6 +192,10 @@ class CoreContext:
// Destructor does nothing; this is by design.
std::weak_ptr<Object> m_outstanding;

// Creation rules are allowed to refer to private methods in this type
template<autowiring::construction_strategy, class T, class... Args>
friend struct autowiring::crh;

protected:
// Delayed creation routine
typedef std::shared_ptr<CoreContext> (*t_pfnCreate)(
Expand Down Expand Up @@ -312,7 +331,7 @@ class CoreContext:
/// <summary>
/// Unsynchronized version of FindByType
/// </summary>
void FindByTypeUnsafe(AnySharedPointer& reference) const;
MemoEntry& FindByTypeUnsafe(AnySharedPointer& reference) const;

/// <summary>
/// Recursive locking for Autowire satisfaction search
Expand Down Expand Up @@ -353,13 +372,41 @@ class CoreContext:
/// </summary>
void UnsnoopAutoPacket(const ObjectTraits& traits);

/// <summary>
/// Registers a factory _function_, a lambda which is capable of constructing decltype(fn())
/// </summary>
template<class Fn>
void RegisterFactoryFn(Fn&& fn) {
Inject<AutoFactoryFn<typename std::remove_pointer<decltype(fn())>::type, Fn>>(std::forward<Fn>(fn));
}

/// <summary>
/// Registers a new foreign factory type without explicitly specifying the returned value type
/// </summary>
/// <param name="Factory">The factory type to be added</param>
/// <param name="obj">A reference to the factory proper</param>
template<class Factory>
void RegisterFactory(Factory& obj, autowiring::member_new_type<Factory, autowiring::factorytype::ret_val>) {
RegisterFactoryFn([&obj] { return obj.New(); });
}

template<class Factory>
void RegisterFactory(const Factory&, autowiring::member_new_type<Factory, autowiring::factorytype::none>) {}

public:
// Accessor methods:
bool IsGlobalContext(void) const { return !m_pParent; }
size_t GetMemberCount(void) const { return m_concreteTypes.size(); }
size_t GetChildCount(void) const;
virtual const std::type_info& GetSigilType(void) const = 0;
t_childList::iterator GetBackReference(void) const { return m_backReference; }
const std::shared_ptr<CoreContext>& GetParentContext(void) const { return m_pParent; }

/// <returns>
/// True if the sigil type of this CoreContext matches the specified sigil type
/// </returns>
template<class Sigil>
bool Is(void) const { return GetSigilType() == typeid(Sigil); }

/// <returns>
/// The first child in the set of this context's children
Expand Down Expand Up @@ -443,28 +490,21 @@ class CoreContext:
/// </remarks>
template<typename T, typename... Args>
std::shared_ptr<T> Inject(Args&&... args) {
// Creator proxy, knows how to create the type we intend to inject
typedef autowiring::CreationRules<T, Args...> CreationRules;

// Add this type to the TypeRegistry
(void) RegType<T>::r;

// If T doesn't inherit Object, then we need to compose a unifying type which does
typedef typename SelectTypeUnifier<T>::type TActual;
static_assert(std::is_base_of<Object, TActual>::value, "Constructive type does not implement Object as expected");
static_assert(
std::is_base_of<Object, T>::value || !has_static_new<T>::value,
"If type T provides a static New method, then the constructed type MUST directly inherit Object"
);

// First see if the object has already been injected:
std::shared_ptr<TActual> retVal;
std::shared_ptr<typename CreationRules::TActual> retVal;
FindByType(retVal);
if(retVal)
return retVal;

// We must make ourselves current for the remainder of this call:
CurrentContextPusher pshr(shared_from_this());

// Cannot safely inject while holding the lock, so we have to unlock and then inject
retVal.reset(CreationRules::New<TActual>(std::forward<Args>(args)...));
retVal.reset(CreationRules::New(*this, std::forward<Args>(args)...));

// AutoInit if sensible to do so:
CallAutoInit(*retVal, has_autoinit<T>());
Expand All @@ -481,6 +521,10 @@ class CoreContext:
// Construct.
FindByType(retVal);
}

// Factory registration if sensible to do so, but only after the underlying type has been
// added, so that the proper type can succeed
RegisterFactory(*retVal, autowiring::member_new_type<typename CreationRules::TActual>());
return retVal;
}

Expand All @@ -507,12 +551,6 @@ class CoreContext:
return m_junctionBoxManager->CheckEventOutputStream(typeid(T));
}

/// <returns>
/// True if the sigil type of this CoreContext matches the specified sigil type
/// </returns>
template<class Sigil>
bool Is(void) const { return GetSigilType() == typeid(Sigil); }

/// <summary>
/// Sends AutowiringEvents to build current state
/// </summary>
Expand Down Expand Up @@ -663,11 +701,6 @@ class CoreContext:
/// </remarks>
static std::shared_ptr<CoreContext> CurrentContext(void);

/// <summary>
/// Obtains a pointer to the parent context
/// </summary>
const std::shared_ptr<CoreContext>& GetParentContext(void) const {return m_pParent;}

/// <summary>
/// Filters std::current_exception using any registered exception filters, or rethrows.
/// </summary>
Expand Down Expand Up @@ -771,7 +804,7 @@ class CoreContext:
/// Identical to Autowire, but will not register the passed slot for deferred resolution
/// </summary>
template<class T>
void FindByTypeRecursive(std::shared_ptr<T>& ptr) {
void FindByTypeRecursive(std::shared_ptr<T>& ptr) const {
AnySharedPointerT<T> slot;
FindByTypeRecursive(slot, AutoSearchLambdaDefault());
ptr = slot.slot()->get();
Expand All @@ -781,7 +814,7 @@ class CoreContext:
/// Identical to Autowire, but will not register the passed slot for deferred resolution
/// </summary>
template<class T>
void FindByTypeRecursive(AnySharedPointerT<T>& slot) {
void FindByTypeRecursive(AnySharedPointerT<T>& slot) const {
FindByTypeRecursive(slot, AutoSearchLambdaDefault());
}

Expand Down Expand Up @@ -957,3 +990,49 @@ template<typename T, typename... Sigil>
void CoreContext::AutoRequireMicroBolt(void) {
Inject<MicroBolt<T, Sigil...>>();
}

template<class T>
class CoreContext::AutoFactory
{
public:
virtual T* operator()(CoreContext& ctxt) const = 0;
};

template<class T, class Fn>
class CoreContext::AutoFactoryFn :
public Object,
public CoreContext::AutoFactory<T>
{
public:
AutoFactoryFn(Fn&& fn) :
fn(std::move(fn))
{}

const Fn fn;

T* operator()(CoreContext&) const override { return fn(); }
};

template<class... Ts, class Fn>
class CoreContext::AutoFactoryFn<std::tuple<Ts...>, Fn> :
public Object,
CoreContext::AutoFactory<Ts>...
{
public:
AutoFactoryFn(Fn&& fn) :
fn(std::move(fn))
{}

const Fn fn;
};

template<typename T, typename... Args>
T* autowiring::crh<autowiring::construction_strategy::foreign_factory, T, Args...>::New(CoreContext& ctxt, Args&&... args) {
AnySharedPointerT<CoreContext::AutoFactory<T>> af;
ctxt.FindByType(af);
if(!af)
throw autowiring_error("Attempted to AutoRequire an interface, but failed to find a factory for this interface in the current context");

// Standard factory invocation:
return (*af)(ctxt);
}

0 comments on commit e06b78b

Please sign in to comment.