Fix handling of unordered_map/unordered_set on OSX 10.9.0. Depending on the compiler + standard library combination, unordered_map/set may or may not be available. If available they maybe in the std or the std::tr1 namespaces. Apple switched to using libc++ with 10.9.0 which places unordered_map in std, breaking our assumptions about the platform. This change refactors our logic for dealing with the namespace switching, making it a three state thing rather than two. There are three defines now, CERES_NO_UNORDERED_MAP, CERES_STD_UNORDERED_MAP and CERES_TR1_UNORDERED_MAP. Earlier the first two were conflated into one, leading to the breakage. Change-Id: I904fe8c49529169bdefa9f2ee6d629e7eab0b855
diff --git a/CMakeLists.txt b/CMakeLists.txt index 75967f2..7519f48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -104,9 +104,7 @@ # Multithreading using OpenMP OPTION(OPENMP "Enable threaded solving in Ceres (requires OpenMP)" ON) # TODO(sameeragarwal): Replace this with a positive option instead? -OPTION(DISABLE_TR1 - "Don't use TR1. This replaces some hash tables with sets. Slower." - OFF) + # Line search minimizer is useful for large scale problems or when # sparse linear algebra libraries are not available. If compile time, # binary size or compiler performance is an issue, consider disabling @@ -409,37 +407,24 @@ ADD_DEFINITIONS(-DCERES_NO_THREADS) ENDIF (OPENMP) -IF (DISABLE_TR1) - MESSAGE("-- Replacing unordered_map/set with map/set (warning: slower!)") - ADD_DEFINITIONS(-DCERES_NO_TR1) -ELSE (DISABLE_TR1) - MESSAGE("-- Using normal TR1 unordered_map/set") - # Use the std namespace for the hash<> and related templates. This may vary by - # system. - IF (MSVC) - IF (MSVC90) - # Special case for Visual Studio 2008. - # Newer versions have got tr1 symbols in another namespace, - # and this is being handled in Else branch of this condition. - # Probably Visual studio 2003 and 2005 also shall be handled here, - # but don't have by hand to verify and most likely they're not - # used by Ceres users anyway. - ADD_DEFINITIONS("\"-DCERES_HASH_NAMESPACE_START=namespace std { namespace tr1 {\"") - ADD_DEFINITIONS("\"-DCERES_HASH_NAMESPACE_END=}}\"") - ELSE (MSVC90) - # This is known to work with Visual Studio 2010 Express. - # Further, for as long Visual Studio 2012 didn't move tr1 to - # just another namespace, the same define will work for it as well. - # Hopefully all further versions will also keep working with this define. - ADD_DEFINITIONS("\"-DCERES_HASH_NAMESPACE_START=namespace std {\"") - ADD_DEFINITIONS("\"-DCERES_HASH_NAMESPACE_END=}\"") - ENDIF(MSVC90) - ELSE (MSVC) - # This is known to work with recent versions of Linux and Mac OS X. +Include(CheckIncludeFileCXX) +CHECK_INCLUDE_FILE_CXX(unordered_map UNORDERED_MAP_IN_STD_NAMESPACE) +If (UNORDERED_MAP_IN_STD_NAMESPACE) + ADD_DEFINITIONS(-DCERES_STD_UNORDERED_MAP) + ADD_DEFINITIONS("\"-DCERES_HASH_NAMESPACE_START=namespace std {\"") + ADD_DEFINITIONS("\"-DCERES_HASH_NAMESPACE_END=}\"") +ELSE (UNORDERED_MAP_IN_STD_NAMESPACE) + CHECK_INCLUDE_FILE_CXX("tr1/unordered_map" UNORDERED_MAP_IN_TR1_NAMESPACE) + IF (UNORDERED_MAP_IN_TR1_NAMESPACE) + ADD_DEFINITIONS(-DCERES_TR1_UNORDERED_MAP) ADD_DEFINITIONS("\"-DCERES_HASH_NAMESPACE_START=namespace std { namespace tr1 {\"") ADD_DEFINITIONS("\"-DCERES_HASH_NAMESPACE_END=}}\"") - ENDIF (MSVC) -ENDIF (DISABLE_TR1) + ELSE (UNORDERED_MAP_IN_TR1_NAMESPACE) + MESSAGE("-- Unable to find <unordered_map> or <tr1/unordered_map>. ") + MESSAGE("-- Replacing unordered_map/set with map/set (warning: slower!)") + ADD_DEFINITIONS(-DCERES_NO_UNORDERED_MAP) + ENDIF (UNORDERED_MAP_IN_TR1_NAMESPACE) +ENDIF (UNORDERED_MAP_IN_STD_NAMESPACE) INCLUDE_DIRECTORIES( include
diff --git a/internal/ceres/collections_port.h b/internal/ceres/collections_port.h index 715c975..ae71e54 100644 --- a/internal/ceres/collections_port.h +++ b/internal/ceres/collections_port.h
@@ -33,26 +33,30 @@ #ifndef CERES_INTERNAL_COLLECTIONS_PORT_H_ #define CERES_INTERNAL_COLLECTIONS_PORT_H_ -#if defined(CERES_NO_TR1) +#if defined(CERES_NO_UNORDERED_MAP) # include <map> # include <set> -#else -# if defined(_MSC_VER) -# include <unordered_map> -# include <unordered_set> -# else -# include <tr1/unordered_map> -# include <tr1/unordered_set> -# endif #endif + +#if defined(CERES_TR1_UNORDERED_MAP) +# include <tr1/unordered_map> +# include <tr1/unordered_set> +#endif + +#if defined(CERES_STD_UNORDERED_MAP) +# include <unordered_map> +# include <unordered_set> +#endif + + #include <utility> #include "ceres/integral_types.h" #include "ceres/internal/port.h" -// Some systems don't have access to TR1. In that case, substitute the hash -// map/set with normal map/set. The price to pay is slightly slower speed for -// some operations. -#if defined(CERES_NO_TR1) +// Some systems don't have access to unordered_map/unordered_set. In +// that case, substitute the hash map/set with normal map/set. The +// price to pay is slightly slower speed for some operations. +#if defined(CERES_NO_UNORDERED_MAP) namespace ceres { namespace internal { @@ -71,11 +75,19 @@ namespace ceres { namespace internal { +#if defined(CERES_TR1_UNORDERED_MAP) template<typename K, typename V> struct HashMap : std::tr1::unordered_map<K, V> {}; - template<typename K> struct HashSet : std::tr1::unordered_set<K> {}; +#endif + +#if defined(CERES_STD_UNORDERED_MAP) +template<typename K, typename V> +struct HashMap : std::unordered_map<K, V> {}; +template<typename K> +struct HashSet : std::unordered_set<K> {}; +#endif #if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__) #define GG_LONGLONG(x) x##I64 @@ -162,6 +174,5 @@ CERES_HASH_NAMESPACE_END -#endif // CERES_NO_TR1 - +#endif // CERES_NO_UNORDERED_MAP #endif // CERES_INTERNAL_COLLECTIONS_PORT_H_
diff --git a/jni/Android.mk b/jni/Android.mk index 1c6f045..c68f79b 100644 --- a/jni/Android.mk +++ b/jni/Android.mk
@@ -104,7 +104,7 @@ -DCERES_NO_GFLAGS \ -DCERES_NO_THREADS \ -DCERES_NO_CXSPARSE \ - -DCERES_NO_TR1 \ + -DCERES_NO_UNORDERED_MAP \ -DCERES_WORK_AROUND_ANDROID_NDK_COMPILER_BUG # On Android NDK 8b, GCC gives spurrious warnings about ABI incompatibility for