zeus

Unnamed repository; edit this file 'description' to name the repository.
git clone Unknown
Log | Files | Refs

commit 394a2664d61b9f5b05e7830cd21661b6f1d9a354
parent ca88f900f3fb64f5482e84530cf599ec68dbc0e8
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Fri, 6 Jun 2025 11:09:10 +0200

Text referencing toy example

Diffstat:
A tag_rename.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

1 files changed, 156 insertions(+), 0 deletions(-)


diff --git a/ tag_rename.cpp b/ tag_rename.cpp

@@ -0,0 +1,156 @@

/*
* Create and maintain an index of tags
* that can be renamed while keeping
* references in tact
*/


#include <algorithm>
#include <format>
#include <iostream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>

struct string_hash {
using hash_type = std::hash<std::string_view>;
using is_transparent = void;

std::size_t operator()(const char *str) const { return hash_type{}(str); }
std::size_t operator()(std::string_view str) const {
return hash_type{}(str);
}
std::size_t operator()(std::string const &str) const {
return hash_type{}(str);
}
};

class refs {
using string_pos_type = std::size_t;
using vector_pos_type = std::size_t;

std::vector<string_pos_type> m_poss;
std::unordered_map<std::string, std::vector<vector_pos_type>, string_hash,
std::equal_to<>>
m_map;

public:
auto poss(std::string_view name) const {
std::vector<std::size_t> res;

const auto itr = m_map.find(name);
if (itr == std::end(m_map)) {
return res;
}

const auto &refs = itr->second;
res.reserve(std::size(refs));
for (const auto idx : refs) {
res.emplace_back(m_poss[idx]);
}
return res;
}

void insert(std::string_view name, string_pos_type pos) {
auto itr = m_map.find(name);
if (itr == std::end(m_map)) {
itr = m_map.emplace(name, std::vector<std::size_t>()).first;
}
itr->second.emplace_back(std::size(m_poss));
m_poss.emplace_back(pos);
}

void reindex(std::string_view name, std::string_view new_name) {
const auto itr = m_map.find(name);
if (itr == std::end(m_map)) {
return;
}

std::size_t diff = std::size(new_name) - std::size(name);

std::size_t acc = 0;
const auto &idxs = itr->second;
auto crnt = std::begin(idxs);
for (std::size_t i = 0; i < std::size(m_poss); i++) {
m_poss[i] += acc;
if (crnt != std::end(idxs) && *crnt == i) {
acc += diff;
crnt++;
}
}

auto node = m_map.extract(itr);
node.key() = new_name;
m_map.insert(std::move(node));
}
};

class file {
std::string m_text;
refs m_refs;

public:
file(std::string_view input) {
for (int i = 0; i < std::size(input); i++) {
if (input[i] != '[') {
m_text += input[i];
continue;
}

std::string name;
while (++i < std::size(input) && input[i] != ']') {
name += input[i];
}

if (i == std::size(input)) {
m_text += name;
continue;
}

m_refs.insert(name, std::size(m_text));
m_text += name;
}
}

std::size_t rename(std::string_view tag, std::string_view new_tag) {
std::size_t prev = 0;
std::string new_text;
const auto &poss = m_refs.poss(tag);
for (const auto ref : poss) {
new_text += m_text.substr(prev, ref - prev);
new_text += new_tag;
prev = ref + std::size(tag);
}
new_text += m_text.substr(prev);
m_text = new_text;

m_refs.reindex(tag, new_tag);
return std::size(poss);
}

std::string_view text() const { return m_text; }
};

int main() {
const std::string_view input = R"(
this is a [test] that references some [topic]
I want to be able to change the name of the [topic]
and for it to propagate through the rest of the [test].
)";

const auto rename = [](file &f, std::string_view tag,
std::string_view new_tag) {
std::cout << std::format("\nRaplaced {} with {}: {}", tag, new_tag,
f.rename(tag, new_tag));
std::cout << f.text() << std::endl;
};

file f(input);

std::cout << f.text() << std::endl;
rename(f, "test", "example");
rename(f, "topic", "other_topic");
rename(f, "example", "test");
rename(f, "other_topic", "topic");
}