feat: init

This commit is contained in:
Flinner Yuu 2024-12-04 11:51:16 +03:00
commit c46805e77b
Signed by untrusted user: flinner
GPG Key ID: 95CE0DA7F0E58CA6
11 changed files with 710 additions and 0 deletions

24
CMakeLists.txt Normal file
View File

@ -0,0 +1,24 @@
# Minimum required version of CMake
cmake_minimum_required(VERSION 3.10)
# Project name
project(ClinicProject)
# Set the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Add the executable target for the project
add_executable(ClinicApp
main.cpp
Clinic.cpp
Patient.cpp
Visit.cpp
)
# Include directories if necessary (e.g., for .hpp files)
include_directories(${CMAKE_SOURCE_DIR})
# If you have any custom configurations or testing requirements,
# you can define them here, such as linking libraries or adding flags.

172
Clinic.cpp Normal file
View File

@ -0,0 +1,172 @@
#include "Patient.hpp"
#include <algorithm>
#include <fstream>
#include <functional>
#include <iostream>
#include <optional>
#include <sstream>
#include <sys/types.h>
#ifndef CLINIC_
#define CLINIC_
enum class MenuChoice {
NewPatient = 1,
NewVisit = 2,
DisplayPatient = 3,
Quit = 4,
};
struct Clinic {
public:
std::vector<Patient> patients;
std::string filename;
private:
// C++ types are getting crazy here :( I really miss Rust
// `std::optional` needed because a patient might not be found
// `std::reference_wrapper` because `std::optional` deoesn't accept references
// I want to reference because (I want to save cpu cycles from memory copies)
std::optional<std::reference_wrapper<Patient>>
find_patient(u_int32_t patient_id) {
auto it = std::find_if(patients.begin(), patients.end(),
[&id = patient_id](const Patient &p) -> bool {
return p.get_id() == id;
});
if (it != patients.end())
return *it;
return std::nullopt;
};
public:
Clinic(std::string filename) : filename(filename) {
/// this file contains a list of patient IDs.
// 1
// 2
// 4 (could be non-sequential
// but always sorted!)
u_int32_t patient_id;
std::ifstream file{filename};
if (!file.is_open()) {
std::cerr << "File " << filename << " couldn't be opened :(\n";
exit(1);
}
while (file >> patient_id)
patients.push_back(Patient(patient_id));
}
// writes the patients.txt file containing patient IDs.
void write_file() {
std::ofstream file{filename};
for (auto p : patients)
file << p.get_id() << "\n";
}
u_int32_t generate_id() {
u_int32_t id{};
// O(n), could be improved by using UUIDs, or store max_id in Clinic
for (auto p : patients)
id = std::max(id, p.get_id());
id++;
return id;
}
MenuChoice menu_main() {
int choice{};
std::cout << "==============================================\n";
std::cout << "Please choose a command:\n";
std::cout << "1. add new patient\n";
std::cout << "2. add new visit\n";
std::cout << "3. display patient information\n";
std::cout << "4. quit\n";
std::cout << ">> ";
std::cin >> choice;
while (choice < int(MenuChoice::NewPatient) ||
choice > int(MenuChoice::Quit)) {
std::cout << "Invalid input! Try again :)\n";
std::cout << "Please choose a command:\n";
std::cout << "1. add new patient\n";
std::cout << "2. add new visit\n";
std::cout << "3. display patient information\n";
std::cout << "4. quit\n";
std::cout << ">> ";
std::cin >> choice;
}
return static_cast<MenuChoice>(choice);
}
void menu_patient_info() {
int patient_id;
std::cout << "Patient file number: ";
std::cin >> patient_id;
auto patient = find_patient(patient_id);
if (patient.has_value())
std::cout << patient.value();
else
std::cout << "No Patient exists with id= " << patient_id << "\n";
std::cout << "--------------------\n\n";
}
void menu_add_new_patient() {
std::string reading_string;
std::string input_string;
Patient patient{};
std::stringstream patient_stream;
// not the most optimal way, but the lazy way
// see: https://ammar.engineer/posts/2023/06/03/laziness/
// this "emulates" a file so that I can resuse my >> operator
reading_string += std::to_string(generate_id()) + "\n";
std::cout << "Generate " << reading_string;
std::cout << "First name (no spaces): ";
std::cin >> input_string;
reading_string += input_string + "\n";
std::cout << "Last name (no spaces): ";
std::cin >> input_string;
reading_string += input_string + "\n";
std::cout << "Gender (M or F): ";
std::cin >> input_string;
reading_string += input_string + "\n";
std::cout << "Age: ";
std::cin >> input_string;
reading_string += input_string + "\n";
std::cout << reading_string;
patient_stream = std::stringstream(reading_string);
// all of that just for this moment:
patient_stream >> patient;
patients.push_back(patient); // save in memory
patient.write_patient(); // write to file
write_file();
}
void menu_add_vist() {
std::string reading_string;
std::string input_string;
int patient_id;
std::cout << "Patient file number: ";
std::cin >> patient_id;
std::cout << "Date:";
std::cin >> input_string;
reading_string += input_string + " ";
std::cout << "Doctor's First Name: ";
std::cin >> input_string;
reading_string += input_string + " ";
std::cout << "Doctors's Last Name: ";
std::cin >> input_string;
reading_string += input_string + " ";
std::stringstream visit_stream = std::stringstream(reading_string);
Visit visit;
visit_stream >> visit;
auto patient = find_patient(patient_id);
if (patient.has_value())
patient.value().get().add_visit(visit);
else
std::cout << "No Patient exists with id= " << patient_id << "\n";
}
};
#endif

111
Patient.cpp Normal file
View File

@ -0,0 +1,111 @@
// The class Patient stores the personal information of a patient as well as
// his/her history of medical visits as a vector of Visit objects, all as
// private data members. The class interface allows user code to:
// - Instantiate a Patient object given (as parameters) all his/her
// personal information. No visit history is required. The same
// function should also create a patient record file according to
// the format specified above.
// - Instantiate a Patient object given (as parameter) his/her ID
// number. The personal information as well as the visit history of
// the patients to be read from his existing record file.
// - Add one Visit record given a Visit object as parameter. The same
// function should record the Visit in the patient file.
// - Print the patient record according to the format specified in
// the files above using the << operator (including history)
#include "Patient.hpp"
#include "Visit.hpp"
#include <fstream>
#include <iostream>
#include <istream>
#include <ostream>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <vector>
////////////////////////////////////
// File: patient_files/3.txt //
// 3 //
// Amirah //
// Asaad //
// F //
// 26 //
// 3 1/1/2018 Abdullah Alshareef //
// 9 4/1/2018 Helen Philips //
// 14 8/1/2018 Abdullah Alshareef //
////////////////////////////////////
Patient::Patient(u_int32_t id) : id(id) {
auto patient_file_path = "patient_files/" + std::to_string(id) + ".txt";
std::ifstream patient_file{patient_file_path};
if (patient_file.is_open()) {
patient_file >> *this;
} else {
std::cerr << "Failed to read patient file at: " + patient_file_path;
exit(1);
}
}
void Patient::write_patient() {
// create patient's file
// this will overwrite any patient with the same id
auto patient_file_path = "patient_files/" + std::to_string(id) + ".txt";
std::ofstream patient_file{patient_file_path};
if (patient_file.is_open()) {
patient_file << *this;
} else {
std::cerr << "Failed to create patient file at: " + patient_file_path;
exit(1);
}
}
u_int32_t Patient::get_id() const { return id; }
void Patient::add_visit(Visit const &visit) {
visits.push_back(visit);
// could have logic to append data and not re-write the whole thing, but not
// worth it
// this rewrites the entire file each time a visits gets added
write_patient();
}
std::ostream &operator<<(std::ostream &out, Patient &patient) {
// clang-format off
out << patient.id << "\n";
out << patient.first_name << "\n"<< patient.last_name << "\n";
out << patient.gender_char() << "\n";
out << patient.age << "\n";
for (auto visit : patient.visits)
out << visit << "\n";
return out;
// clang-format on
}
std::istream &operator>>(std::istream &in, Patient &patient) {
char gender_char{};
in >> patient.id;
in >> patient.first_name >> patient.last_name;
in >> gender_char;
in >> patient.age;
patient.gender = gender_char == 'M' ? true : false;
std::string visit_string;
Visit visit{};
// read to string, convert to string stream, read from that stream again
// weird C++ gymnastics (or bad design by me)
getline(in, visit_string); // first string is always empty for some reason
while (getline(in, visit_string)) {
std::stringstream visit_stream(visit_string);
visit_stream >> visit;
patient.visits.push_back(visit);
}
return in;
// clang-format on
}

53
Patient.hpp Normal file
View File

@ -0,0 +1,53 @@
#ifndef PATIENT_HPP
#define PATIENT_HPP
#include "Visit.hpp"
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <sys/types.h>
#include <vector>
////////////////////////////////////
// File: patient_files/3.txt //
// 3 //
// Amirah //
// Asaad //
// F //
// 26 //
// 3 1/1/2018 Abdullah Alshareef //
// 9 4/1/2018 Helen Philips //
// 14 8/1/2018 Abdullah Alshareef //
////////////////////////////////////
class Patient {
private:
// clang-format off
u_int32_t id;
std::string first_name;
std::string last_name;
bool gender; // true gender = M, false gender = F
u_int32_t age;
std::vector<Visit> visits;
char gender_char() { return gender ? 'M' : 'F'; }
public:
void write_patient();
Patient(){};
Patient(u_int32_t id, std::string first_name, std::string last_name, bool gender, u_int age)
: id(id), first_name(first_name), last_name(last_name), gender(gender), age(age) {
// clang-format on
write_patient();
}
Patient(u_int32_t id);
u_int32_t get_id() const;
public:
void add_visit(Visit const &visit);
friend std::ostream &operator<<(std::ostream &out, Patient &patient);
friend std::istream &operator>>(std::istream &in, Patient &patient);
};
#endif

23
Visit.cpp Normal file
View File

@ -0,0 +1,23 @@
#include <iostream>
#include <istream>
#include <ostream>
#include <sys/types.h>
#include "Visit.hpp"
std::istream &operator>>(std::istream &in, Visit &visit) {
in >> visit.visit_id;
in >> visit.date;
in >> visit.doctor_first_name;
in >> visit.doctor_last_name;
return in;
}
std::ostream &operator<<(std::ostream &out, Visit &visit) {
auto v = visit;
out << v.visit_id << " " //
<< v.date << " " //
<< v.doctor_first_name << " " //
<< v.doctor_last_name;
return out;
}

35
Visit.hpp Normal file
View File

@ -0,0 +1,35 @@
#ifndef VISIT_HPP
#define VISIT_HPP
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <sys/types.h>
class Visit {
// clang-format off
private:
u_int32_t visit_id{};
u_int32_t patient_id{};//.txt
std::string date{}; //"dd/mm/yyyy"
std::string doctor_first_name{};
std::string doctor_last_name{};
// clang-format on
public:
Visit() {}
Visit(u_int32_t visit_id, u_int32_t patient_id, std::string date,
std::string doctor_first_name, std::string doctor_last_name)
: visit_id(visit_id), patient_id(patient_id), date(date),
doctor_first_name(doctor_first_name),
doctor_last_name(doctor_last_name) {}
// clang-format off
// clang-format on
friend std::istream &operator>>(std::istream &in, Visit &visit);
friend std::ostream &operator<<(std::ostream &out, Visit &visit);
};
#endif

201
linkedList.cpp Normal file
View File

@ -0,0 +1,201 @@
#include <cstddef>
#include <iostream>
#ifndef LINKED_LIST
#define LINKED_LIST
using namespace std;
struct node {
int data;
node *next;
node *previous;
};
class List {
// private:
public:
node *head{};
node *tail{};
public:
// A default constructor, which creates an empty list
List() {}
// Not specified in the HW, but needed in my opinion
List(node *head, node *tail) : head(head), tail(tail) {}
// A parametrized constructor, which creates a list out of the elements of an
// array, keeping them in the same given order.
List(char *data, size_t n) {
for (int i{0}; i < n; i++)
appendList(data[i]);
}
// A copy constructor.
List(List const &list) {
auto h = list.head;
while (h != list.tail->next) {
appendList(h->data);
h = h->next;
}
}
bool isEmptyList();
std::ostream &printList(std::ostream &out);
void prependList(int);
void appendList(int);
bool findInList(int);
void pop();
void popBack();
void removeFromList(node *);
void removeFromList(int);
friend List operator+(int const a, List const list) {
// copy
List newlist(list);
newlist.prependList(a);
return newlist;
}
friend List operator+(List const list, int a) {
// copy
List newlist(list);
newlist.appendList(a);
return newlist;
}
friend List operator+(List const list1, List const list2) {
// copies
List newlist1(list1);
node *h = list2.head;
while (h != list2.tail->next) {
newlist1.appendList(h->data);
h = h->next;
}
return newlist1;
}
node operator[](int i) {
auto h = head;
for (int j{0}; j < i; j++)
h = h->next;
return *h;
}
};
std::ostream &operator<<(std::ostream &out, List list) {
return list.printList(out);
}
bool List::isEmptyList() {
if (head == nullptr && tail == nullptr)
return true;
return false;
}
void List::appendList(int data) {
node *node1 = new node{data, nullptr, tail};
if (head == nullptr && tail == nullptr) {
head = node1;
tail = node1;
} else {
tail->next = node1;
tail = node1;
}
}
std::ostream &List::printList(std::ostream &out) {
if (isEmptyList()) {
out << "List is empty" << endl;
return out;
}
node *traveller = head;
while (traveller != tail) {
out << traveller->data << "=>";
traveller = traveller->next;
}
out << tail->data << endl;
return out;
}
void List::prependList(int data) {
node *node1 = new node{data, head, nullptr};
if (head == nullptr && tail == nullptr) {
head = node1;
tail = node1;
} else {
head->previous = node1;
head = node1;
}
}
bool List::findInList(int key) {
// returns a pointer to the first occurrence of the key in the list
node *traveller = head;
while (traveller != tail->next) {
if (traveller->data == key) {
// return traveller;
return true;
}
traveller = traveller->next;
}
return false;
}
void List::pop() {
if (isEmptyList())
return;
if (head == tail) // one node
{
delete head;
head = nullptr;
tail = nullptr;
return;
}
node *firstNode = head;
head = head->next;
head->previous = nullptr;
delete firstNode;
}
void List::popBack() {
if (isEmptyList())
return;
if (head == tail) // one node
{
delete head;
head = nullptr;
tail = nullptr;
return;
}
node *lastNode = tail;
tail = tail->previous;
tail->next = nullptr;
delete lastNode;
}
void List::removeFromList(node *node1) {
if (node1 == head) {
pop();
return;
}
if (node1 == tail) {
popBack();
return;
}
if (node1) {
node *tempPrev = node1->previous;
node *tempNext = node1->next;
tempPrev->next = tempNext;
tempNext->previous = tempPrev;
delete node1;
}
}
void List::removeFromList(int key) {
node *traveller = head;
while (traveller != tail->next) {
if (traveller->data == key) {
removeFromList(traveller);
return;
}
traveller = traveller->next;
}
// note that this deletes only the first occurrence of the key in the list
}
#endif

73
main.cpp Normal file
View File

@ -0,0 +1,73 @@
#include "Clinic.cpp"
#include "Patient.hpp"
#include "linkedList.cpp"
#include <algorithm>
#include <fstream>
#include <functional>
#include <iostream>
#include <optional>
#include <sstream>
#include <sys/types.h>
int main() {
// this program implements the sieve of Erathosthenes using linked lists
// it does not use/test all the list functions
List primes{nullptr, nullptr};
for (int i = 2; i <= 20; i++) {
primes.appendList(i);
}
node *p = primes.head;
while (p != primes.tail) {
int prime = p->data;
int tailData = primes.tail->data;
for (int composite = 2 * prime; composite <= tailData; composite += prime) {
primes.removeFromList(
composite); // if the composite is not in the list, nothing happens
}
p = p->next;
}
std::cout << primes;
// testing copy
List primes_copy(primes);
std::cout << "primes: " << primes;
std::cout << "primes: " << primes_copy + 1;
std::cout << "primes+primes: " << primes_copy + primes_copy;
// should return 5
std::cout << "primes[2] = ";
std::cout << primes_copy[2].data << std::endl;
return 0;
}
// int main() {
// Clinic clinic("patients.txt");
// std::cout << "Welcome to patient management\n\n";
// // run util main_menu recieves a non-exit value
// MenuChoice choice;
// Patient patient{};
// std::string reading_string;
// std::string input_string;
// while (1) {
// choice = clinic.menu_main();
// switch (choice) {
// case MenuChoice::NewPatient:
// clinic.menu_add_new_patient();
// break;
// case MenuChoice::NewVisit:
// clinic.menu_add_vist();
// break;
// case MenuChoice::DisplayPatient:
// clinic.menu_patient_info();
// break;
// case MenuChoice::Quit:
// return 0;
// break;
// }
// }
// return 0;
// }

9
patient_files/1.txt Normal file
View File

@ -0,0 +1,9 @@
1
Joe
Doe
M
18
1 11/12/103 Mike WWW
1 11/12/103 Mike WWW
1 11/12/103 Mike WWW
77 /88/9999 Doctr Last

6
patient_files/6.txt Normal file
View File

@ -0,0 +1,6 @@
6
Karim
Alaswad
M
14
16 12/1/2018 Helen Philips

3
patients.txt Normal file
View File

@ -0,0 +1,3 @@
1
3
4