Refactor for robustness and clarity
This commit is contained in:
		@@ -6,7 +6,7 @@
 | 
			
		||||
#include "graph.hpp"
 | 
			
		||||
 | 
			
		||||
void graph::print () {
 | 
			
		||||
   printf("np: %d\tnr: %d\n", num_processes, num_resources);
 | 
			
		||||
   printf("resource_counts:\n"); for (auto e: resource_counts) printf("%d\t", e); printf("\n");
 | 
			
		||||
   printf("matrix:\n"); for (auto x: matrix.data) {for (auto y: x) printf("%d\t", y); printf("\n");}
 | 
			
		||||
   printf("num_processes: %d\nnum_resources: %d\n", num_processes, num_resources);
 | 
			
		||||
   printf("resource_counts: ["); for (auto e: resource_counts) printf("%d, ", e); printf("\b\b]\n");
 | 
			
		||||
   printf("matrix:\n| "); for (auto x: m) {for (auto y: x) printf("%d, ", y); printf("\b\b |\n| ");} printf("\b\b  \b\b");
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,11 +15,14 @@ int main(int argc, char** argv) {
 | 
			
		||||
   graph g;
 | 
			
		||||
 | 
			
		||||
   //TODO: Implement reading from a file
 | 
			
		||||
   g.read(filename);
 | 
			
		||||
   int err = g.read(filename);
 | 
			
		||||
   if (err) {
 | 
			
		||||
      return err;
 | 
			
		||||
   }
 | 
			
		||||
   g.print();
 | 
			
		||||
 | 
			
		||||
   // 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
 | 
			
		||||
   return 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,45 +7,51 @@
 | 
			
		||||
#include <regex>
 | 
			
		||||
#include "graph.hpp"
 | 
			
		||||
 | 
			
		||||
#define MAX_INT_LEN 16
 | 
			
		||||
 | 
			
		||||
// Vector of regices, in order of precedence. Earlier entries will be checked before later entries.
 | 
			
		||||
//* Vector of regex rules, in order of precedence. Earlier entries will be checked before later entries.
 | 
			
		||||
std::vector<std::regex> patterns = {
 | 
			
		||||
   //* Rule 1: A line starting with a % is a comment, and should not be parsed
 | 
			
		||||
   std::regex("^\\s*(%)"),
 | 
			
		||||
   //* Rule 2: A line starting with `num_processes=` contains the number of processes
 | 
			
		||||
   std::regex("^.*(num_processes)\\s*=\\s*(\\d+).*"),
 | 
			
		||||
   //* Rule 3: A line starting with `num_resources=` contains the number of resources
 | 
			
		||||
   std::regex("^.*(num_resources)\\s*=\\s*(\\d+)"),
 | 
			
		||||
   //* Rule 4: A line containing only comma-separated values should be captured completely
 | 
			
		||||
   std::regex("^([\\-0-9, ]+)") // matches comma-separated space-separated signed decimal integers
 | 
			
		||||
   //* Rule 1: A line containing % is a comment, and should not be parsed
 | 
			
		||||
   std::regex("(%)"),
 | 
			
		||||
   //* Rule 2: A line containing `num_processes` contains the number of processes
 | 
			
		||||
   std::regex("(num_processes)\\D*(\\d+)"),
 | 
			
		||||
   //* Rule 3: A line containing `num_resources` contains the number of resources
 | 
			
		||||
   std::regex("(num_resources)\\D*(\\d+)"),
 | 
			
		||||
   //* Rule 4: A line containing integers should be saved somewhere
 | 
			
		||||
   std::regex("(-?[0-9]+.*-?[0-9]+)") // Magical!
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// convert comma-separated string s to vector<int>
 | 
			
		||||
std::vector<int> stovi (const std::string &s);
 | 
			
		||||
 | 
			
		||||
// TODO: Implement reading from a file
 | 
			
		||||
void graph::read(std::string filename) {
 | 
			
		||||
 | 
			
		||||
   // Open file with name filename as read-only
 | 
			
		||||
   std::fstream f; f.open(filename, f.in);
 | 
			
		||||
   // TODO: Check for file IO errors (I might have a solution for that in another project)
 | 
			
		||||
 | 
			
		||||
// Say hi to Stovey, here to bake your cakes.
 | 
			
		||||
//* convert string s to vector<int> no matter the cost
 | 
			
		||||
std::vector<int> stovi (const std::string &s) {
 | 
			
		||||
   // Create the number classification rule
 | 
			
		||||
   std::regex rule("-?[0-9]+");
 | 
			
		||||
   // Make a new tokenizing iterator using the rule
 | 
			
		||||
   std::sregex_token_iterator start{s.begin(), s.end(), rule, 0}, end;
 | 
			
		||||
   // Match the numbers
 | 
			
		||||
   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()) {
 | 
			
		||||
      // acquire a line
 | 
			
		||||
      std::string line;
 | 
			
		||||
      std::getline (f, line);
 | 
			
		||||
 | 
			
		||||
      // Iterate over each pattern, and grab the associated data
 | 
			
		||||
      for (auto pattern: patterns) {
 | 
			
		||||
      for (const auto &pattern: patterns) {
 | 
			
		||||
         std::smatch res;
 | 
			
		||||
         // Capture data with a regex search, using the pattern
 | 
			
		||||
         if (std::regex_search (line, res, pattern)) {
 | 
			
		||||
            // get the pattern type, value
 | 
			
		||||
            std::string type = res.format("$1"), value = res.format("$2");
 | 
			
		||||
            // Handle the pattern
 | 
			
		||||
            //   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
 | 
			
		||||
            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
 | 
			
		||||
            if (type == "num_resources") { num_resources = std::stoi(value); } else
 | 
			
		||||
 | 
			
		||||
            //   Rule 4: If this line is a comma-separated list of numbers,
 | 
			
		||||
            //     and this is the first match, assign it to resource counts
 | 
			
		||||
            //   Rule 4: If this line is a comma-separated list of numbers:
 | 
			
		||||
            //     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
 | 
			
		||||
            //     and this is a subsequent match, push it onto the matrix
 | 
			
		||||
            { matrix.data.push_back(stovi(type)); }
 | 
			
		||||
 | 
			
		||||
            // If a pattern is matched, go to the next line and skip evaluating other patterns
 | 
			
		||||
            { m.push_back(stovi(type)); }
 | 
			
		||||
            break;
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   // Close file
 | 
			
		||||
   f.close();
 | 
			
		||||
   // TODO: Check for file IO errors (Shouldn't be any)
 | 
			
		||||
   //* Test validity of the input file
 | 
			
		||||
   // Check if all sections are properly defined:
 | 
			
		||||
   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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
   // fstream destructor closes file when going out of scope
 | 
			
		||||
   // in this house we RAII sometimes.
 | 
			
		||||
   return ret;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user