Reactor: Add support for specifying and modifying default configuration settings.

rr::Config holds the full reactor configuration state.
rr::Config::Edit holds edits on a config, which can be applied on top of the current defaults.

Default configurations are updated atomically, preventing modifications to the default state from tearing.

Bug: b/137167988
Change-Id: Ib05f2cfc31ab22fb9a891a267fffe33c18691028
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/33768
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/Reactor.cpp b/src/Reactor/Reactor.cpp
index bb94cf5..60ee656 100644
--- a/src/Reactor/Reactor.cpp
+++ b/src/Reactor/Reactor.cpp
@@ -21,8 +21,59 @@
 #define REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION 0
 #endif
 
+namespace
+{
+	// Introduced in C++20.
+	template <class ForwardIterator, class UnaryPredicate>
+	ForwardIterator remove_if(ForwardIterator first, ForwardIterator last,
+								UnaryPredicate pred)
+	{
+		ForwardIterator result = first;
+		while (first!=last) {
+			if (!pred(*first)) {
+				*result = std::move(*first);
+				++result;
+			}
+			++first;
+		}
+		return result;
+	}
+}
+
 namespace rr
 {
+	const Config::Edit Config::Edit::None = {};
+
+	Config Config::Edit::apply(const Config &cfg) const
+	{
+		if (this == &None) { return cfg; }
+
+		auto level = optLevelChanged ? optLevel : cfg.optimization.getLevel();
+		auto passes = cfg.optimization.getPasses();
+		apply(optPassEdits, passes);
+		return Config{ Optimization{level, passes} };
+	}
+
+	template <typename T>
+	void rr::Config::Edit::apply(const std::vector<std::pair<ListEdit, T>> & edits, std::vector<T>& list) const
+	{
+		for (auto & edit : edits)
+		{
+			switch (edit.first)
+			{
+			case ListEdit::Add:
+				list.push_back(edit.second);
+				break;
+			case ListEdit::Remove:
+				::remove_if(list.begin(), list.end(), [&](T item) { return item == edit.second; });
+				break;
+			case ListEdit::Clear:
+				list.clear();
+				break;
+			}
+		}
+	}
+
 	// Set of variables that do not have a stack location yet.
 	std::unordered_set<Variable*> Variable::unmaterializedVariables;