diff foosdk/sdk/foobar2000/helpers/cfg_objList.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/helpers/cfg_objList.h	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,160 @@
+#pragma once
+
+#include <SDK/cfg_var.h>
+
+#if FOOBAR2020
+#include <SDK/configStore.h>
+namespace cfg_var_modern {
+	template<typename obj_t>
+	class cfg_objList : private cfg_var_common {
+	public:
+		cfg_objList(const GUID& guid) : cfg_var_common(guid) { }
+        template<typename source_t, unsigned source_count> cfg_objList(const GUID& guid, const source_t(&source)[source_count]) : cfg_var_common(guid) {
+            m_defaults.resize(source_count);
+            for( unsigned walk = 0; walk < source_count; ++ walk) m_defaults[walk] = source[walk];
+        }
+
+		void clear() { set(std::vector<obj_t>()); }
+		void remove_all() { clear(); }
+		size_t remove_mask(pfc::bit_array const& arg) {
+			init();
+			PFC_INSYNC_WRITE(m_listGuard);
+			size_t gone = pfc::remove_mask_t(m_list, arg);
+			if (gone > 0) save();
+			return gone;
+		}
+		//! Returns number of items removed.
+		template<typename pred_t> size_t remove_if(pred_t&& p) {
+			init();
+			PFC_INSYNC_WRITE(m_listGuard);
+			const auto nBefore = m_list.size();
+			const size_t nAfter = pfc::remove_if_t(m_list, std::forward<pred_t>(p));
+			const auto gone = nAfter - nBefore;
+			if (gone > 0) save();
+			return gone;
+		}
+		bool remove_item(obj_t const& v) {
+			return remove_if([&v](const obj_t& arg) { return v == arg; }) != 0;
+		}
+		size_t size() { init(); PFC_INSYNC_READ(m_listGuard);return m_list.size(); }
+		size_t get_count() { return size(); }
+		size_t get_size() { return size(); }
+
+		obj_t get(size_t idx) { init(); PFC_INSYNC_READ(m_listGuard); return m_list[idx]; }
+
+		obj_t operator[] (size_t idx) { return get(idx); }
+
+		template<typename arg_t>
+		void set(size_t idx, arg_t&& v) {
+			init();
+			PFC_INSYNC_WRITE(m_listGuard); m_list[idx] = std::forward<arg_t>(v); save();
+		}
+		bool have_item(obj_t const& arg) {
+			return find_item(arg) != SIZE_MAX;
+		}
+		size_t find_item(obj_t const& arg) {
+			init();
+			PFC_INSYNC_READ(m_listGuard);
+			for (size_t idx = 0; idx < m_list.size(); ++idx) {
+				if (m_list[idx] == arg) return idx;
+			}
+			return SIZE_MAX;
+		}
+		template<typename arg_t>
+		void insert_item(size_t idx, arg_t&& arg) {
+			init();
+			PFC_INSYNC_WRITE(m_listGuard);
+			m_list.insert(m_list.begin() + idx, std::forward<arg_t>(arg));
+			save();
+		}
+		template<typename arg_t>
+		void set_items(arg_t&& arg) {
+			init();
+			PFC_INSYNC_WRITE(m_listGuard);
+			m_list.clear();
+			for (auto& item : arg) m_list.push_back(item);
+			save();
+		}
+		template<typename arg_t>
+		void insert_items(arg_t&& arg, size_t at) {
+			init();
+			PFC_INSYNC_WRITE(m_listGuard);
+			m_list.insert(m_list.begin() + at, arg.begin(), arg.end());
+			save();
+		}
+		template<typename arg_t>
+		void add_items(arg_t&& arg) {
+			init();
+			PFC_INSYNC_WRITE(m_listGuard);
+
+			m_list.insert(m_list.end(), arg.begin(), arg.end());
+			save();
+		}
+		template<typename arg_t>
+		void add_item(arg_t&& arg) {
+			init();
+			PFC_INSYNC_WRITE(m_listGuard);
+			m_list.push_back(std::forward<arg_t>(arg));
+			save();
+		}
+		template<typename arg_t>
+		void set(arg_t&& arg) {
+			init();
+			set_(std::forward<arg_t>(arg));
+		}
+		std::vector<obj_t> get() {
+			init();
+			PFC_INSYNC_READ(m_listGuard);
+			return m_list;
+		}
+
+
+	private:
+		void init() {
+			std::call_once(m_init, [this] {
+				auto blob = fb2k::configStore::get()->getConfigBlob(formatName(), nullptr);
+				if (blob.is_valid()) try {
+					stream_reader_formatter_simple<> reader(blob->data(), blob->size());
+					std::vector<obj_t> data;
+					uint32_t count; reader >> count; data.resize(count);
+					for (auto& v : data) reader >> v;
+					set_(std::move(data), false);
+					return;
+				} catch(...) {} // fall through, set defaults
+				set_(m_defaults, false);
+			});
+		}
+		template<typename arg_t>
+		void set_(arg_t&& arg, bool bSave = true) {
+			PFC_INSYNC_WRITE(m_listGuard);
+			m_list = std::forward<arg_t>(arg);
+			if (bSave) save();
+		}
+		void save() {
+			// assumes write sync
+			stream_writer_formatter_simple<> out;
+			out << (uint32_t)m_list.size();
+			for (auto& v : m_list) out << v;
+			fb2k::configStore::get()->setConfigBlob(formatName(), out.m_buffer.get_ptr(), out.m_buffer.get_size());
+		}
+#ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY
+		void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) override {
+			stream_reader_formatter<> reader(*p_stream, p_abort);
+			std::vector<obj_t> data;
+			uint32_t count; reader >> count; data.resize(count);
+			for (auto& v : data) reader >> v;
+			set(std::move(data));
+		}
+#endif
+
+		std::vector<obj_t> m_list;
+		pfc::readWriteLock m_listGuard;
+
+		std::once_flag m_init;
+        
+        std::vector<obj_t> m_defaults;
+	};
+
+}
+#endif // FOOBAR2020
+