This program is automatically exiting after finishing any one action, why? - c++

My program is exiting after giving one command every time and I am unable to find a logical reason why. I have checked all my loops and if-statements for exit codes but was not able to located any.
the program includes many classes and functions, but here is main:
int main()
{
int local_location = 0;
vector<string>Inventory = { "", "", "" };
unordered_set<string> excl = { "in", "on", "the", "with" };
string word;
array<string, 2> command;
size_t n = 0;
command.at(1) = "";
command.at(0) = "";
while (n < command.size() && cin >> word) {
auto search = excl.find(word);
if (search == excl.end())
command.at(n++) = word;
}
if (command.at(0) == "look") {
look(command.at(1), local_location, Inventory);
}
else if (command.at(0) == "get") {
look(command.at(1), local_location, Inventory);
}
else if (command.at(0) == "drop") {
look(command.at(1), local_location, Inventory);
}
else if (command.at(0) == "bag") {
bag(Inventory);
}
else if (command.at(0) == "go") {
look(command.at(1), local_location, Inventory);
}
}

Loop over standard input and reset the condition on n after processing the command.
while(cin>>word)
{
auto search = excl.find(word);
if (search == excl.end())
command.at(n++) = word;
if (n== command.size())
{
// process the command
// reset n=0
}
}

Related

Concurrent file reading / writing far slower than single-threaded

I am writing a program which reads, parses, and writes large (~15Gb) text files in parallel. On a single thread, the program works very quickly, but there is a massive performance drop when I run it concurrently on several jobs (much more than to be expected from multithreading overhead).
The main file-reading/writing function takes an "SRA" object, which has two corresponding files associated with it, and the amount of RAM to dedicate, in bytes, as input. The function then reads the files chunk-buffer-wise and writes two new files that omit "error" information. The two files correspond to one another, with the information therein order-dependent. Their structure is not super important, but they look like this:
#SRR1000000.1 cor
ATATTTACCGGGTTATTCGGATTAGTTTTGGGCCCCCC
+
FFFFF:::F:::F:::,FFFF:::::::FFFFF,,,,F
#SRR1000000.2 error
ATTTTTTTTTCCCCCCGGCGGCGCGGCTTCTCGGTTAA
+
FF:FF:::::F::F::,,,,,:FFFFF,,F,F:,FF:F
#SRR1000000.3
ATTTTTTTTTCCCCCCGGCGGCGCGGCTTCTCGGTTAA
+
FF:FF:::::F::F::,,,,,:FFFFF,,F,F:,FF:F
.
.
.
The "header", beginning with "#", is associated with and identifies the next 3 lines of data, and the number after the "." denotes the order. Both files have these headers.
Below is the file reader, parser, writer function mentioned above:
// File read/parse/write function
// Takes SRA object, amount of RAM as input
// Reads objects associated files in chunks according to RAM
// Parses them to remove "errors" while writing to new files
void rem_unfix(SRA sra, long long int ram_b) {
// Get in-file / out-file paths
std::string inFile1Str(sra.get_sra_path_corr().first.c_str());
std::string inFile2Str(sra.get_sra_path_corr().second.c_str());
std::string outFile1Str(std::string(sra.get_sra_path_corr().first.replace_extension("fix.fq").c_str()));
std::string outFile2Str(std::string(sra.get_sra_path_corr().second.replace_extension("fix.fq").c_str()));
// Open streams for file processing
std::ifstream inFile1(inFile1Str);
std::ifstream inFile2(inFile2Str);
std::ofstream outFile1(outFile1Str);
std::ofstream outFile2(outFile2Str);
// Get amount of RAM to dedicate to each file (bytes)
long long int ram_b_per_file = ram_b / 2;
// Allocate space on heap for the file buffers
char * inFile1Data = new char[ram_b_per_file];
char * inFile2Data = new char[ram_b_per_file];
// Algorithmic pointer/size variables to aid in parsing
std::streamsize s1;
std::streamsize s2;
char * currPos1;
char * currPos2;
char * nlPos1;
char * nlPos2;
char * nlPos1Prev;
char * nlPos2Prev;
char * writeStart1;
char * writeStart2;
char * writeEnd1;
char * writeEnd2;
char * inFile1L;
char * inFile2L;
// Strings to ensure ends of buffers are lined up before parsing
std::string readMatch;
std::string read;
// Main loop processes files in RAM-determined chunks
while (!inFile1.eof() || !inFile2.eof()) {
// Fill buffers, count number of bytes read to account for
// end-of-file condition
inFile1.read(inFile1Data, ram_b_per_file);
inFile2.read(inFile2Data, ram_b_per_file);
s1 = inFile1.gcount();
s2 = inFile2.gcount();
currPos1 = inFile1Data;
currPos2 = inFile2Data;
nlPos1 = inFile1Data;
nlPos2 = inFile2Data;
writeStart1 = inFile1Data;
writeStart2 = inFile2Data;
inFile1L = inFile1Data + s1;
inFile2L = inFile2Data + s2;
// Line up the ends of the buffers / ifstreams so that all
// information is "paired", or that there is no piece of
// data in one buffer without its partner data in the other
if (!inFile1.eof() && !inFile2.eof()) {
// Unget/unstream character-wise until one of the buffers/ifstreams
// ends just before a header
while ((inFile1.peek() != '#' && inFile1.peek() != '>') &&
(inFile2.peek() != '#' && inFile2.peek() != '>')) {
if (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
if (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
}
// If inFile1's buffer was was first to get into position
// Get its header number, get inFile2's last header number.
// Then unstream accordingly until the two buffers end at the
// same data point in their files.
if (inFile1.peek() == '#' || inFile1.peek() == '>') {
inFile1.get();
inFile1 >> readMatch;
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
}
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
inFile2 >> read;
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
}
if (read > readMatch) {
inFile2.unget();
while (read.compare(readMatch) != 0) {
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
inFile2 >> read;
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
}
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
}
else if (read < readMatch) {
inFile1.unget();
while (read.compare(readMatch) != 0) {
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
inFile1 >> readMatch;
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
}
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
}
else {
// Buffer in position -- do nothing
}
}
// If inFile2's buffer was was first to get into position
// Get its header number, get inFile1's last header number.
// Then unstream accordingly until the two buffers end at the
// same data point in their files.
else {
inFile2.get();
inFile2 >> readMatch;
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
}
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
inFile1 >> read;
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
}
if (read > readMatch) {
inFile1.unget();
while (read.compare(readMatch) != 0) {
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
inFile1 >> read;
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
}
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
}
else if (read < readMatch) {
inFile2.unget();
while (read.compare(readMatch) != 0) {
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
inFile2 >> readMatch;
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
}
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
}
else {
// Buffer in position -- do nothing
}
}
}
// With buffers now aligned, parse them and write non-error
// information into the new files
while (nlPos1 != inFile1L && nlPos2 != inFile2L) {
nlPos1Prev = nlPos1;
nlPos2Prev = nlPos2;
nlPos1 = std::find(nlPos1 + 1, inFile1L, '\n');
nlPos2 = std::find(nlPos2 + 1, inFile2L, '\n');
if (strncmp(nlPos1 - 5, "error", 5) == 0 ||
strncmp(nlPos2 - 5, "error", 5) == 0) {
writeEnd1 = nlPos1Prev;
outFile1.write(writeStart1, writeEnd1 - writeStart1);
writeEnd2 = nlPos2Prev;
outFile2.write(writeStart2, writeEnd2 - writeStart2);
for (int i = 0; i < 3; i++) {
nlPos1 = std::find(nlPos1 + 1, inFile1L, '\n');
nlPos2 = std::find(nlPos2 + 1, inFile2L, '\n');
}
writeStart1 = nlPos1;
writeStart2 = nlPos2;
}
}
outFile1.write(writeStart1, inFile1Data + s1 - writeStart1);
outFile2.write(writeStart2, inFile2Data + s2 - writeStart2);
}
inFile1.close();
inFile2.close();
outFile1.close();
outFile2.close();
}
The function, albeit a bit spaghetti-ish, works fine. I call it into concurrency with the below function, which leverages a "threadPool" object, for which the header, implementation files are at the bottom of the question:
// Concurrency function which starts parallel file-pair-processing
// jobs for each **"SRA"** object in its input vector.
void rem_unfix_bulk(std::vector<SRA> sras, int numThreads, int ram_gb) {
long long int ram_b = stoi(ram_gb) * 1000000000;
long long int ram_b_per_thread = ram_b / numThreads;
// Instantiate thread pool with numThreads threads to handle jobs
threadPool fileCorrPool;
fileCorrPool.start(numThreads);
// Add queue jobs to thread pool
for (auto sra : sras) {
if (fs::exists(sra.get_sra_path_corr_fix().first.c_str())) {
continue;
}
fileCorrPool.queueJob([sra, ram_b_per_thread {rem_unfix_pe(sra, ram_b_per_thread);});
}
fileCorrPool.stop();
}
threadPool object header file (thread_pool.h):
#include <thread>
#include <mutex>
#include <functional>
#include <vector>
#include <queue>
#include <condition_variable>
class threadPool {
public:
void start(int threadNum);
void queueJob(const std::function<void()>& job);
void stop();
bool busy();
private:
void threadLoop();
bool endProc = false;
std::mutex queue_mutex;
std::condition_variable mutex_condition;
std::vector<std::thread> threads;
std::queue<std::function<void()>> jobs;
};
threadPool object implementation file (thread_pool.cpp):
#include "thread_pool.h"
void threadPool::start(int threadNum) {
threads.resize(threadNum);
for (int i = 0; i < threadNum; i++) {
threads.at(i) = std::thread(&threadPool::threadLoop, this);
}
}
void threadPool::threadLoop() {
while (true) {
std::function<void()> job;
{
std::unique_lock<std::mutex> lock(queue_mutex);
mutex_condition.wait(lock, [this] {
return (!jobs.empty() || endProc);
});
if (jobs.empty() && endProc) {
return;
}
job = jobs.front();
jobs.pop();
}
job();
}
}
void threadPool::queueJob(const std::function<void()>& job) {
{
std::unique_lock<std::mutex> lock(queue_mutex);
jobs.push(job);
}
mutex_condition.notify_one();
}
bool threadPool::busy() {
bool poolBusy;
{
std::unique_lock<std::mutex> lock(queue_mutex);
poolBusy = jobs.empty();
}
return poolBusy;
}
void threadPool::stop() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
endProc = true;
}
mutex_condition.notify_all();
for (std::thread& t : threads) {
t.join();
}
threads.clear();
}

Converting a cstring to camelcase

So my task is to fill out my function to work with a test driver that feeds it a random string during every run. For this function I have to convert the first character of every word to a capital and everything else must be lower.
It mostly works but the issue i'm having with my code is that it won't capitalize the very first character and if there is a period before the word like:
.word
The 'w' in this case would remain lower.
Here is my source:
void camelCase(char line[])
{
int index = 0;
bool lineStart = true;
for (index;line[index]!='\0';index++)
{
if (lineStart)
{
line[index] = toupper(line[index]);
lineStart = false;
}
if (line[index] == ' ')
{
if (ispunct(line[index]))
{
index++;
line[index] = toupper(line[index]);
}
else
{
index++;
line[index] = toupper(line[index]);
}
}else
line[index] = tolower(line[index]);
}
lineStart = false;
}
Here's a solution that should work and is a bit less complicated in my opinion:
#include <iostream>
#include <cctype>
void camelCase(char line[]) {
bool active = true;
for(int i = 0; line[i] != '\0'; i++) {
if(std::isalpha(line[i])) {
if(active) {
line[i] = std::toupper(line[i]);
active = false;
} else {
line[i] = std::tolower(line[i]);
}
} else if(line[i] == ' ') {
active = true;
}
}
}
int main() {
char arr[] = "hELLO, wORLD!"; // Hello, World!
camelCase(arr);
std::cout << arr << '\n';
}
The variable active tracks whether the next letter should be transformed to an uppercase letter. As soon as we have transformed a letter to uppercase form, active becomes false and the program starts to transform letters into lowercase form. If there's a space, active is set to true and the whole process starts again.
Solution using std::string
void toCamelCase(std::string & s)
{
char previous = ' ';
auto f = [&](char current){
char result = (std::isblank(previous) && std::isalpha(current)) ? std::toupper(current) : std::tolower(current);
previous = current;
return result;
};
std::transform(s.begin(),s.end(),s.begin(),f);
}

How to perform other operations when my tokenizer recognizes a token?

I have written a simple tokenizer that will split a command line into seperate lines each containing a single word. I am trying to ...
Make the program close if the first word of a command line is "quit"
Recognize instructions such as "Pickup", "Save", and "Go" in which the compiler will then look to the next token.
My idea has been to use a simple switch with cases to check for these commands, but I cannot figure out where to place it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char command[256];
int commandIndex;
char token[32];
int isWhiteSpace(char character) {
if (character == ' ') {
return 1;
}
else if(character == '\t') {
return 1;
}
else if(character < ' ') {
return 1;
}
else {
return 0;
}
} char* getToken() {
int index = 0; // Skip white spaces
while(commandIndex<256 && isWhiteSpace(command[commandIndex])) {
commandIndex ++;
} // If at end of line return empty token
if(commandIndex>=256) {
token[0] = 0;
return token;
} // Capture token
while(commandIndex<256 && !isWhiteSpace(command[commandIndex])) {
token[index] = command[commandIndex];
index++;
commandIndex ++;
}
token[index] = 0;
return token;
}
void main() {
printf("Zeta - Version 2.0\n");
while(1) {
printf("Command: ");
gets_s(command);
commandIndex = 0;
char* token = getToken();
while (strcmp(token,"") != 0) {
printf("%s\n", token);
token = getToken();
}
}
}
A little reorganization of the loop you have in main will do it.
int main() {
printf("Zeta - Version 2.0\n");
bool done = false;
while (!done) {
printf("Command: ");
gets_s(command);
commandIndex = 0;
char* token = getToken();
if (strcmp(token, "quit") == 0) {
done = true;
} else if (strcmp(token, "pickup") == 0) {
doPickup();
} else if (strcmp(token, "save") == 0) {
char * filename = getToken();
doSave(filename);
} ...
}
return 0;
}
You can't use a switch statement with strings, so you just use a bunch of if ... else if ... statements to check for each command. There are other approaches, but this one required the fewest changes from the code you already have.
In the example, under the handling for "save" I showed how you can just call getToken again to get the next token on the same command line.
(Note that I also fixed the return value for main. Some compilers will let you use void, but that's not standard so it's best if you don't do that.)

Testing if the string meets the Right format C++

I am currently trying to test if a read in string matches the following format, without the use of regex.
The format the code should be in, is:
Supplier Reference: XXXXXXX
Date & Time: XXXX
Name of Device: XXXXX
Priority: X
IP Address: XXXXXXXXXXXXXXXXXXXX
Event ID: XXXXXX
Description of Event: XXXXXXXXXXXX
I want the code to have a cout << "Format is incorrect" << endl;.
This is edit, taken out previous attempt and gone back to basics to explain my logic:
using namespace std;
int f;
int main()
{
string mystring;
ifstream myfile ("test.txt");
if (myfile.is_open())
{ while (getline (myfile,mystring))
{
//searches the text entered//
string search;
size_t pos;
{
//searches the text for the Date entry//
{
search = "Supplier Reference:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f=f-1;
}
else
{
++f;
}
}
}
{
search = "Date & Time:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "Name of Device:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "Priority:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "IP Address";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "Event ID:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "Description of Event:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
}
}
{
if (f>35)
cout << f << "Field is missing, Ticket is formatted incorrectly" << endl;
}
}
system ("pause");
return 0;
}
I know the code is incredibly repetitive. Cheep and Cheerful is what I'm aiming for.
I was hoping someone could let me know how to test for the order of the lines?
One way to solve this is to read seven lines (one for each line of data). If a line is empty, then discard it and don't count it.
Then for each line, you split it into two strings at the colon ':'. Use the left part (e.g. "Supplier Reference") as the key into a std::map with the right part as data.
Then just loop over the map and make sure that each key matches the needed keys from the file. If a key is missing, or an unknown key is in the map (or if there are not enough lines when reading from the file) your have a format error.

C++, How do get this function to delete the string stored in the array?

I have a delete function that is supposed to delete a string in an array by writing over it with the previous strings.
The look function see's that Overide matches and should be deleted. But the code i wrote for the loop in Delete is not removing that first spot in the array that Overide has taken up, and the output remains unchanged.
Also each phrase after + is being added into the array so four spots are taken in the array, and sorry i could not make that part look better the formatting screwed it up.
int AR::Look(const std::string & word)
{
int result = -1;
for(int i=0; i<counter; ++i)
{
if( con[i].find(word) != std::string::npos)
result = i;
}
return result;
}
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout<<"word not found\n";
}
else
{
for(int i=0; i<counter-1,i++;)
{
con[i]= con[i+1];
}
}
}
AR their
Ar(1);
theirAr + "Overload the +" + " operator as a member function " + "with chaining to add a string " + "to an Arrary object.";
cout<<theirAr<<endl<<endl;
cout<<"testing Delete and Look. <<endl;
theirAr.Delete("XXXXXX");
theirAr.Delete("Overload");
cout<<"Output after Delete and Look called\n";
cout<<theirArray<<endl<<endl;
You are locating the String but only use the value to write an error if it does not appear; if you find the string at pos N you will delete the first string anyway:
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout<<"word not found\n";
}
else
{
for(int i=0;i<counter-1,i++;) <--- Why don't you use loc here???
{
con[i]= con[i+1];
}
}
}
Also, your Look method would be better returning after the first match:
for ... {
if( con[i].find(word) != std::string::npos)
return i;
}
return -1;
Not sure if this is your problem, but shouldn't this be like so?
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout<<"word not found\n";
}
else
{
for(int i=loc;i<counter-1,i++;) // changes in this line
{
con[i]= con[i+1];
}
}
}
Start at where you found the string and start shuffling them backwards. Also, what shortens the array? i.e. drops the last element off. Looks like that is missing too.
Try this instead:
int AR::Look(const std::string & word)
{
for (int i = 0; i < counter; ++i)
{
if (con[i].find(word) != std::string::npos)
return i;
}
return -1;
}
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout << "word not found" << endl;
}
else
{
for (int i = loc+1; i < counter; ++i)
{
con[i-1] = con[i];
}
--counter;
}
}