Rewrite it in C++
rust people are going to be very mad at me now /j
This commit is contained in:
parent
20d72e0cd2
commit
af49206a16
11 changed files with 359 additions and 128 deletions
44
.clang-format
Executable file
44
.clang-format
Executable file
|
@ -0,0 +1,44 @@
|
||||||
|
BasedOnStyle: Google
|
||||||
|
|
||||||
|
# force T* or T&
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
PointerAlignment: Left
|
||||||
|
|
||||||
|
TabWidth: 4
|
||||||
|
IndentWidth: 4
|
||||||
|
UseTab: Always
|
||||||
|
IndentPPDirectives: BeforeHash
|
||||||
|
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakStringLiterals: false
|
||||||
|
|
||||||
|
ColumnLimit: 150
|
||||||
|
CompactNamespaces: false
|
||||||
|
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
ContinuationIndentWidth: 0
|
||||||
|
|
||||||
|
# turning this on causes major issues with initializer lists
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
SpaceBeforeCpp11BracedList: true
|
||||||
|
|
||||||
|
FixNamespaceComments: true
|
||||||
|
|
||||||
|
NamespaceIndentation: All
|
||||||
|
ReflowComments: true
|
||||||
|
|
||||||
|
SortIncludes: CaseInsensitive
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
SpaceBeforeParens: Never
|
||||||
|
SpacesBeforeTrailingComments: 1
|
15
Makefile
Normal file
15
Makefile
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
CXX = g++ -std=c++23 -O3
|
||||||
|
|
||||||
|
all: vxorg tree_test
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm vxorg tree_test *.o
|
||||||
|
|
||||||
|
vxorg: vxorg.o vxheaven_parse.o
|
||||||
|
$(CXX) $^ -o $@
|
||||||
|
|
||||||
|
tree_test: tree_test.o
|
||||||
|
$(CXX) $^ -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) -c $< -o $@
|
106
tree.hpp
Normal file
106
tree.hpp
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/// Port of tree.py to C++
|
||||||
|
template<class T>
|
||||||
|
struct Tree {
|
||||||
|
|
||||||
|
// FIXME make T not require default constructability
|
||||||
|
struct Node {
|
||||||
|
protected:
|
||||||
|
friend Tree;
|
||||||
|
Node* parent = nullptr;
|
||||||
|
std::vector<Node*> children{};
|
||||||
|
T item{};
|
||||||
|
public:
|
||||||
|
~Node() {
|
||||||
|
for(auto& child: children)
|
||||||
|
delete child;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& data() {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& data() const {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_leaf() const {
|
||||||
|
return children.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* parent_node() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* create_leaf(const T& item) {
|
||||||
|
auto* node = new Node;
|
||||||
|
node->parent = this;
|
||||||
|
node->item = item;
|
||||||
|
children.push_back(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Fn>
|
||||||
|
void walk(Fn&& fn) {
|
||||||
|
fn(this);
|
||||||
|
if(!is_leaf()) {
|
||||||
|
for(auto& child: children)
|
||||||
|
child->walk(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Pred>
|
||||||
|
Node* find_child(Pred&& predicate) {
|
||||||
|
if(predicate(this) == true)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
for(auto& child: children)
|
||||||
|
if(predicate(child) == true)
|
||||||
|
return child;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t parent_count() const {
|
||||||
|
auto* parent = this->parent;
|
||||||
|
auto parent_count = 0z;
|
||||||
|
while(parent) {
|
||||||
|
parent_count ++;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
return parent_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Tree() {
|
||||||
|
root = new Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Tree() {
|
||||||
|
delete root;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trees are not copyable but they can move
|
||||||
|
Tree(const Tree&) = delete;
|
||||||
|
Tree(Tree&&) = default;
|
||||||
|
|
||||||
|
template<class Fn>
|
||||||
|
void walk(Fn&& fn) {
|
||||||
|
root->walk(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Node* create_leaf(const T& item) {
|
||||||
|
return root->create_leaf(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* root_node() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Node* root;
|
||||||
|
};
|
35
tree_test.cpp
Normal file
35
tree_test.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include "tree.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void test_tree() {
|
||||||
|
Tree<std::string> tree;
|
||||||
|
|
||||||
|
auto* virus = tree.create_leaf("Virus");
|
||||||
|
auto* worm = tree.create_leaf("Worm");
|
||||||
|
|
||||||
|
auto* test = virus->create_leaf("test");
|
||||||
|
|
||||||
|
test->create_leaf("a");
|
||||||
|
test->create_leaf("b");
|
||||||
|
test->create_leaf("c");
|
||||||
|
test->create_leaf("884");
|
||||||
|
|
||||||
|
tree.walk([](auto* node) {
|
||||||
|
auto tab_count = node->parent_count();
|
||||||
|
auto& data = node->data();
|
||||||
|
|
||||||
|
for(auto i = 0; i < tab_count; ++i)
|
||||||
|
std::printf("\t");
|
||||||
|
|
||||||
|
if(data.empty()) {
|
||||||
|
std::printf("(root)\n");
|
||||||
|
} else {
|
||||||
|
std::printf("%s\n", data.c_str());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
test_tree();
|
||||||
|
return 0;
|
||||||
|
}
|
94
vxheaven_parse.cpp
Normal file
94
vxheaven_parse.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#include "vxheaven_parse.hpp"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <fstream>
|
||||||
|
#include <optional>
|
||||||
|
#include <ranges>
|
||||||
|
#include <span>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace vxorg {
|
||||||
|
|
||||||
|
/// Wrapper for std::views::split.
|
||||||
|
/// Make sure line outlives the vector.
|
||||||
|
std::vector<std::string_view> split_by(const std::string& string, char delim) {
|
||||||
|
auto res = std::vector<std::string_view> {};
|
||||||
|
for(auto word : std::views::split(string, delim)) {
|
||||||
|
res.push_back(std::string_view(word));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_into_tree(VxHeavenTree& tree, std::istream& is) {
|
||||||
|
std::string line {};
|
||||||
|
while(std::getline(is, line)) {
|
||||||
|
auto split = split_by(line, '.');
|
||||||
|
|
||||||
|
VxHeavenTree::Node* type_leaf { nullptr };
|
||||||
|
VxHeavenTree::Node* platform_leaf { nullptr };
|
||||||
|
VxHeavenTree::Node* family_leaf { nullptr };
|
||||||
|
VxHeavenTree::Node* sample_leaf { nullptr };
|
||||||
|
|
||||||
|
if(auto* node = tree.root_node()->find_child([&](auto* node) { return node->data().name == split[0]; }); node == nullptr) {
|
||||||
|
// std::printf("making leaf for type %.*s\n", split[0].length(), split[0].data());
|
||||||
|
type_leaf = tree.create_leaf({ .name = std::string(split[0].data(), split[0].length()), .is_sample = false });
|
||||||
|
} else {
|
||||||
|
// std::printf("using existing leaf for type %.*s\n", split[0].length(), split[0].data());
|
||||||
|
type_leaf = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(split.size() == 1) {
|
||||||
|
type_leaf->data().is_sample = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(auto* n = type_leaf->find_child([&](auto* node) {
|
||||||
|
// auto matches = node->data().name == split[1];
|
||||||
|
// std::printf("trying to find %.*s in node %s's child %s: %s\n", split[1].length(), split[1].data(),
|
||||||
|
// type_leaf->data().name.c_str(), node->data().name.c_str(), matches ? "matches": "doesnt fucking match god damn it");
|
||||||
|
return node->data().name == split[1];
|
||||||
|
});
|
||||||
|
n == nullptr) {
|
||||||
|
// std::printf("making leaf for platform %s %.*s\n", type_leaf->data().name.c_str(), split[1].length(), split[1].data());
|
||||||
|
platform_leaf = type_leaf->create_leaf({ .name = std::string(split[1].data(), split[1].length()), .is_sample = false });
|
||||||
|
} else {
|
||||||
|
// std::printf("using existing leaf for platform %.*s\n", split[1].length(), split[1].data());
|
||||||
|
platform_leaf = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(auto* n = platform_leaf->find_child([&](auto* node) { return node->data().name == split[2]; }); n == nullptr) {
|
||||||
|
// std::printf("making leaf for platform %s %.*s\n", type_leaf->data().name.c_str(), split[1].length(), split[1].data());
|
||||||
|
family_leaf = platform_leaf->create_leaf({ .name = std::string(split[2].data(), split[2].length()), .is_sample = false });
|
||||||
|
} else {
|
||||||
|
// std::printf("using existing leaf for platform %.*s\n", split[1].length(), split[1].data());
|
||||||
|
family_leaf = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle famlies with a variantless sample inside of them
|
||||||
|
if(split.size() == 3) {
|
||||||
|
family_leaf->data().is_sample = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(split.size() > 4) {
|
||||||
|
auto subvariants = std::span(split.data() + 4, split.size() - 4);
|
||||||
|
auto leaf = family_leaf;
|
||||||
|
|
||||||
|
for(auto& subvariant : subvariants) {
|
||||||
|
if(auto* node = leaf->find_child([&](auto* node) { return node->data().name == subvariant; }); node == nullptr) {
|
||||||
|
leaf = leaf->create_leaf({ .name = std::string(subvariant.data(), subvariant.length()), .is_sample = false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf->data().is_sample = true;
|
||||||
|
} else {
|
||||||
|
auto subvariant = split[3];
|
||||||
|
if(auto* node = family_leaf->find_child([&](auto* node) { return node->data().name == subvariant; }); node == nullptr) {
|
||||||
|
family_leaf->create_leaf({ .name = std::string(subvariant.data(), subvariant.length()), .is_sample = true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace vxorg
|
16
vxheaven_parse.hpp
Normal file
16
vxheaven_parse.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
#include "tree.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace vxorg {
|
||||||
|
|
||||||
|
struct VxHeavenItem {
|
||||||
|
std::string name;
|
||||||
|
// True if this item is also a sample
|
||||||
|
bool is_sample;
|
||||||
|
};
|
||||||
|
|
||||||
|
using VxHeavenTree = Tree<VxHeavenItem>;
|
||||||
|
|
||||||
|
void parse_into_tree(VxHeavenTree& tree, std::istream& is);
|
||||||
|
}
|
177
vxorg.cpp
177
vxorg.cpp
|
@ -1,134 +1,55 @@
|
||||||
#include <optional>
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <ranges>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <filesystem>
|
#include "tree.hpp"
|
||||||
|
#include "vxheaven_parse.hpp"
|
||||||
/// Port of tree.py to C++
|
|
||||||
template<class T>
|
|
||||||
struct Tree {
|
|
||||||
|
|
||||||
// FIXME make T not require default constructability
|
|
||||||
struct Node {
|
|
||||||
protected:
|
|
||||||
friend Tree;
|
|
||||||
Node* parent = nullptr;
|
|
||||||
std::vector<Node*> children{};
|
|
||||||
T item{};
|
|
||||||
public:
|
|
||||||
~Node() {
|
|
||||||
for(auto& child: children)
|
|
||||||
delete child;
|
|
||||||
}
|
|
||||||
|
|
||||||
T& data() {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& data() const {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_leaf() const {
|
|
||||||
return children.size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* create_leaf(const T& item) {
|
|
||||||
auto* node = new Node;
|
|
||||||
node->parent = this;
|
|
||||||
node->item = item;
|
|
||||||
children.push_back(node);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Fn>
|
|
||||||
void walk(Fn&& fn) {
|
|
||||||
fn(this);
|
|
||||||
if(!is_leaf()) {
|
|
||||||
for(auto& child: children)
|
|
||||||
child->walk(fn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Pred>
|
|
||||||
std::optional<Node*> find_child(Pred&& predicate) {
|
|
||||||
if(predicate(*this))
|
|
||||||
return this;
|
|
||||||
|
|
||||||
for(auto& child: children)
|
|
||||||
if(predicate(*child))
|
|
||||||
return child;
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t parent_count() const {
|
|
||||||
auto* parent = this->parent;
|
|
||||||
auto parent_count = 0z;
|
|
||||||
while(parent) {
|
|
||||||
parent_count ++;
|
|
||||||
parent = parent->parent;
|
|
||||||
}
|
|
||||||
return parent_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
Tree() {
|
|
||||||
root = new Node;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Tree() {
|
|
||||||
delete root;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trees are not copyable but they can move
|
|
||||||
Tree(const Tree&) = delete;
|
|
||||||
Tree(Tree&&) = default;
|
|
||||||
|
|
||||||
template<class Fn>
|
|
||||||
void walk(Fn&& fn) {
|
|
||||||
root->walk(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Node* create_leaf(const T& item) {
|
|
||||||
return root->create_leaf(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Node* root;
|
|
||||||
};
|
|
||||||
|
|
||||||
void test_tree() {
|
|
||||||
Tree<std::string> tree;
|
|
||||||
|
|
||||||
auto* virus = tree.create_leaf("Virus");
|
|
||||||
auto* worm = tree.create_leaf("Worm");
|
|
||||||
|
|
||||||
auto* test = virus->create_leaf("test");
|
|
||||||
|
|
||||||
test->create_leaf("a");
|
|
||||||
test->create_leaf("b");
|
|
||||||
test->create_leaf("c");
|
|
||||||
test->create_leaf("884");
|
|
||||||
|
|
||||||
tree.walk([](auto* node) {
|
|
||||||
auto tab_count = node->parent_count();
|
|
||||||
auto& data = node->data();
|
|
||||||
|
|
||||||
for(auto i = 0; i < tab_count; ++i)
|
|
||||||
std::printf("\t");
|
|
||||||
|
|
||||||
if(data.empty()) {
|
|
||||||
std::printf("(root)\n");
|
|
||||||
} else {
|
|
||||||
std::printf("%s\n", data.c_str());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
test_tree();
|
std::ifstream ifs("./samples.sort");
|
||||||
return 0;
|
vxorg::VxHeavenTree tree;
|
||||||
|
|
||||||
|
vxorg::parse_into_tree(tree, ifs);
|
||||||
|
|
||||||
|
// walk the resulting tree
|
||||||
|
tree.walk([](auto* node) {
|
||||||
|
auto tab_count = node->parent_count();
|
||||||
|
auto& data = node->data();
|
||||||
|
|
||||||
|
for(auto i = 0; i < tab_count; ++i)
|
||||||
|
std::printf("\t");
|
||||||
|
|
||||||
|
if(data.name.empty()) {
|
||||||
|
std::printf("(root)\n");
|
||||||
|
} else {
|
||||||
|
if(data.is_sample) {
|
||||||
|
std::string sample_name {};
|
||||||
|
|
||||||
|
std::vector<vxorg::VxHeavenItem*> parent_list {};
|
||||||
|
vxorg::VxHeavenTree::Node* parent = node->parent_node();
|
||||||
|
while(parent) {
|
||||||
|
if(parent->data().name.empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
parent_list.push_back(&parent->data());
|
||||||
|
parent = parent->parent_node();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& item : std::views::reverse(parent_list)) {
|
||||||
|
sample_name += std::format("{}.", item->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
sample_name += data.name;
|
||||||
|
|
||||||
|
std::printf("%s (sample %s)\n", data.name.c_str(), sample_name.c_str());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
std::printf("%s\n", data.name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in a new issue