mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-10-24 17:44:14 -05:00
Add VariableRef wrapper and variable reference collector
Just a wrapper around weark_ptr<Variable> to make tracking usage easier
This commit is contained in:
@@ -321,6 +321,8 @@ target_sources(
|
||||
lib/variables/variable-line-edit.hpp
|
||||
lib/variables/variable-number.hpp
|
||||
lib/variables/variable-number.tpp
|
||||
lib/variables/variable-ref.cpp
|
||||
lib/variables/variable-ref.hpp
|
||||
lib/variables/variable-spinbox.cpp
|
||||
lib/variables/variable-spinbox.hpp
|
||||
lib/variables/variable-string.cpp
|
||||
|
||||
78
lib/variables/variable-ref.cpp
Normal file
78
lib/variables/variable-ref.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "variable-ref.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
thread_local static VariableRefCollector *activeCollector = nullptr;
|
||||
|
||||
VariableRefCollector::VariableRefCollector() : _previous(activeCollector)
|
||||
{
|
||||
activeCollector = this;
|
||||
}
|
||||
|
||||
VariableRefCollector::~VariableRefCollector()
|
||||
{
|
||||
activeCollector = _previous;
|
||||
}
|
||||
|
||||
void VariableRefCollector::Add(const std::string &name, int count)
|
||||
{
|
||||
_counts[name] += count;
|
||||
}
|
||||
|
||||
void ReportVariableRef(const std::weak_ptr<Variable> &variable)
|
||||
{
|
||||
if (!activeCollector) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto var = variable.lock();
|
||||
if (!var) {
|
||||
return;
|
||||
}
|
||||
|
||||
activeCollector->Add(var->Name());
|
||||
}
|
||||
|
||||
static int countOccurrences(const std::string &text, const std::string &pattern)
|
||||
{
|
||||
int count = 0;
|
||||
for (auto pos = text.find(pattern); pos != std::string::npos;
|
||||
pos = text.find(pattern, pos + pattern.length())) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void ReportVariableRefsInText(const std::string &text)
|
||||
{
|
||||
if (!activeCollector || text.find("${") == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &variable : GetVariables()) {
|
||||
const auto &name = variable->Name();
|
||||
const int count = countOccurrences(text, "${" + name + "}");
|
||||
if (count > 0) {
|
||||
activeCollector->Add(name, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VariableRef::Save(obs_data_t *obj, const char *key) const
|
||||
{
|
||||
auto var = _variable.lock();
|
||||
if (!var) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_data_set_string(obj, key, var->Name().c_str());
|
||||
ReportVariableRef(_variable);
|
||||
}
|
||||
|
||||
void VariableRef::Load(obs_data_t *obj, const char *key)
|
||||
{
|
||||
_variable = GetWeakVariableByName(obs_data_get_string(obj, key));
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
59
lib/variables/variable-ref.hpp
Normal file
59
lib/variables/variable-ref.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <obs-data.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Variable;
|
||||
|
||||
// While an instance is alive, variable references saved on the current
|
||||
// thread are counted by variable name.
|
||||
class VariableRefCollector {
|
||||
public:
|
||||
EXPORT VariableRefCollector();
|
||||
EXPORT ~VariableRefCollector();
|
||||
VariableRefCollector(const VariableRefCollector &) = delete;
|
||||
VariableRefCollector &operator=(const VariableRefCollector &) = delete;
|
||||
|
||||
EXPORT void Add(const std::string &name, int count = 1);
|
||||
const std::unordered_map<std::string, int> &Counts() const
|
||||
{
|
||||
return _counts;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, int> _counts;
|
||||
VariableRefCollector *_previous = nullptr;
|
||||
};
|
||||
|
||||
EXPORT void ReportVariableRef(const std::weak_ptr<Variable> &variable);
|
||||
EXPORT void ReportVariableRefsInText(const std::string &text);
|
||||
|
||||
class VariableRef {
|
||||
public:
|
||||
VariableRef() = default;
|
||||
VariableRef(const std::weak_ptr<Variable> &variable)
|
||||
: _variable(variable)
|
||||
{
|
||||
}
|
||||
VariableRef &operator=(const std::weak_ptr<Variable> &variable)
|
||||
{
|
||||
_variable = variable;
|
||||
return *this;
|
||||
}
|
||||
operator std::weak_ptr<Variable>() const { return _variable; }
|
||||
std::shared_ptr<Variable> lock() const { return _variable.lock(); }
|
||||
bool expired() const { return _variable.expired(); }
|
||||
|
||||
EXPORT void Save(obs_data_t *obj, const char *key) const;
|
||||
EXPORT void Load(obs_data_t *obj, const char *key);
|
||||
|
||||
private:
|
||||
std::weak_ptr<Variable> _variable;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -128,6 +128,7 @@ target_sources(
|
||||
${ADVSS_SOURCE_DIR}/lib/utils/item-selection-helpers.cpp
|
||||
${ADVSS_SOURCE_DIR}/lib/utils/name-dialog.cpp
|
||||
${ADVSS_SOURCE_DIR}/lib/utils/resizing-text-edit.cpp
|
||||
${ADVSS_SOURCE_DIR}/lib/variables/variable-ref.cpp
|
||||
${ADVSS_SOURCE_DIR}/lib/variables/variable.cpp)
|
||||
|
||||
# --- macro / macro-condition --- #
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <variable-ref.hpp>
|
||||
#include <variable.hpp>
|
||||
|
||||
#include <obs.hpp>
|
||||
#include <thread>
|
||||
|
||||
TEST_CASE("Variable", "[variable]")
|
||||
@@ -50,3 +53,70 @@ TEST_CASE("Variable", "[variable]")
|
||||
variable.SetValue(123);
|
||||
REQUIRE(*variable.GetSecondsSinceLastChange() > 0);
|
||||
}
|
||||
|
||||
static std::shared_ptr<advss::Variable> addVariable(const std::string &name)
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
obs_data_set_string(data, "name", name.c_str());
|
||||
auto variable = std::make_shared<advss::Variable>();
|
||||
variable->Load(data);
|
||||
advss::GetVariables().emplace_back(variable);
|
||||
return variable;
|
||||
}
|
||||
|
||||
TEST_CASE("VariableRef", "[variable]")
|
||||
{
|
||||
auto var = addVariable("var");
|
||||
addVariable("var2");
|
||||
addVariable("Var");
|
||||
|
||||
SECTION("Save reports and writes name")
|
||||
{
|
||||
advss::VariableRefCollector collector;
|
||||
advss::VariableRef ref(var);
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
ref.Save(data, "key");
|
||||
REQUIRE(std::string(obs_data_get_string(data, "key")) == "var");
|
||||
REQUIRE(collector.Counts().at("var") == 1);
|
||||
|
||||
advss::VariableRef loaded;
|
||||
loaded.Load(data, "key");
|
||||
REQUIRE(loaded.lock() == var);
|
||||
}
|
||||
|
||||
SECTION("Expired ref is not saved or reported")
|
||||
{
|
||||
advss::VariableRefCollector collector;
|
||||
advss::VariableRef ref;
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
ref.Save(data, "key");
|
||||
REQUIRE_FALSE(obs_data_has_user_value(data, "key"));
|
||||
REQUIRE(collector.Counts().empty());
|
||||
}
|
||||
|
||||
SECTION("Text references")
|
||||
{
|
||||
advss::VariableRefCollector collector;
|
||||
advss::ReportVariableRefsInText(
|
||||
"${var} ${var2} ${var} var Var");
|
||||
const auto &counts = collector.Counts();
|
||||
REQUIRE(counts.at("var") == 2);
|
||||
REQUIRE(counts.at("var2") == 1);
|
||||
REQUIRE(counts.find("Var") == counts.end());
|
||||
}
|
||||
|
||||
SECTION("Nested collectors")
|
||||
{
|
||||
advss::VariableRefCollector outer;
|
||||
{
|
||||
advss::VariableRefCollector inner;
|
||||
advss::ReportVariableRef(var);
|
||||
REQUIRE(inner.Counts().at("var") == 1);
|
||||
}
|
||||
REQUIRE(outer.Counts().empty());
|
||||
advss::ReportVariableRef(var);
|
||||
REQUIRE(outer.Counts().at("var") == 1);
|
||||
}
|
||||
|
||||
advss::GetVariables().clear();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user