#pragma once #ifdef FOOBAR2000_MODERN #include #endif template static bool service_by_guid_fallback(service_ptr_t & out, const GUID & id) { service_enum_t e; service_ptr_t ptr; while(e.next(ptr)) { if (ptr->get_guid() == id) {out = ptr; return true;} } return false; } template class service_by_guid_data { public: service_by_guid_data() : m_inited(), m_servClass() {} bool ready() const {return m_inited;} // Caller must ensure initialize call before create() as well as thread safety of initialize() calls. The rest of this class is thread safe (only reads member data). void initialize() { if (m_inited) return; pfc::assert_same_type< what, typename what::t_interface_entrypoint >(); m_servClass = service_factory_base::enum_find_class(what::class_guid); const t_size servCount = service_factory_base::enum_get_count(m_servClass); for(t_size walk = 0; walk < servCount; ++walk) { service_ptr_t temp; if (_service_instantiate_helper(temp, m_servClass, walk)) { m_order.set(temp->get_guid(), walk); } } m_inited = true; } bool create(service_ptr_t & out, const GUID & theID) const { PFC_ASSERT(m_inited); t_size index; if (!m_order.query(theID,index)) return false; return _service_instantiate_helper(out, m_servClass, index); } service_ptr_t create(const GUID & theID) const { service_ptr_t temp; if (!crete(temp,theID)) throw exception_service_not_found(); return temp; } private: volatile bool m_inited; pfc::map_t m_order; service_class_ref m_servClass; }; template class _service_by_guid_data_container { public: static service_by_guid_data data; }; template service_by_guid_data _service_by_guid_data_container::data; template static void service_by_guid_init() { service_by_guid_data & data = _service_by_guid_data_container::data; data.initialize(); } template static bool service_by_guid(service_ptr_t & out, const GUID & theID) { pfc::assert_same_type< what, typename what::t_interface_entrypoint >(); service_by_guid_data & data = _service_by_guid_data_container::data; if (data.ready()) { //fall-thru } else if (core_api::is_main_thread()) { data.initialize(); } else { #if PFC_DEBUG FB2K_DebugLog() << "Warning: service_by_guid() used in non-main thread without initialization, using fallback"; #endif return service_by_guid_fallback(out,theID); } return data.create(out,theID); } template static service_ptr_t service_by_guid(const GUID & theID) { service_ptr_t temp; if (!service_by_guid(temp, theID)) { #if PFC_DEBUG FB2K_DebugLog() << "service_by_guid failure: " << what::debugServiceName() << " : " << pfc::print_guid( theID ); #endif throw exception_service_not_found(); } return temp; } class comparator_service_guid { public: template static int compare(const what & v1, const what & v2) { return pfc::compare_t(v1->get_guid(), v2->get_guid()); } };