Skip to content

Commit

Permalink
Use hashmap for type mapping only on Windows
Browse files Browse the repository at this point in the history
See comments in jlcxx.cpp for details
  • Loading branch information
barche committed Jun 9, 2024
1 parent 3b5ae22 commit 1cbd400
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 1 deletion.
1 change: 1 addition & 0 deletions include/jlcxx/jlcxx_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define JLCXX_CONFIG_HPP

#ifdef _WIN32
#define JLCXX_USE_TYPE_MAP
#ifdef JLCXX_EXPORTS
#define JLCXX_API __declspec(dllexport)
#else
Expand Down
4 changes: 4 additions & 0 deletions include/jlcxx/module.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,10 @@ class TypeWrapper

using TypeWrapper1 = TypeWrapper<Parametric<TypeVar<1>>>;

#ifdef JLCXX_USE_TYPE_MAP
JLCXX_API std::shared_ptr<TypeWrapper1>& jlcxx_smartpointer_type(std::type_index idx);
#endif

template<typename ApplyT, typename... TypeLists> using combine_types = typename CombineTypes<ApplyT, TypeLists...>::type;

template<typename T>
Expand Down
4 changes: 4 additions & 0 deletions include/jlcxx/smart_pointers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,12 @@ struct SmartPtrMethods<PtrT<PointeeT, ExtraArgs...>, OtherPtrT>
template<typename T>
inline std::shared_ptr<TypeWrapper1>& stored_smartpointer_type()
{
#ifdef JLCXX_USE_TYPE_MAP
return jlcxx_smartpointer_type(typeid(T));
#else
static std::shared_ptr<TypeWrapper1> m_ptr;
return m_ptr;
#endif
}

template<typename T>
Expand Down
42 changes: 41 additions & 1 deletion include/jlcxx/type_conversion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,51 @@ struct JLCXX_API CachedDatatype
jl_datatype_t* m_dt = nullptr;
};


#ifdef JLCXX_USE_TYPE_MAP

JLCXX_API CachedDatatype& jlcxx_type(std::type_index idx);
JLCXX_API CachedDatatype& jlcxx_reftype(std::type_index idx);
JLCXX_API CachedDatatype& jlcxx_constreftype(std::type_index idx);

template<typename T>
struct HashedCache
{
static inline CachedDatatype& value()
{
return jlcxx_type(typeid(T));
}
};

template<typename T>
struct HashedCache<T&>
{
static inline CachedDatatype& value()
{
return jlcxx_reftype(typeid(T));
}
};

template<typename T>
struct HashedCache<const T&>
{
static inline CachedDatatype& value()
{
return jlcxx_constreftype(typeid(T));
}
};

#endif

template<typename CppT>
inline CachedDatatype& stored_type()
CachedDatatype& stored_type()
{
#ifdef JLCXX_USE_TYPE_MAP
return HashedCache<CppT>::value();
#else
static CachedDatatype m_dt;
return m_dt;
#endif
}

template<typename T>
Expand Down
44 changes: 44 additions & 0 deletions src/jlcxx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,50 @@ namespace detail
};
}

#ifdef JLCXX_USE_TYPE_MAP

// On windows, we can't store a mapping from the C++ type to the Julia type
// in a static variable declared in a template function, since each DLL
// will have its onw copy of that variable, making it impossible to share
// type definitions between the CxxWrap base library and other libraries.
// The workaround is to store the types in a map, but this is more fragile
// because the guarantees on std::type_index are not very strong either
// in the context of sharing information between shared libraries. This is
// why we fall back to this approach only on Windows. Using type names is
// also not a solution because types in anonymous namespaces will clash.
// Refs:
// https://stackoverflow.com/questions/398069/static-member-variable-in-template-with-multiple-dlls
// https://developercommunity.visualstudio.com/t/template-static-members-and-multiple-definitions-a/1202888
// https://github.com/pybind/pybind11/pull/4319
// https://bugs.llvm.org/show_bug.cgi?id=33542
// https://github.com/pybind/pybind11/issues/3289

JLCXX_API CachedDatatype& jlcxx_type(std::type_index idx)
{
static std::unordered_map<std::type_index, CachedDatatype> m_map;
return m_map.insert(std::make_pair(idx,CachedDatatype())).first->second;
}

JLCXX_API CachedDatatype& jlcxx_reftype(std::type_index idx)
{
static std::unordered_map<std::type_index, CachedDatatype> m_map;
return m_map.insert(std::make_pair(idx,CachedDatatype())).first->second;
}

JLCXX_API CachedDatatype& jlcxx_constreftype(std::type_index idx)
{
static std::unordered_map<std::type_index, CachedDatatype> m_map;
return m_map.insert(std::make_pair(idx,CachedDatatype())).first->second;
}

JLCXX_API std::shared_ptr<TypeWrapper1>& jlcxx_smartpointer_type(std::type_index idx)
{
static std::unordered_map<std::type_index, std::shared_ptr<TypeWrapper1>> m_map;
return m_map.insert(std::make_pair(idx, nullptr)).first->second;
}

#endif

JLCXX_API void register_core_types()
{
if(jl_base_module == nullptr)
Expand Down

0 comments on commit 1cbd400

Please sign in to comment.