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 Mar 14, 2015
2 parents e1606cf + 7d4bc3b commit 109b87e
Show file tree
Hide file tree
Showing 36 changed files with 920 additions and 313 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Expand Up @@ -9,6 +9,9 @@ before_install:
# Enforce Leap Motion copyright notice
- ./scripts/copyright_check.sh

# Verify that our version numbers all line up
- ./scripts/version_number_updated.sh

# g++4.8.1
- if [ "$CXX" == "g++" ]; then
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
Expand Down
8 changes: 0 additions & 8 deletions AutowiringConfig.h.in
Expand Up @@ -10,11 +10,3 @@

// Building for ARM?
#cmakedefine01 autowiring_BUILD_ARM

// Are we linking with C++11 STL?
#cmakedefine01 autowiring_USE_LIBCXX
#if autowiring_USE_LIBCXX
#define AUTOWIRING_USE_LIBCXX 1
#else
#define AUTOWIRING_USE_LIBCXX 0
#endif
46 changes: 6 additions & 40 deletions CMakeLists.txt
Expand Up @@ -40,33 +40,6 @@ if(EXTERNAL_LIBRARY_DIR)
list(APPEND CMAKE_INCLUDE_PATH ${EXTERNAL_LIBRARY_DIR})
endif()

if(APPLE)
# Offer option for autowiring_USE_LIBCXX
# Check for existing definition of autowiring_USE_LIBCXX
if(NOT DEFINED autowiring_USE_LIBCXX)
option(autowiring_USE_LIBCXX "Build Autowiring using c++11" ON)
else()
if(NOT autowiring_USE_LIBCXX)
message("Parent project has set autowiring_USE_LIBCXX = OFF -> Build Autowiring using c++98")
endif()
endif()

# Install autoboost when using libstdc++
if(autowiring_USE_LIBCXX)
set(autowiring_INSTALL_AUTOBOOST OFF)
else()
set(autowiring_INSTALL_AUTOBOOST ON)
endif()
else()
# Always use libc++ on other platforms
set(autowiring_USE_LIBCXX ON)

# Don't install autoboost unless otherwise specified
if(NOT DEFINED autowiring_INSTALL_AUTOBOOST)
set(autowiring_INSTALL_AUTOBOOST OFF)
endif()
endif()

if(CMAKE_COMPILER_IS_GNUCC)
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8")
message(FATAL_ERROR "GCC version 4.8 minimum is required to build Autowiring")
Expand All @@ -86,16 +59,9 @@ endif()

# Clang needs special additional flags to build with C++11
if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
# Apple needs us to tell it that we're using libc++, or it will try to use libstdc++ instead
if(autowiring_USE_LIBCXX)
message(STATUS "AppleClang C++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
else()
message(STATUS "AppleClang C++11 with libstdc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libstdc++")
endif()
message(STATUS "AppleClang C++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
message(STATUS "Clang C++11")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lstdc++")
Expand Down Expand Up @@ -223,9 +189,9 @@ if(NOT AUTOWIRING_IS_EMBEDDED)
COMPONENT autowiring
FILES_MATCHING PATTERN "*.h"
)

# Install autoboost headers
if(autowiring_INSTALL_AUTOBOOST)
# Install autoboost headers on ARM, which still requires them
if(autowiring_BUILD_ARM)
install(
DIRECTORY ${PROJECT_SOURCE_DIR}/contrib/autoboost/autoboost
DESTINATION include
Expand Down
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.4.2"
PROJECT_NUMBER = "0.5.0"

# 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
27 changes: 10 additions & 17 deletions autowiring-configVersion.cmake.in
Expand Up @@ -12,9 +12,6 @@ if(autowiring_DEBUG)

message(STATUS "Installed CMAKE_SIZEOF_VOID_P: @CMAKE_SIZEOF_VOID_P@")
message(STATUS "Configured CMAKE_SIZEOF_VOID_P: ${CMAKE_SIZEOF_VOID_P}")

message(STATUS "Installed using autowiring_USE_LIBCXX: @autowiring_USE_LIBCXX@")
message(STATUS "Configured using autowiring_USE_LIBCXX: ${autowiring_USE_LIBCXX}")
endif()

# If the customer has an override architecture requirement, use that
Expand Down Expand Up @@ -73,26 +70,22 @@ endforeach()
# Determine whether the user's request (either implied or explicit) for libstdc++ can
# be met by this verison of Autowiring
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
# If this value isn't defined, then we assume the user's request is "on"
if(NOT DEFINED autowiring_USE_LIBCXX)
SET(autowiring_USE_LIBCXX ON)
# Require that the user either omit autowiring_USE_LIBCXX or leave it off
if(DEFINED autowiring_USE_LIBCXX)
if(autowiring_USE_LIBCXX)
message(WARNING "Autowiring no longer supports libstdc++, autowiring_USE_LIBCXX is therefore a deprecated flag")
else()
message(STATUS "Autowiring no longer supports libstdc++")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
set(PACKAGE_VERSION_UNSUITABLE TRUE)
return()
endif()
endif()

if(autowiring_DEBUG)
message(STATUS "Installed autowiring_USE_LIBCXX: @autowiring_USE_LIBCXX@")
message(STATUS "Configured autowiring_USE_LIBCXX: ${autowiring_USE_LIBCXX}")
endif()

# Our built version must be the same as the requested version. If it's not, then we are
# not a match for the user's request
if((NOT ${autowiring_USE_LIBCXX} AND @autowiring_USE_LIBCXX@) OR (${autowiring_USE_LIBCXX} AND NOT @autowiring_USE_LIBCXX@))
if(autowiring_DEBUG)
message("User C++ runtime library request incompatible with locally built version")
endif()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
set(PACKAGE_VERSION_UNSUITABLE TRUE)
return()
endif()
endif()

if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
Expand Down
49 changes: 34 additions & 15 deletions autowiring/AutoPacket.h
Expand Up @@ -161,6 +161,11 @@ class AutoPacket:
/// </summary>
static void ThrowNotDecoratedException(const DecorationKey& key);

/// <summary>
/// Throws a formatted runtime error corresponding to the case where a decoration was demanded and more than one such decoration was present
/// </summary>
static void ThrowMultiplyDecoratedException(const DecorationKey& key);

public:
/// <returns>
/// The number of distinct decoration types on this packet
Expand Down Expand Up @@ -210,11 +215,20 @@ class AutoPacket:
/// </remarks>
template<class T>
bool Get(const T*& out, int tshift=0) const {
const DecorationDisposition* pDisposition = GetDisposition(DecorationKey(auto_id<T>::key(), false, tshift));
DecorationKey key(auto_id<T>::key(), false, tshift);
const DecorationDisposition* pDisposition = GetDisposition(key);
if (pDisposition) {
if (pDisposition->m_decorations.size() == 1) {
switch (pDisposition->m_decorations.size()) {
case 0:
// No shared pointer decorations available, we have to try something else
break;
case 1:
// Single decoration, we can do what the user is asking
out = static_cast<const T*>(pDisposition->m_decorations[0]->ptr());
return true;
default:
ThrowMultiplyDecoratedException(key);
break;
}

// Second-chance satisfaction with an immediate
Expand All @@ -238,18 +252,31 @@ class AutoPacket:
/// <remarks>
/// This specialization cannot be used to obtain a decoration which has been attached to this packet via
/// DecorateImmediate.
///
/// This method will throw an exception if the requested decoration is multiply present on the packet
/// </remarks>
template<class T>
bool Get(const std::shared_ptr<const T>*& out, int tshift=0) const {
// Decoration must be present and the shared pointer itself must also be present
const DecorationDisposition* pDisposition = GetDisposition(DecorationKey(auto_id<T>::key(), true, tshift));
if (!pDisposition || pDisposition->m_decorations.size() != 1) {
DecorationKey key(auto_id<T>::key(), true, tshift);
const DecorationDisposition* pDisposition = GetDisposition(key);
if (!pDisposition) {
out = nullptr;
return false;
}

out = &pDisposition->m_decorations[0]->as_unsafe<const T>();
return true;
switch (pDisposition->m_decorations.size()) {
case 0:
// Simple non-availability, trivial return
out = nullptr;
return false;
case 1:
// Single decoration available, we can return here
out = &pDisposition->m_decorations[0]->as_unsafe<const T>();
return true;
default:
ThrowMultiplyDecoratedException(key);
return false;
}
}

/// <summary>
Expand Down Expand Up @@ -431,18 +458,10 @@ class AutoPacket:
}

// Now trigger a rescan to hit any deferred, unsatisfiable entries:
#if autowiring_USE_LIBCXX
for (const std::type_info* ti : {&auto_id<T>::key(), &auto_id<Ts>::key()...}) {
MarkUnsatisfiable(DecorationKey(*ti, true, 0));
MarkUnsatisfiable(DecorationKey(*ti, false, 0));
}
#else
bool dummy[] = {
(MarkUnsatisfiable(DecorationKey(auto_id<T>::key(), false, 0)), false),
(MarkUnsatisfiable(DecorationKey(auto_id<Ts>::key(), false, 0)), false)...
};
(void)dummy;
#endif
}),
PulseSatisfaction(pTypeSubs, 1 + sizeof...(Ts));
}
Expand Down
17 changes: 15 additions & 2 deletions autowiring/AutowirableSlot.h
Expand Up @@ -84,6 +84,11 @@ class DeferrableAutowiring:
m_pFlink = pFlink;
}

/// <returns>
/// The context corresponding to this slot, if it hasn't already expired
/// </returns>
std::shared_ptr<CoreContext> GetContext(void) const { return m_context.lock(); }

/// <returns>
/// The type on which this deferred slot is bound
/// </returns>
Expand Down Expand Up @@ -184,15 +189,23 @@ class AutowirableSlot:
// where we can guarantee that the type will be completely defined, because the user is about
// to make use of this type.
(void) autowiring::fast_pointer_cast_initializer<T, CoreObject>::sc_init;
return get();

auto retVal = get();
if (!retVal)
throw autowiring_error("Attempted to dereference a null autowired field");
return retVal;
}

T& operator*(void) const {
auto retVal = get();
if (!retVal)
throw autowiring_error("Attempted to dereference a null autowired field");

// We have to initialize here, in the operator context, because we don't actually know if the
// user will be making use of this type.
(void) autowiring::fast_pointer_cast_initializer<T, CoreObject>::sc_init;

return *get();
return *retVal;
}

using AnySharedPointer::operator=;
Expand Down
68 changes: 67 additions & 1 deletion autowiring/Autowired.h
@@ -1,5 +1,6 @@
// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#pragma once
#include "auto_signal.h"
#include "AutowirableSlot.h"
#include "Decompose.h"
#include "GlobalCoreContext.h"
Expand Down Expand Up @@ -120,11 +121,15 @@ class Autowired:
}

~Autowired(void) {
// Unlink all signal entries
for (auto& unlinkEntry : m_unlinkEntries)
*unlinkEntry.relay -= unlinkEntry.node;

if(m_pFirstChild == this)
// Tombstoned, nothing to do:
return;

// Need to ensure that nobody tries to autowire us while we are tearing down:
// Need to ensure that nobody tries to fill us while we are tearing down:
this->CancelAutowiring();

// And now we destroy our deferrable autowiring collection:
Expand All @@ -139,6 +144,23 @@ class Autowired:
// which will be the first member registered via NotifyWhenAutowired.
std::atomic<AutowirableSlot<T>*> m_pFirstChild;

struct unlink_entry
{
unlink_entry(
autowiring::signal_relay* relay,
autowiring::internal::signal_node_base* node
) :
relay(relay),
node(node)
{}

autowiring::signal_relay* relay;
autowiring::internal::signal_node_base* node;
};

// The set of all nodes that will have to be unlinked when this field is torn down
std::vector<unlink_entry> m_unlinkEntries;

public:
operator const std::shared_ptr<T>&(void) const {
return
Expand All @@ -156,7 +178,37 @@ class Autowired:
operator T*(void) const {
return this->operator const std::shared_ptr<T>&().get();
}

template<typename... Args>
struct signal_relay {
signal_relay(Autowired<T>& owner, autowiring::signal_relay_t<Args...>& relay) :
owner(owner),
relay(relay)
{}

private:
Autowired<T>& owner;
autowiring::signal_relay_t<Args...>& relay;

public:
void operator+=(std::function<void(Args...)>&& fn) {
owner.m_unlinkEntries.push_back(
unlink_entry(
&relay,
relay += std::move(fn)
)
);
}
};

template<typename... Args>
signal_relay<Args...> operator()(autowiring::signal<void(Args...)> T::*handler) {
auto ctxt = AutowirableSlot<T>::GetContext();
if (!ctxt)
throw std::runtime_error("Attempted to attach a signal to an Autowired field in a context that was already destroyed");
return {*this, ctxt->RelayForType(handler)};
}

/// <summary>
/// Assigns a lambda function to be called when the dependency for this slot is autowired.
/// </summary>
Expand Down Expand Up @@ -331,6 +383,20 @@ class AutowiredFast:
return std::shared_ptr<T>::get();
}

T* operator->(void) const {
auto* retVal = std::shared_ptr<T>::operator->();
if (!retVal)
throw autowiring_error("Attempted to dereference a null autowired field");
return retVal;
}

T& operator*(void) const {
T* retVal = std::shared_ptr<T>::get();
if (!retVal)
throw autowiring_error("Attempted to dereference a null autowired field");
return *retVal;
}

bool IsAutowired(void) const { return std::shared_ptr<T>::get() != nullptr; }
};

Expand Down
6 changes: 1 addition & 5 deletions autowiring/C++11/cpp11.h
Expand Up @@ -131,11 +131,7 @@
#endif

#if TYPE_TRAITS_AVAILABLE
#if defined(_MSC_VER) || defined(_LIBCPP_VERSION)
#define TYPE_TRAITS_HEADER <type_traits>
#else
#define TYPE_TRAITS_HEADER <type_traits>
#endif
#define TYPE_TRAITS_HEADER <type_traits>
#else
#define TYPE_TRAITS_HEADER <autowiring/C++11/boost_type_traits.h>
#endif
Expand Down

0 comments on commit 109b87e

Please sign in to comment.