/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* BitcoinExchange.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/21 10:39:45 by adjoly #+# #+# */ /* Updated: 2025/06/03 11:40:22 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 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 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 BitcoinExchange::_parseLine(void) { std::pair 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 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 &pair) const { return pair.first >= _date; }