Refactor for robustness and clarity

This commit is contained in:
John 2022-04-23 04:47:55 -05:00
parent 8c04650caf
commit 6603f96d69
6 changed files with 97 additions and 72 deletions

View File

@ -6,6 +6,6 @@ Project 2 for CSCE4600, for Team G4
Build with `make` Build with `make`
Run with `make run` Run with `./main.out filename`
Clean with `make clean` Clean with `make clean`

View File

@ -11,9 +11,8 @@ public:
graph() {} graph() {}
// Initializers: // Initializers:
// Read a graph from a file // Read a graph from a file
void read(std::string filename); int read(std::string filename);
// TODO: generate a random graph
void random(int processes, int resources);
// check functions: // check functions:
// is the graph... // is the graph...
bool reducible();// ? bool reducible();// ?
@ -23,17 +22,13 @@ public:
// print the graph // print the graph
void print (); void print ();
struct m{ typedef std::vector<std::vector<int>> matrix;
int x, y;
std::vector<std::vector<int>> data;
};
private: private:
int num_processes = 0; int num_processes = 0;
int num_resources = 0; int num_resources = 0;
std::vector<int> resource_counts; std::vector<int> resource_counts;
struct m matrix; // Tell me, Mr. Anderson, what good is a phone call if you are unable to speak? matrix m; // Tell me, Mr. Anderson, what good is a phone call if you are unable to speak?
bool is_blocked(int process_id);
}; };
#endif #endif

View File

@ -6,7 +6,7 @@
#include "graph.hpp" #include "graph.hpp"
void graph::print () { void graph::print () {
printf("np: %d\tnr: %d\n", num_processes, num_resources); printf("num_processes: %d\nnum_resources: %d\n", num_processes, num_resources);
printf("resource_counts:\n"); for (auto e: resource_counts) printf("%d\t", e); printf("\n"); printf("resource_counts: ["); for (auto e: resource_counts) printf("%d, ", e); printf("\b\b]\n");
printf("matrix:\n"); for (auto x: matrix.data) {for (auto y: x) printf("%d\t", y); printf("\n");} printf("matrix:\n| "); for (auto x: m) {for (auto y: x) printf("%d, ", y); printf("\b\b |\n| ");} printf("\b\b \b\b");
} }

View File

@ -15,11 +15,14 @@ int main(int argc, char** argv) {
graph g; graph g;
//TODO: Implement reading from a file //TODO: Implement reading from a file
g.read(filename); int err = g.read(filename);
if (err) {
return err;
}
g.print(); g.print();
// TODO: Implement graph reduction and/or knot detection // TODO: Implement graph reduction and/or knot detection
printf("Graph is %s\n", g.reducible()?"not reducible (deadlock!)":"reducible (no deadlock!)");//? printf("Graph is %s\n", g.reducible()?"not reducible! Deadlock!":"reducible! No deadlock!");//?
// TODO: Destroy the graph created by read_file // TODO: Destroy the graph created by read_file
return 0; return 0;

View File

@ -7,45 +7,51 @@
#include <regex> #include <regex>
#include "graph.hpp" #include "graph.hpp"
#define MAX_INT_LEN 16 //* Vector of regex rules, in order of precedence. Earlier entries will be checked before later entries.
// Vector of regices, in order of precedence. Earlier entries will be checked before later entries.
std::vector<std::regex> patterns = { std::vector<std::regex> patterns = {
//* Rule 1: A line starting with a % is a comment, and should not be parsed //* Rule 1: A line containing % is a comment, and should not be parsed
std::regex("^\\s*(%)"), std::regex("(%)"),
//* Rule 2: A line starting with `num_processes=` contains the number of processes //* Rule 2: A line containing `num_processes` contains the number of processes
std::regex("^.*(num_processes)\\s*=\\s*(\\d+).*"), std::regex("(num_processes)\\D*(\\d+)"),
//* Rule 3: A line starting with `num_resources=` contains the number of resources //* Rule 3: A line containing `num_resources` contains the number of resources
std::regex("^.*(num_resources)\\s*=\\s*(\\d+)"), std::regex("(num_resources)\\D*(\\d+)"),
//* Rule 4: A line containing only comma-separated values should be captured completely //* Rule 4: A line containing integers should be saved somewhere
std::regex("^([\\-0-9, ]+)") // matches comma-separated space-separated signed decimal integers std::regex("(-?[0-9]+.*-?[0-9]+)") // Magical!
}; };
// convert comma-separated string s to vector<int> // Say hi to Stovey, here to bake your cakes.
std::vector<int> stovi (const std::string &s); //* convert string s to vector<int> no matter the cost
std::vector<int> stovi (const std::string &s) {
// TODO: Implement reading from a file // Create the number classification rule
void graph::read(std::string filename) { std::regex rule("-?[0-9]+");
// Make a new tokenizing iterator using the rule
// Open file with name filename as read-only std::sregex_token_iterator start{s.begin(), s.end(), rule, 0}, end;
std::fstream f; f.open(filename, f.in); // Match the numbers
// TODO: Check for file IO errors (I might have a solution for that in another project) std::vector<int> res;
for (auto i = start; i != end; ++i) res.push_back(atoi(i->str().c_str()));
// give the numbers back
return res;
}
//* Read from a file of name `filename`
int graph::read(std::string filename) {
// Open file with name filename as input fstream
std::ifstream f(filename);
// Read the entire file
while (!f.eof()) { while (!f.eof()) {
// acquire a line // acquire a line
std::string line; std::string line;
std::getline (f, line); std::getline (f, line);
// Iterate over each pattern, and grab the associated data // Iterate over each pattern, and grab the associated data
for (auto pattern: patterns) { for (const auto &pattern: patterns) {
std::smatch res; std::smatch res;
// Capture data with a regex search, using the pattern
if (std::regex_search (line, res, pattern)) { if (std::regex_search (line, res, pattern)) {
// get the pattern type, value // get the pattern type, value
std::string type = res.format("$1"), value = res.format("$2"); std::string type = res.format("$1"), value = res.format("$2");
// Handle the pattern // Handle the pattern
// Rule 1: If line is a comment, ignore it and move on // Rule 1: If line is a comment, ignore it and move on
if (type == "%"); else if (type == "%") break;
// Rule 2: If num_processes= matched, assign value to num_processes // Rule 2: If num_processes= matched, assign value to num_processes
if (type == "num_processes") { num_processes = std::stoi(value); } else if (type == "num_processes") { num_processes = std::stoi(value); } else
@ -53,32 +59,48 @@ void graph::read(std::string filename) {
// Rule 3: If num_resources= matched, assign value to num_resources // Rule 3: If num_resources= matched, assign value to num_resources
if (type == "num_resources") { num_resources = std::stoi(value); } else if (type == "num_resources") { num_resources = std::stoi(value); } else
// Rule 4: If this line is a comma-separated list of numbers, // Rule 4: If this line is a comma-separated list of numbers:
// and this is the first match, assign it to resource counts // If resource_counts is empty, assume this is the resource counts,
// else it's part of the matrix being reloaded
if (!resource_counts.size()) { resource_counts = stovi(type); } else if (!resource_counts.size()) { resource_counts = stovi(type); } else
// and this is a subsequent match, push it onto the matrix { m.push_back(stovi(type)); }
{ matrix.data.push_back(stovi(type)); }
// If a pattern is matched, go to the next line and skip evaluating other patterns
break; break;
} }
} }
} }
// Close file //* Test validity of the input file
f.close(); // Check if all sections are properly defined:
// TODO: Check for file IO errors (Shouldn't be any) const char errmsg[] = "%s: Definition failed for %s\n";
int ret = 0;
if (!num_processes){
printf(errmsg, filename.c_str(), "num_processes");
ret |= 0b00001;
}
if (!num_resources){
printf(errmsg, filename.c_str(), "num_resources");
ret |= 0b00010;
}
if (resource_counts.size() != num_resources){
printf(errmsg, filename.c_str(), "resource counts");
ret |= 0b00100;
}
if (m.size() != num_processes + num_resources){
printf(errmsg, filename.c_str(), "adjacency matrix rows");
ret |= 0b01000;
}
for (auto i: m) {
if (i.size() != num_processes + num_resources)
ret |= 0b10000;
}
if (ret & 0b10000) {
printf(errmsg, filename.c_str(), "adjacency matrix columns");
}
if (ret) {
printf("Check to ensure your input file is correct and follows the Rules.\n");
}
return; // fstream destructor closes file when going out of scope
} // in this house we RAII sometimes.
return ret;
std::vector<int> stovi (const std::string &s) {
// Create the number classifier
std::regex pattern("[0-9]+");
std::sregex_token_iterator first{s.begin(), s.end(), pattern, 0}, last;
// Match the numbers
std::vector<int> res;
for (auto i = first; i != last; ++i) res.push_back(atoi(i->str().c_str()));
// give the numbers back
return res;
} }

View File

@ -1,13 +1,14 @@
% This file is a very poorly formatted example file, which contains all sorts of garbage % This file is a very poorly formatted example file, which contains all sorts of garbage
% This was written to ensure the parser is as robust as possible, and won't crash on malformed input % This was written to stress-test the parser
nv249hvbwer8oysbvdofuvbfdz wsdfabsv num_processes = 4 this is horrible to read!
// Gee, this isn't actually a comment is it? nv249hvbwer8oysbvdofuvbfdzwsdfabsvnum_processesbgskjhdfd=lbahfbzjhxbc,4gsv4wf5fewf6, 7, 8
# but most of that is there to distract the program! ^^^^ Believe it or not, this is a num_processes line! ^^^^
// Gee, this isn't actually a comment is it? As long as I don't include a number, it won't care.
[][][][]\\\\\';./` num_resources= 4ibeoifbavdivbkdhbz [][][][]\\\\\';./` num_resources= 4ibeoifbavdivbkdhbz
% lines beginning with % are comments % lines containing % are comments
% for example: num_processes = 128314 for example: num_processes = 128314%
% The first line containing a list of numbers will be interpreted as resource_counts % The first non-comment line containing a list of numbers will be interpreted as resource_counts
12 ,14,16 , 18 12 ,14,16 , 18
% this line is missing a comma % this line is missing a comma
1,2 3,4,5,6,7,8 1,2 3,4,5,6,7,8
@ -16,8 +17,12 @@ nv249hvbwer8oysbvdofuvbfdz wsdfabsv num_processes = 4
% and this one, before the comma % and this one, before the comma
1 ,2 ,3 ,4 ,5 ,6 ,7,8 1 ,2 ,3 ,4 ,5 ,6 ,7,8
% nevertheless, it keeps on chugging. % nevertheless, it keeps on chugging.
1,2,3,4,5,6,7,8 ~~~1~~~2~~~3~~~4~~~5~~~6~~~7~~~8~~~
1,2,3,4,5,6,7,8 1a 2b 3c, 4d 5e 6f, 7g 8h
1,2,3,4,5,6,7,8 ^^^^ Testing mixed letters and numbers ^^^^
1,2,3,4,5,6,7,8 @Xx_1_2_3_4_5_6_7_8_()_xX#
1,2,3,4,5,6,7,8 words, words, words!
vvvv testing negative numbers vvvv
1,-2,3,4,5,6,-7,8
-1,2,3,4,5,6,7,-8