1
0
Files
CPP_Module_09/ex00/BitcoinExchange.cpp
2025-06-03 11:41:31 +02:00

306 lines
8.3 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* BitcoinExchange.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/05/21 10:39:45 by adjoly #+# #+# */
/* Updated: 2025/06/03 11:40:22 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#include <BitcoinExchange.hpp>
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <exception>
#include <fstream>
#include <functional>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>
const uint32_t Date::_d_in_m[12] = {31, 29, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
void _log(std::string emoji, std::string what, std::string who,
std::string str) {
#ifdef VERBOSE
if (who.empty())
std::cout << "" << emoji << "" << what << ": " << str << std::endl;
else
std::cout << "" << emoji << "" << what << "(" << who << "): " << str
<< std::endl;
#else
(void)emoji, (void)what, (void)who, (void)str;
#endif
}
bool Date::_isMonthValid(uint16_t month) const {
if (month >= 1 && month <= 12)
return true;
return false;
}
bool Date::_isDayValid(uint16_t day, uint16_t month) const {
if (day >= 1 && day <= _d_in_m[month - 1])
return true;
return false;
}
Date::Date(void) : _year(0), _month(1), _day(1) {
_log("", "Date", "", "default constructor called");
}
Date::Date(std::string date) {
_log("", "Date", "", "string constructor called");
std::istringstream iss(date);
char del1, del2;
uint32_t year;
uint16_t month, day;
if (iss >> year >> del1 >> month >> del2 >> day) {
if (del1 == '-' && del2 == '-' && iss.eof()) {
if (_isMonthValid(month) && _isDayValid(day, month)) {
_year = year;
_month = month;
_day = day;
return;
}
}
}
throw std::runtime_error("bad input => " + date);
}
Date::Date(const Date &cpy)
: _year(cpy._year), _month(cpy._month), _day(cpy._day) {
_log("", "Date", "", "copy constructor called");
}
Date::~Date(void) { _log("", "Date", "", "destructor called"); }
Date &Date::operator=(const Date &cpy) {
_log("", "Date", "", "copy assignement constructor called");
if (&cpy != this) {
_year = cpy._year;
_month = cpy._month;
_day = cpy._day;
}
return *this;
}
uint32_t Date::getYear(void) const { return _year; }
uint16_t Date::getMonth(void) const { return _month; }
uint16_t Date::getDay(void) const { return _day; }
bool Date::operator==(const Date &other) const {
return other._year == _year && other._month == _month && other._day == _day;
}
bool Date::operator!=(const Date &other) const {
return other._year != _year || other._month != _month || other._day != _day;
}
bool Date::operator<(const Date &other) const {
if (_year != other._year)
return _year < other._year;
if (_month != other._month)
return _month < other._month;
return _day < other._day;
}
bool Date::operator>(const Date &other) const {
if (_year != other._year)
return _year > other._year;
if (_month != other._month)
return _month > other._month;
return _day > other._day;
}
bool Date::operator<=(const Date &other) const {
return (*this) < other || (*this) == other;
}
bool Date::operator>=(const Date &other) const {
return (*this) > other || (*this) == other;
}
std::ostream &operator<<(std::ostream &os, const Date &date) {
std::stringstream month;
std::stringstream day;
if (date.getMonth() < 10)
month << "0" << date.getMonth();
else
month << date.getMonth();
if (date.getDay() < 10)
day << "0" << date.getDay();
else
day << date.getDay();
os << date.getYear() << "-" << month.str() << "-" << day.str();
return os;
}
CsvParser::CsvParser(void) : _is("data.csv") {
_log("", "CsvParser", "", "default constructor called");
if (_is.is_open() != true)
throw std::runtime_error("could not open database file");
std::string buf;
std::getline(_is, buf);
if (buf != "date,exchange_rate")
throw std::runtime_error("first line not good");
std::getline(_is, buf);
while (buf != "") {
size_t i = buf.find(",");
if (i == std::string::npos)
throw std::runtime_error("did not found ,");
Date date(buf.substr(0, i));
float nb;
if (buf.substr(i + 1, buf.length()) == "0")
nb = 0;
else {
nb = std::atof(buf.substr(i + 1, buf.length()).c_str());
if (nb == 0)
throw std::runtime_error("number not well formatted - " +
buf.substr(i + 1, buf.length()));
}
_csv.insert(std::make_pair(date, nb));
std::getline(_is, buf);
}
}
CsvParser::CsvParser(const CsvParser &cpy) : _is(cpy._filename.c_str()) {
_log("", "CsvParser", "", "copy constructor called");
if (&cpy != this) {
_filename = cpy._filename;
_csv = cpy._csv;
}
}
CsvParser::~CsvParser(void) { _log("", "CsvParser", "", "destructor called"); }
CsvParser &CsvParser::operator=(const CsvParser &cpy) {
_log("", "CsvParser", "", "copy assignement constructor called");
if (&cpy != this) {
_csv = cpy._csv;
_filename = cpy._filename;
}
return *this;
}
std::map<Date, float> CsvParser::getCsv(void) const { return _csv; }
BitcoinExchange::BitcoinExchange(void)
: _is("input.txt"), _filename("input.txt") {
_log("", "BitcoinExchange", "", "default constructor called");
if (!_is.is_open())
throw std::runtime_error("could not open file - " + _filename);
}
BitcoinExchange::BitcoinExchange(char *av) : _is(av), _filename(av) {
_log("", "BitcoinExchange", "", "file name constructor called");
try {
_csv = new CsvParser();
} catch (std::exception &e) {
throw e;
}
if (!_is.is_open())
throw std::runtime_error("could not open file - " + _filename);
std::string buf;
std::getline(_is, buf);
if (buf != "date | value")
throw std::runtime_error("file has not the good format - " + buf);
}
BitcoinExchange::BitcoinExchange(const BitcoinExchange &) {
_log("", "BitcoinExchange", "", "copy constructor called");
}
BitcoinExchange &BitcoinExchange::operator=(const BitcoinExchange &) {
_log("", "BitcoinExchange", "", "copy assignement constructor called");
return *this;
}
BitcoinExchange::~BitcoinExchange(void) {
_log("", "BitcoinExchange", "", "destructor called");
delete _csv;
}
void BitcoinExchange::print(void) {
std::pair<Date, float> pair;
std::getline(_is, _line);
while (!_line.empty()) {
try {
pair = _parseLine();
} catch (std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
std::getline(_is, _line);
continue;
}
_printPair(pair);
std::getline(_is, _line);
}
}
std::pair<Date, float> BitcoinExchange::_parseLine(void) {
std::pair<Date, float> pair;
std::string buf;
size_t i;
for (i = 0;
i < _line.length() && (std::isdigit(_line[i]) || _line[i] == '-');
i++) {
buf.push_back(_line[i]);
}
try {
pair.first = Date(buf);
} catch (std::exception &e) {
throw std::runtime_error("bad input => " + _line);
}
if (_line[i] != ' ' || _line[i + 1] != '|' || _line[i + 2] != ' ') {
throw std::runtime_error("bad input => " + _line);
}
if (_line.substr(i + 3) == "0") {
pair.second = 0;
} else {
float f = std::atof(_line.substr(i + 3).c_str());
if (f == 0) {
throw std::runtime_error("bad input => " + _line);
} else if (f > 1000)
throw std::runtime_error("too large number.");
else if (f < 0)
throw std::runtime_error("not a positive number.");
pair.second = f;
}
return pair;
}
void BitcoinExchange::_printPair(std::pair<Date, float> pair) {
auto map = _csv->getCsv();
auto it = std::find_if(map.begin(), map.end(), CompareDate(pair.first));
if (it == map.end())
throw std::out_of_range("out of range");
float i = it->second * pair.second;
std::cout << pair.first << " => " << pair.second << " = " << i << std::endl;
}
CompareDate::CompareDate(Date date) : _date(date) {}
bool CompareDate::operator()(const std::pair<Date, float> &pair) const {
return pair.first >= _date;
}