diff --git a/cppwinrt/component_writers.h b/cppwinrt/component_writers.h index 94e20e53e..aa664569a 100644 --- a/cppwinrt/component_writers.h +++ b/cppwinrt/component_writers.h @@ -76,14 +76,7 @@ namespace cppwinrt return; } - if (settings.component_opt) - { - auto format = R"(void* winrt_make_%(); -)"; - - w.write(format, get_impl_name(type.TypeNamespace(), type.TypeName())); - } - else + if (!settings.component_opt) { auto format = R"(#include "%.h" )"; @@ -92,7 +85,7 @@ namespace cppwinrt } } - static void write_component_activation(writer& w, TypeDef const& type) + static void write_component_make_definition(writer& w, TypeDef const& type) { if (!has_factory_members(w, type) || is_always_disabled(type)) { @@ -103,35 +96,49 @@ namespace cppwinrt auto type_namespace = type.TypeNamespace(); auto impl_name = get_impl_name(type_namespace, type_name); - if (settings.component_opt) - { - auto format = R"( - if (requal(name, L"%.%")) - { - return winrt_make_%(); - } + auto format = R"(void* winrt_make_%() +{ + return winrt::detach_abi(winrt::make()); +} )"; - w.write(format, - type_namespace, - type_name, - impl_name); + w.write(format, + impl_name, + type_namespace, + type_name); + } + + static void write_component_activation(writer& w, std::vector const& classes) + { + if (!settings.component_opt) + { + for (auto&& type : classes) + { + write_component_make_definition(w, type); + } } else { - auto format = R"( - if (requal(name, L"%.%")) - { - return winrt::detach_abi(winrt::make()); - } + auto declarations = R"( +#define WINRT_DECLARE_FUNC(func, name) void* func(); +WINRT_ACTIVATION_TABLE(WINRT_DECLARE_FUNC) )"; + w.write(declarations); + } + } - w.write(format, - type_namespace, - type_name, - type_namespace, - type_name); + static void collect_component(writer& w, TypeDef const& type, std::vector& components) + { + if (!has_factory_members(w, type) || is_always_disabled(type)) + { + return; } + + std::string name; + name += type.TypeNamespace(); + name += '.'; + name += type.TypeName(); + components.push_back(std::move(name)); } static void write_module_g_cpp(writer& w, std::vector const& classes) @@ -140,7 +147,31 @@ namespace cppwinrt { w.write_root_include("base"); } - auto format = R"(% + + std::vector components; + for (auto&& type : classes) + { + write_component_include(w, type); + collect_component(w, type, components); + } + + // Sort the strings so that binary search can be used. + std::sort(components.begin(), components.end()); + w.write("#define WINRT_ACTIVATION_TABLE(X)\\\n"); + + for (std::size_t i = 0; i + 1 < components.size(); ++i) + { + w.write(std::string{ " X(winrt_make_" } + get_impl_name(components[i]) + ", L\"" + components[i] + "\") \\\n"); + } + + if (!components.empty()) + { + w.write(std::string{ " X(winrt_make_" } + get_impl_name(components.back()) + ", L\"" + components.back() + "\")\n"); + } + + write_component_activation(w, classes); + + auto format = R"( bool __stdcall %_can_unload_now() noexcept { if (winrt::get_module_lock()) @@ -154,20 +185,36 @@ bool __stdcall %_can_unload_now() noexcept void* __stdcall %_get_activation_factory([[maybe_unused]] std::wstring_view const& name) { - auto requal = [](std::wstring_view const& left, std::wstring_view const& right) noexcept +#if % + static constexpr std::wstring_view names[] = { - return std::equal(left.rbegin(), left.rend(), right.rbegin(), right.rend()); +#define WINRT_NAME_LIST(func, name) name, + WINRT_ACTIVATION_TABLE(WINRT_NAME_LIST) }; -% + + using make_t = void* (*)(); + static constexpr make_t makes[] = + { +#define WINRT_MAKE_LIST(func, name) func, + WINRT_ACTIVATION_TABLE(WINRT_MAKE_LIST) + }; + +#if % <= 32 + auto it = std::find(std::begin(names), std::end(names), name); + if (it != std::end(names)) +#else + auto it = std::lower_bound(std::begin(names), std::end(names), name); + if (it != std::end(names) && *it == name) +#endif + { + return makes[it - std::begin(names)](); + } +#endif return nullptr; } )"; - w.write(format, - bind_each(classes), - settings.component_lib, - settings.component_lib, - bind_each(classes)); + w.write(format, settings.component_lib, settings.component_lib, components.size(), components.size()); if (settings.component_lib != "winrt") { @@ -379,21 +426,8 @@ catch (...) { return winrt::to_hresult(); } { auto type_name = type.TypeName(); auto type_namespace = type.TypeNamespace(); - auto impl_name = get_impl_name(type_namespace, type_name); - if (has_factory_members(w, type)) - { - auto format = R"(void* winrt_make_%() -{ - return winrt::detach_abi(winrt::make()); -} -)"; - - w.write(format, - impl_name, - type_namespace, - type_name); - } + write_component_make_definition(w, type); if (!settings.component_opt) {