Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

I need help on below projects. I finished implementing them, but I need your help find some bugs. Thank you in advance! Instruction: The first

I need help on below projects. I finished implementing them, but I need your help find some bugs.

Thank you in advance!

Instruction:

The first portion of this workshop consists of modules:

  • w5 (supplied) - do not modifythis file!
  • Job
  • CentralUnit
  • Processor

Job module

This module defines a class that holds information about a single job that requires handling.

Private Data

Design and code a class named Job that should be able to store the following information (for each attribute, you can chose any type you think is appropriate--you must be able to justify the decisions you have made):

  • a title describing the job to be done.
  • a positive number indicating the units of work to be done to finish the job.
  • a positive number indicating the remaining units of work to be done to finish the job.
  • a flag to determine if the job is active or not.

Public Members

a default constructor that sets the job to an empty, inactive state.

a custom constructor that receives the title of the job. For simplicity, the number of units of work to be done to finish the job is equal to the remainder from dividing the number of characters in the title by 10 and adding 1.

is_active(): a query that returns whether the job is active or not.

is_complete(): a query that returns whether the job is complete or not (no remaining units of work).

name(): a query that returns a copy of the title of the job.

display(): inserts the job details into the output stream (received as an argument) and returns nothing. The output should be displayed in the following format:

`JOB NAME` [XX/XX remaining] 

where the XX's are the remaining and total work represented with two digits padded with zeroes.

overload the appropriate operator to make this object behave like a function object. The purpose of this member is to perform work on the job to progress towards completion. When called, this function takes the units of work handled (as a positive number) as its only argument and reduces the remaining work by it. If there is no remaining work, the job is marked as inactive. If the handled work is more than the remaining work, the remaining work is set to 0 and your function reports an std::underflow_error to the caller.

FREE Helpers

  • std::ostream& operator<<(std::ostream&, Job&): displays the job details.

Add any other function that is required by your design, but make sure they are private members!

Central Unit module

This module defines a family of classes that represents a central (or managing or main) unit that hosts and coordinates individual units to handle jobs.

Private Data

Design and code a family of classes named CentralUnit. Since you are creating a family of classes, its members must be defined in the header file. A CentralUnit object stores the following information:

  • std::string m_type: a short name describing the type of work this central unit will be coordinating.
  • T** m_items: a dynamically-allocated array of pointers to individual units of type T (i.e. any type). These are the units that will be hosted in the CentralUnit object.
  • Job* m_jobs[ ]: a statically-allocated array of pointers to jobs that are queued up and waiting to be handled by an individual unit when the central unit is run. Only a maximum of 4 jobs can be queued up at any given time.
  • size_t m_size: stores the number of individual units hosted by the central unit.
  • size_t m_count: stores the number of jobs queued up and waiting to be handled.

Public Data

  • std::ostream& log: a class member that stores a reference to an output stream that will be used for logging information. Defaults to std::cout.

Public Members

a custom constructor that receives the type of work handled by the central unit as its first argument and a C-style null-terminated string holding the name of a file that will initialize this object as its second argument. Each line in the file provided will hold information about an individual unit that this object hosts, formatted as:

UNIT_TYPE | UNIT_NAME | WORK_CAPACITY 

If the file cannot be opened, report an std::invalid_argument error with the messsage File cannot be opened.. Create a store the individual units based on each line and remove all leading and trailing spaces for each token. Consider using std::stoi() to parse WORK_CAPACITY as a positive number.

Note: std::stoi can report an error if it fails to convert WORK_CAPACITY to a number. Capture and handle this error by defaulting to a work capacity of 1.

ASSUMPTION: In this design, the constructor for T takes the address of the hosting central unit (the current object in this case) as its first argument, two strings as its next two arguments (the unit type and name), and a positive number (work capacity) as its last argument.

all standard member functions needed to properly handle the dynamically-allocated data member. This design does not support copy operations -- if creating a new instance from a copy, report an exception, and assigning a copy of a CentralUnit should result in a compile-time error.

operator+=(): takes the name of a job as an argument, creates a new Job object that is added to the job queue, and returns a reference to the current central unit. If the queue is full, report an error of type std::string.

run(): runs a cycle for each individual unit. Goes through every unit and runs it once. While going through every unit, if there are jobs queued up and a unit is available (has no job assigned), remove the last job from the queue and assign it to the unit before running the unit.

ASSUMPTION: In this design, units of type T implement a run() method that does work towards completing a job.

has_jobs(): a query that returns if there are any jobs assigned to its units or waiting to be assigned to a unit. This query does not change the state of the central unit.

get_available_units(): a query that returns the number of units without jobs assigned to them. This query does not change the state of the central unit.

Add any other function that is required by your design, but make sure they are private members!

Processor Module

This module defines a microprocessor as a specific type of individual unit that can process a job.

Private Data

Design and code a class named Processor that stores the following information (for each attribute, you can chose any type you think is appropriate--you must be able to justify the decisions you have made):

  • m_host: stores the address of the hosting central unit that specifically hosts processors.
  • m_brand: stores the name of the brand of microprocessor, representing the unit type.
  • m_code: stores a short text descriptor of the microprocessor, representing the unit name.
  • m_power: stores the number of work units that the microprocessor can process for a job in a single run, representing the unit's work capacity.
  • m_current: stores the address of the job currently assigned to the microprocessor to be processed.

Public Members

  • a custom constructor that takes the address of the hosting central unit, the brand, code, and power of the microprocessor as arguments and uses this data to initialize the processor.
  • void run() - perform m_power units of work on the job assigned to this processor. If the job is completed, clear and remove the job assigned to this processor. If an std::underflow_error occurs, handle it by logging an error using the hosting central unit with the message Processed over quota for followed by the job details, and then clearing and removing the job assigned to this processor. This member does nothing if the processor isn't hosted or no job is assigned to it.
  • explicit operator bool() const - a true/false representation of the processor that returns true if a job is assigned to it, false otherwise.
  • Processor& operator+=(Job*&) - assigns a job to the processor. Report an exception if there is a job already assigned.
  • Job* get_current_job() const - a query that returns the job currently assigned to the processor.

Add any other function that is required by your design, but make sure they are private members!

w5 Module (supplied)

The tester module for this portion has been supplied. Do not modify the existing code!

When doing the workshop, you are encouraged to write your own tests, focusing on a single implemented feature at the time, until you get all functionality in place.

Sample Output

When the program is started with the command (the file processors.txt is provided):

ws processors.txt

the output should look like the one from the sample_output.txt file.

Job.h

#ifndef SDDS_JOB_H #define SDDS_JOB_H #include  namespace sdds { class Job { const char* title{}; size_t totalWork{}; size_t remainingUnitOfWork{}; bool isJobActive{}; public: Job(); Job(const char* jobTitle); bool is_active(); bool is_complete(); const char* name(); void display(std::ostream& ostr = std::cout); bool operator()(size_t workUnit); }; std::ostream& operator<<(std::ostream& ostr, Job& J); } #endif // !SDDS_JOB_H 

Job.cpp

#include  #include "Job.h" using namespace std; namespace sdds { Job::Job() {} Job::Job(const char* jobTitle) : title{ jobTitle } { totalWork = (strlen(jobTitle) % 10) + 1; } bool Job::is_active() { return isJobActive; } bool Job::is_complete() { return remainingUnitOfWork == 0; } const char* Job::name() { return title; } void Job::display(ostream& ostr) { ostr << "`" << title << "` [" << remainingUnitOfWork << "/" << totalWork << " remaining]" << endl; } bool Job::operator()(size_t workUnit) { workUnit = -remainingUnitOfWork; if (!remainingUnitOfWork) { isJobActive = false; } if (workUnit > remainingUnitOfWork) { remainingUnitOfWork = 0; throw std::underflow_error("underflow error"); } } ostream& operator<<(ostream& ostr, Job& J) { J.display(ostr); return ostr; } }

CentralUnit.h

#ifndef SDDS_CENTRALUNIT_H #define SDDS_CENTRALUNIT_H #include  #include  #include "Job.h" namespace sdds { const size_t MAX_JOB = 4; template  class CentralUnit { std::string m_type{}; T** m_items{}; // dynamically-allocated array of pointers to individual units of type T Job* m_jobs[MAX_JOB]{}; // statically-allocated array of pointers to jobs that are queued up size_t m_size{}; // number of individual units size_t m_count{}; // number of jobs queued up and waiting to be handled. public: std::ostream& log = std::cout; CentralUnit(); CentralUnit(std::string type, std::string name); CentralUnit(const CentralUnit& C); CentralUnit& operator=(const CentralUnit& C); CentralUnit(CentralUnit&& C); CentralUnit& operator=(const CentralUnit&& C); CentralUnit& operator+=(std::string jobName); void run(); bool has_jobs()const; size_t get_available_units()const; }; template CentralUnit::CentralUnit(){} template CentralUnit::CentralUnit(std::string type, std::string name) { std::ifstream file; file.open(name); std::string unit_type; std::string unit_name; std::string work_capacity = "1"; if (file.is_open()) { while (file) { cin.getline(file, unit_type, "|"); cin.getline(file, unit_name, "|"); cin.getline(file, work_capacity, " "); m_count++; } if (cin) { m_type = unit_type; m_items = new T*[strlen(unit_name) + 1]; m_size = std::stoi(work_capacity); } } else { throw std::invalid_argument("File cannot be opened"); } } template CentralUnit::CentralUnit(const CentralUnit& C) { operator=(C); } template CentralUnit& CentralUnit::operator=(const CentralUnit& C) { if (this != &C) { for (size_t i = 0, i < m_size;i++) { delete m_itmes[i]; } delete[] m_items; m_items = new T*[C.m_size]; for (size_t i = 0; i < C.m_size; i++) { m_items[i] = new T(C.m_items[i]); } m_type = C.m_type; m_jobs = C.m_jobs; m_size = C.m_size; m_count = C.m_count; } return *this; } template CentralUnit::CentralUnit(CentralUnit&& C) { operator=(move(C)); } template CentralUnit& CentralUnit::operator=(const CentralUnit&& C) { if (this != &C) { for (size_t i = 0, i < m_size; i++) { delete m_itmes[i]; } delete[] m_items; m_type = C.m_type; C.m_type = nullptr; m_items = C.m_items; C.m_items = nullptr; m_jobs = C.m_jobs; C.m_jobs = nullptr; m_size = C.m_size; C.m_size = nullptr; m_count = C.m_count; C.m_count = nullptr; } return *this; } template CentralUnit& CentralUnit::operator+=(std::string jobName) { jobName = new Job[m_count]; m_count++; if (m_count > MAXJOB) { throw std::string; } return m_jobs[m_count]; } template void sdds::CentralUnit::run() { for (size_t i = 0; i < m_size; i++) { if (m_count > 0 && m_count <= MAX_JOB) { // remove the last job from the queue and assign it to the unit m_items[m_size++] = m_bjos[m_count--]; } } } template bool CentralUnit::has_jobs()const { // returns if there are any jobs assigned to its units or waiting to be assigned to a unit return m_count > 0; } template size_t CentralUnit::get_available_units()const{ return m_count; } } #endif // !SDDS_CENTRALUNIT_H 

Processor.h

#ifndef SDDS_PROCESSOR_H #define SDDS_PROCESSOR_H #include  #include "Job.h" namespace sdds { class Processor { std::string m_host{}; std::string m_brand{}; std::string m_code{}; size_t m_power{}; // number of work units that the microprocessor can process for a job in a single run std::string m_current{}; // address of the job currently assigned to the microprocessor public: Processor(std::string address, std::string brand, std::string code, size_t power); void run(); explicit operator bool() const; Processor& operator+=(Job*&); Job* get_current_job() const; }; } #endif // !SDDS_PROCESSOR_H 

Processor.cpp

#include  #include "Processor.h" using namespace std; namespace sdds { Processor::Processor(std::string address, std::string brand, std::string code, size_t power) : m_host{ address }, m_brand{ brand }, m_code{ code }, m_power{ power } { } void Processor::run() { try { } catch (std::underflow_error) { cerr << "Processed over quota for" << endl; } } Processor::operator bool() const { return m_current != ""; } Processor& Processor::operator+=(Job*&) { // assigns a job to the processor. Report an exception if there is a job already assigned. } Job* Processor::get_current_job() const { return m_current; } }

main.cpp

#include  #include  #include  #include "CentralUnit.h" #include "Job.h" #include "Processor.h" void printLine() { std::cout << std::setfill('-') << std::setw(45) << "-" << std::setfill(' ') << " "; } void printHeader(std::string label) { size_t padLeft = (45 - label.length()) / 2; printLine(); std::cout << std::setw(padLeft) << " " << label << std::endl; printLine(); } int main(int argc, char** argv) { std::cout << "Command Line: "; printLine(); for (int i = 0; i < argc; i++) std::cout << std::setw(3) << i + 1 << ": " << argv[i] << ' '; printLine(); std::cout << " "; printHeader("CPU SETUP"); try { sdds::CentralUnit fake_host("fake", "invalid file"); } catch (std::invalid_argument& e) { std::cout << "**EXPECTED EXCEPTION: " << e.what() << std::endl; } sdds::CentralUnit* cpu = new sdds::CentralUnit("Processing", argv[1]); try { sdds::CentralUnit test_host = *cpu; } catch (...) { std::cout << "**EXPECTED EXCEPTION: Central Unit cannot be copy-assigned." << std::endl; } if (std::is_copy_assignable>::value) { std::cout << "**EXCEPTION: Central Unit should not support copy operations. " << std::endl; } if (!std::is_move_constructible>::value || !std::is_move_assignable>::value) { std::cout << "**EXCEPTION: Central Unit should support move operations. " << std::endl; } std::cout << "CPU has " << cpu->get_available_units() << " available units and has " << (cpu->has_jobs() ? "some pending" : "no") << " jobs on setup." << std::endl; printLine(); printHeader("ADD JOBS"); *cpu += "Add two numbers"; *cpu += "Join two strings"; *cpu += "Subtract n numbers"; *cpu += "Add a file"; std::cout << "Successfully added 4 jobs to the queue." << std::endl; try { *cpu += "Divide 2 integers"; } catch (...) { std::cout << "**EXPECTED EXCEPTION: Job queue is full." << std::endl; } printLine(); printHeader("RUN CPU"); std::cout << "CPU run #1" << std::endl; cpu->run(); std::cout << "CPU now has " << cpu->get_available_units() << " available units and has " << (cpu->has_jobs() ? "some pending" : "no") << " jobs after run #1." << std::endl; std::cout << "Queuing `Divide 2 integers` job" << std::endl; *cpu += "Divide 2 integers"; std::cout << std::endl; for (auto i = 0; cpu->has_jobs(); i++) { std::cout << "CPU run # " << i + 2 << std::endl; cpu->run(); std::cout << "CPU now has " << cpu->get_available_units() << " available units and has " << (cpu->has_jobs() ? "some pending" : "no") << " jobs after run #" << i + 2 << "." << std::endl; std::cout << std::endl; } printLine(); delete cpu; }

Desired output

Command Line: --------------------------------------------- 1: ws 2: processors.txt --------------------------------------------- --------------------------------------------- CPU SETUP --------------------------------------------- **EXPECTED EXCEPTION: File cannot be opened. **EXPECTED EXCEPTION: Central Unit cannot be copy-assigned. CPU has 5 available units and has no jobs on setup. --------------------------------------------- --------------------------------------------- ADD JOBS --------------------------------------------- Successfully added 4 jobs to the queue. **EXPECTED EXCEPTION: Job queue is full. --------------------------------------------- --------------------------------------------- RUN CPU --------------------------------------------- CPU run #1 Processed over quota for `Add a file` [00/01 remaining] CPU now has 2 available units and has some pending jobs after run #1. Queuing `Divide 2 integers` job CPU run # 2 CPU now has 1 available units and has some pending jobs after run #2. CPU run # 3 CPU now has 1 available units and has some pending jobs after run #3. CPU run # 4 CPU now has 2 available units and has some pending jobs after run #4. CPU run # 5 CPU now has 2 available units and has some pending jobs after run #5. CPU run # 6 CPU now has 3 available units and has some pending jobs after run #6. CPU run # 7 CPU now has 4 available units and has some pending jobs after run #7. CPU run # 8 CPU now has 5 available units and has no jobs after run #8. --------------------------------------------- 

processors.txt

 AMD | RYZEN5-2600 | 2 Intel | Ci9-9900K | 3 Intel | PENT-PRO200 | A IBM | POWER-5 | 1 Intel | C2-SOLO | 1

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Students also viewed these Programming questions