202 lines
4.6 KiB
C++
202 lines
4.6 KiB
C++
#include "BitcoinExchange.hpp"
|
|
|
|
bool is_leap_year(int year)
|
|
{
|
|
if (year % 100 != 0 && year % 400 == 0)
|
|
return false;
|
|
return (year % 4 == 0);
|
|
}
|
|
|
|
Date::Date(void)
|
|
{
|
|
}
|
|
|
|
Date::Date(std::string str)
|
|
{
|
|
// check format (4 char & isdigit into dash into 2 char isdigit & < 1 && isdigit & < 2, and same for day except ahah funny cuz 30 and 31 and 28 and 29 agfjasfgfjahkfga)
|
|
_value = 0;
|
|
for (size_t i = 0; str[i]; ++i)
|
|
{
|
|
if (!isdigit(str[i]) && !((i == (str.length() - 6) || i == (str.length() - 3)) && str[i] == '-'))
|
|
{
|
|
std::cout << str.length() - 6 << i << std::endl;
|
|
throw std::invalid_argument("invalid date.");
|
|
}
|
|
}
|
|
for (std::string::iterator it = str.begin(); it < str.end(); ++it)
|
|
{
|
|
if (!isdigit(*it))
|
|
continue ;
|
|
_value *= 10;
|
|
_value += *it - '0';
|
|
}
|
|
int year = _value / 10000;
|
|
int month = (_value / 100) % 100;
|
|
int day = _value % 100;
|
|
|
|
if (month > 12 || month == 0 || day == 0)
|
|
throw std::invalid_argument("invalid date.");
|
|
|
|
int monthly_days[] = {0, 31, is_leap_year(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 ,31 };
|
|
|
|
if (day > monthly_days[month])
|
|
throw std::invalid_argument("invalid date.");
|
|
}
|
|
|
|
Date::Date(const Date &other)
|
|
{
|
|
this->_value = other._value;
|
|
}
|
|
|
|
Date &Date::operator=(const Date &other)
|
|
{
|
|
this->_value = other._value;
|
|
return *this;
|
|
}
|
|
|
|
Date::~Date(void)
|
|
{
|
|
}
|
|
|
|
bool Date::operator==(const Date &other) const
|
|
{
|
|
return this->_value == other._value;
|
|
}
|
|
|
|
bool Date::operator!=(const Date &other) const
|
|
{
|
|
return this->_value != other._value;
|
|
}
|
|
|
|
bool Date::operator<(const Date &other) const
|
|
{
|
|
return this->_value < other._value;
|
|
}
|
|
|
|
bool Date::operator>(const Date &other) const
|
|
{
|
|
return this->_value > other._value;
|
|
}
|
|
|
|
bool Date::operator<=(const Date &other) const
|
|
{
|
|
return this->_value <= other._value;
|
|
}
|
|
|
|
bool Date::operator>=(const Date &other) const
|
|
{
|
|
return this->_value >= other._value;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const Date &date)
|
|
{
|
|
os << date.getValue();
|
|
return os;
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------- //
|
|
|
|
void BitcoinExchange::parseData(const std::string filename)
|
|
{
|
|
std::ifstream input_file(filename.c_str());
|
|
if (input_file.fail())
|
|
throw std::runtime_error("Error: could not open file.");
|
|
std::string line;
|
|
|
|
(void) std::getline(input_file, line); // ignore first line
|
|
while (std::getline(input_file, line))
|
|
{
|
|
std::stringstream ss(line);
|
|
std::string date_str;
|
|
std::string value_str;
|
|
if (!std::getline(ss, date_str, ',') || !std::getline(ss, value_str, ','))
|
|
throw std::runtime_error("parsing issue in the data.csv file.");
|
|
try {
|
|
this->_data.insert(std::make_pair(Date(date_str), std::strtod(value_str.c_str(), NULL)));
|
|
}
|
|
catch (std::invalid_argument &e)
|
|
{
|
|
throw std::invalid_argument(e.what());
|
|
}
|
|
}
|
|
|
|
/*for (std::map<Date, double>::iterator it = this->_data.begin(); it != this->_data.end(); it++)
|
|
{
|
|
std::cout << it->first // string (key)
|
|
<< ':'
|
|
<< it->second // string's value
|
|
<< std::endl;
|
|
}*/
|
|
}
|
|
|
|
std::string trim(const std::string &s)
|
|
{
|
|
std::string::size_type start = 0;
|
|
while (start < s.size() && std::isspace(static_cast<unsigned char>(s[start])))
|
|
++start;
|
|
|
|
std::string::size_type end = s.size();
|
|
while (end > start && std::isspace(static_cast<unsigned char>(s[end - 1])))
|
|
--end;
|
|
|
|
return s.substr(start, end - start);
|
|
}
|
|
|
|
void BitcoinExchange::str(std::string filename)
|
|
{
|
|
//std::stringstream input_ss(input);
|
|
std::ifstream input_ss(filename.c_str());
|
|
if (input_ss.fail())
|
|
throw std::runtime_error("Error: could not open file.");
|
|
std::string line;
|
|
|
|
(void) std::getline(input_ss, line); // ignore first line
|
|
while (std::getline(input_ss, line))
|
|
{
|
|
std::stringstream ss(line);
|
|
std::string date_str;
|
|
std::string value_str;
|
|
if (!std::getline(ss, date_str, '|') || !std::getline(ss, value_str, '|'))
|
|
{
|
|
std::cout << "Error: bad input => " << line << std::endl;
|
|
continue ;
|
|
}
|
|
if (std::atol(value_str.c_str()) > 2147483647)
|
|
{
|
|
std::cout << "Error: too large a number." << std::endl;
|
|
continue ;
|
|
}
|
|
if (std::strtod(value_str.c_str(), NULL) < 0)
|
|
{
|
|
std::cout << "Error: not a positive number." << std::endl;
|
|
continue ;
|
|
}
|
|
try {
|
|
Date date(trim(date_str));
|
|
if (date < _data.begin()->first)
|
|
{
|
|
std::cout << "Error: input date too low." << std::endl;
|
|
continue ;
|
|
}
|
|
std::map<Date, double>::iterator it = _data.lower_bound(date);
|
|
if (it == _data.end() || it->first > date)
|
|
{
|
|
if (it == _data.begin())
|
|
it = _data.end();
|
|
else
|
|
--it;
|
|
}
|
|
std::cout << date_str << " => " << value_str << " = " << it->second * std::strtod(value_str.c_str(), NULL) << std::endl;
|
|
|
|
}
|
|
catch (std::invalid_argument &e)
|
|
{
|
|
std::cout << "Error: " << e.what() << std::endl;
|
|
continue ;
|
|
}
|
|
}
|
|
|
|
}
|