diff foosdk/sdk/foobar2000/SDK/service_by_guid.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/foosdk/sdk/foobar2000/SDK/service_by_guid.h	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,100 @@
+#pragma once
+#include <pfc/map.h>
+
+
+
+template<typename what>
+static bool service_by_guid_fallback(service_ptr_t<what> & out, const GUID & id) {
+	for (auto ptr : what::enumerate()) {
+		if (ptr->get_guid() == id) { out = ptr; return true; }
+	}
+	return false;
+}
+
+template<typename what>
+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<what> temp;
+			if (_service_instantiate_helper(temp, m_servClass, walk)) {
+				m_order.set(temp->get_guid(), walk);
+			}
+		}
+		m_inited = true;
+	}
+
+	bool create(service_ptr_t<what> & 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<what> create(const GUID & theID) const {
+        service_ptr_t<what> temp; if (!crete(temp,theID)) throw exception_service_not_found(); return temp;
+	}
+
+private:
+	volatile bool m_inited;
+    pfc::map_t<GUID,t_size> m_order;
+	service_class_ref m_servClass;
+};
+
+template<typename what>
+class _service_by_guid_data_container {
+public:
+	static service_by_guid_data<what> data;
+};
+template<typename what> service_by_guid_data<what> _service_by_guid_data_container<what>::data;
+
+
+template<typename what>
+static void service_by_guid_init() {
+	service_by_guid_data<what> & data = _service_by_guid_data_container<what>::data;
+	data.initialize();
+}
+template<typename what>
+static bool service_by_guid(service_ptr_t<what> & out, const GUID & theID) {
+	pfc::assert_same_type< what, typename what::t_interface_entrypoint >();
+	service_by_guid_data<what> & data = _service_by_guid_data_container<what>::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<typename what>
+static service_ptr_t<what> service_by_guid(const GUID & theID) {
+	service_ptr_t<what> 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<typename what> static int compare(const what & v1, const what & v2) { return pfc::compare_t(v1->get_guid(), v2->get_guid()); }
+};
+