Rewrite it in C++

rust people are going to be very mad at me now /j
This commit is contained in:
Lily Tsuru 2024-10-21 12:22:35 -04:00
parent 20d72e0cd2
commit af49206a16
11 changed files with 359 additions and 128 deletions

44
.clang-format Executable file
View 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
View 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
View 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
View 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
View 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
View 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);
}

151
vxorg.cpp
View file

@ -1,118 +1,20 @@
#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++ int main() {
template<class T> std::ifstream ifs("./samples.sort");
struct Tree { vxorg::VxHeavenTree tree;
// FIXME make T not require default constructability vxorg::parse_into_tree(tree, ifs);
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");
// walk the resulting tree
tree.walk([](auto* node) { tree.walk([](auto* node) {
auto tab_count = node->parent_count(); auto tab_count = node->parent_count();
auto& data = node->data(); auto& data = node->data();
@ -120,15 +22,34 @@ void test_tree() {
for(auto i = 0; i < tab_count; ++i) for(auto i = 0; i < tab_count; ++i)
std::printf("\t"); std::printf("\t");
if(data.empty()) { if(data.name.empty()) {
std::printf("(root)\n"); std::printf("(root)\n");
} else { } else {
std::printf("%s\n", data.c_str()); 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();
} }
int main() { for(auto& item : std::views::reverse(parent_list)) {
test_tree(); 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; return 0;
} }