aboutsummaryrefslogtreecommitdiff
path: root/Circuit.cpp
blob: 57fbb02eae15bcfedf72abdcec34381b94b62176 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <format>

#include "Circuit.h"
#include "Exception.h"
#include "NodeFactory.h"

#include "NodeOutputVisitor.h"

using std::format;

void Circuit::create(string label, vector<string> nodes) {
	if (nodes.size() == 1 && NodeFactory::has_type(nodes[0]))
		return new_node(label, nodes[0]);

	new_net(label, nodes);
	loops.add_connection(label, nodes);
}

void Circuit::new_node(string label, string type) {
	if (nodes.find(label) != nodes.end())
		throw CircuitException("node with label \"%s\" already exists!", label.c_str());

	Node * node = NodeFactory::create(type);
	if (node == nullptr)
		throw CircuitException("unknown type \"%s\"", type.c_str());

	nodes[label] = node;
}

void Circuit::new_net(string src, vector<string> dests) {
	Net * net = new Net();
	nets.push_back(net);

	Node * node = find_node(src);
	if (node == nullptr)
		throw CircuitException("unknown source node \"%s\"", src.c_str());
	node->setOutput(net);

	for (auto dest : dests) {
		Node * node = find_node(dest);
		if (node == nullptr)
			throw CircuitException("unknown destination node \"%s\"", dest.c_str());
		node->addInput(net);
	}
}

void Circuit::sim() {
	for (auto & pair : nodes) {
		try {
			Node * node = pair.second;
			node->sim();
		} catch (CircuitException & e) {
			const char * label = "???";
			Node * node = e.node;
			if (node != nullptr) {
				auto it = std::find_if(nodes.begin(), nodes.end(),
					[node](auto && n) { return n.second == node; });
				if (it != nodes.end()) label = it->first.c_str();
			}
			throw CircuitException("node %s: %s", label, e.what());
		}
	}
}

Node * Circuit::find_node(string label) {
	auto map_index = this->nodes.find(label);
	if (map_index == nodes.end()) return nullptr;
	return map_index->second;
}

Circuit::~Circuit() {
	for (auto & n : nodes)
		delete n.second;
	for (auto & n : nets)
		delete n;
}

string Circuit::result() {
	string output;

	for (auto & n : nodes) {
		NodeOutputVisitor visitor;
		n.second->accept(visitor);
		if (!visitor.output_node) continue;

		output += format("{}: {}\n", n.first, std::to_string(visitor.level));
	}

	return output;
}