Add VariableRef wrapper and variable reference collector

Just a wrapper around weark_ptr<Variable> to make tracking usage easier
This commit is contained in:
WarmUpTill
2026-10-19 17:45:55 +02:00
committed by WarmUpTill
parent 7e1acd8f61
commit 392aebff5c
5 changed files with 210 additions and 0 deletions

View 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

View 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