diff --git a/include/date.hpp b/include/date.hpp index ece2a4d..2386e57 100644 --- a/include/date.hpp +++ b/include/date.hpp @@ -67,6 +67,14 @@ struct month { return *this; } + month operator-(date_type remove) const { + return {static_cast(value - remove)}; + } + + month operator+(date_type add) const { + return {static_cast(value + add)}; + } + std::string as_short_string() const { static constexpr const std::array months{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; @@ -86,13 +94,19 @@ struct month { } bool is_valid() const { - return value <= 13; + return value < 13; + } + + bool is_last() const { + return value == 12; } month operator++() { ++value; return *this; } + + friend auto operator<=>(const month & lhs, const month & rhs) = default; }; struct year { @@ -122,6 +136,8 @@ struct year { ++value; return *this; } + + friend auto operator<=>(const year & lhs, const year & rhs) = default; }; struct days { @@ -174,6 +190,8 @@ struct date { } } + // TODO date(year y, month m, day d) : date(y.value, m.value, d.value) {} + budget::year year() const { return budget::year{_year}; } @@ -494,8 +512,8 @@ inline std::string to_string(budget::date date){ struct data_cache; -unsigned short start_year(data_cache & cache); -unsigned short start_month(data_cache & cache, budget::year year); +budget::year start_year(data_cache & cache); +budget::month start_month(data_cache & cache, budget::year year); } //end of namespace budget diff --git a/src/compute.cpp b/src/compute.cpp index 284796c..8eccb35 100644 --- a/src/compute.cpp +++ b/src/compute.cpp @@ -21,7 +21,7 @@ budget::status budget::compute_year_status(data_cache & cache) { } budget::status budget::compute_year_status(data_cache & cache, year year) { - return compute_year_status(cache, year, 12); + return compute_year_status(cache, year, month(12)); } budget::status budget::compute_year_status(data_cache & cache, year year, month month) { @@ -32,7 +32,7 @@ budget::status budget::compute_year_status(data_cache & cache, year year, month status.expenses = fold_left_auto(all_expenses_between(cache, year, sm, month) | to_amount); status.earnings = fold_left_auto(all_earnings_between(cache, year, sm, month) | to_amount); - for (unsigned short i = sm; i <= month; ++i) { + for (budget::month i = sm; i <= month; ++i) { status.budget += fold_left_auto(all_accounts(cache, year, i) | to_amount); status.base_income += get_base_income(cache, budget::date(year, i, 1)); } @@ -97,7 +97,7 @@ budget::status budget::compute_avg_month_status(data_cache & cache, month month) budget::status budget::compute_avg_month_status(data_cache & cache, year year, month month) { budget::status avg_status; - for (budget::month m = 1; m < month; m = m + 1) { + for (budget::month m(1); m < month; ++m) { auto status = compute_month_status(cache, year, m); avg_status.expenses += status.expenses; diff --git a/src/date.cpp b/src/date.cpp index 9eee6dd..389a74e 100644 --- a/src/date.cpp +++ b/src/date.cpp @@ -62,7 +62,7 @@ std::string budget::date_to_string(const budget::date& date) { } // Convert the month - auto* month_ptr = date.month() < 10 ? str.data() + 6 : str.data() + 5; + auto* month_ptr = date.month() < budget::month(10) ? str.data() + 6 : str.data() + 5; if (auto [p, ec] = std::to_chars(month_ptr, str.data() + 7, static_cast(date.month())); ec != std::errc() || p != str.data() + 7) { throw date_exception("Can't convert month to string"); } @@ -76,12 +76,12 @@ std::string budget::date_to_string(const budget::date& date) { return str; } -unsigned short budget::start_month(data_cache & cache, budget::year year){ +budget::month budget::start_month(data_cache & cache, budget::year year){ const budget::month m = min_with_default(cache.expenses() | filter_by_year(year) | to_month, 12); return min_with_default(cache.earnings() | filter_by_year(year) | to_month, m); } -unsigned short budget::start_year(data_cache & cache){ +budget::year budget::start_year(data_cache & cache){ auto today = budget::local_day(); const budget::year y = min_with_default(cache.expenses() | not_template | to_year, today.year()); return min_with_default(cache.earnings() | not_template | to_year, y); diff --git a/src/objectives.cpp b/src/objectives.cpp index 4a5b1ad..b8ea87c 100644 --- a/src/objectives.cpp +++ b/src/objectives.cpp @@ -111,9 +111,7 @@ void budget::monthly_objective_status(budget::writer& w){ std::vector columns = {objective.name, "Status", "Progress"}; std::vector> contents; - for (unsigned short i = sm; i <= current_month; ++i) { - budget::month const month = i; - + for (budget::month month = sm; month <= current_month; ++month) { // Compute the month status auto status = budget::compute_month_status(w.cache, current_year, month); diff --git a/src/overview.cpp b/src/overview.cpp index 99ddaa0..a715a6b 100644 --- a/src/overview.cpp +++ b/src/overview.cpp @@ -36,14 +36,10 @@ bool invalid_accounts_all(){ const std::vector previous = all_accounts(cache, sy, start_month(cache, sy)); - for(unsigned short j = sy; j <= today.year(); ++j){ - const budget::year year = j; - + for(budget::year year = sy; year <= today.year(); ++year){ auto sm = start_month(cache, year); - for(unsigned short i = sm; i < 13; ++i){ - const budget::month month = i; - + for(budget::month month = sm; month.is_valid(); ++month){ auto current_accounts = all_accounts(cache, year, month); if(current_accounts.size() != previous.size()){ @@ -77,10 +73,8 @@ bool invalid_accounts(budget::year year){ std::vector previous = all_accounts(cache, year, sm); - for(unsigned short i = sm + 1; i < 13; ++i){ - const budget::month month = i; - - auto current_accounts = all_accounts(cache, year, month); + for(budget::month m = sm + date_type(1); m.is_valid(); ++m){ + auto current_accounts = all_accounts(cache, year, m); if(current_accounts.size() != previous.size()){ return true; @@ -163,11 +157,11 @@ budget::money compute_total_budget_account(budget::account & account, budget::mo } } - if (y != year && m == 12) { + if (y != year && m.is_last()) { break; } - m = m + 1; + ++m; } } @@ -209,7 +203,7 @@ std::vector compute_total_budget(data_cache & cache, budget::mont tmp[account.name] += fold_left_auto(all_earnings_month(cache, account.id, y, m) | to_amount); } - if(y != year && m == 12){ + if(y != year && m.is_last()){ break; } @@ -505,16 +499,16 @@ void add_month_columns(std::vector& columns, budget::month sm){ } } -int get_current_months(budget::year year){ +budget::month get_current_months(budget::year year){ data_cache cache; auto sm = start_month(cache, year); - auto current_months = 12 - sm + 1; + budget::month current_months = budget::month(12) - sm + budget::month(1); auto today = budget::local_day(); if(today.year() == year){ - current_months = today.month() - sm + 1; + current_months = today.month() - sm + date_type(1); } return current_months; @@ -589,9 +583,7 @@ void display_values(budget::writer& w, budget::year year, const std::string& tit //Fill the table - for(unsigned short j = sm; j < 13; ++j){ - const budget::month m = j; - + for(budget::month m = sm; m.is_valid(); ++m){ for(auto& account : all_accounts(w.cache, year, m)){ budget::money month_total; @@ -610,7 +602,7 @@ void display_values(budget::writer& w, budget::year year, const std::string& tit contents[row_mapping[account.name]].push_back(to_string(month_total)); account_totals[account.name] += month_total; - totals[j-1] += month_total; + totals[m.value - 1] += month_total; if(m < sm + current_months){ account_current_totals[account.name] += month_total; @@ -944,9 +936,7 @@ void budget::display_local_balance(budget::writer& w, budget::year year, bool cu double total_savings_rate = 0.0; double current_total_savings_rate = 0.0; - for (unsigned short i = sm; i < 13; ++i) { - const budget::month m = i; - + for (budget::month m = sm; m.is_valid(); ++m) { auto status = compute_month_status(w.cache, year, m); auto savings = status.income - status.expenses; @@ -958,7 +948,7 @@ void budget::display_local_balance(budget::writer& w, budget::year year, bool cu contents.back().push_back(to_string_precision(savings_rate, 2) + "%"); - if (i < sm + current_months) { + if (m < sm + current_months) { current_total_savings_rate += savings_rate; } @@ -980,9 +970,7 @@ void budget::display_local_balance(budget::writer& w, budget::year year, bool cu double total_savings_rate = 0.0; double current_total_savings_rate = 0.0; - for (unsigned short i = sm; i < 13; ++i) { - budget::month const m = i; - + for (budget::month m = sm; m.is_valid(); ++m) { auto status = compute_month_status(w.cache, year - date_type(1), m); double savings_rate = 0.0; @@ -993,7 +981,7 @@ void budget::display_local_balance(budget::writer& w, budget::year year, bool cu contents.back().push_back(to_string_precision(savings_rate, 2) + "%"); - if (i < sm + current_months) { + if (m < sm + current_months) { current_total_savings_rate += savings_rate; } @@ -1040,7 +1028,7 @@ void budget::display_balance(budget::writer& w, budget::year year, bool relaxed, auto pretotal = compute_total_budget(w.cache, sm, year); size_t i = 0; for(const auto& account : all_accounts(w.cache, year, sm)){ - account_previous[account.name][sm - 1] += pretotal[i++] - account.amount; + account_previous[account.name][sm.value - 1] += pretotal[i++] - account.amount; } } @@ -1343,7 +1331,7 @@ void budget::display_year_overview(budget::year year, budget::writer& w){ } auto today = budget::local_day(); - const bool current = year == today.year() && today.month() != 12; + const bool current = year == today.year() && today.month() != budget::month(12); display_local_balance(w, year, current, false, true); display_balance(w, year, false, true); diff --git a/src/predict.cpp b/src/predict.cpp index d6596f1..7de639e 100644 --- a/src/predict.cpp +++ b/src/predict.cpp @@ -65,9 +65,9 @@ void predict_overview(){ } } - if (today.month() < 12) { + if (today.month() < budget::month(12)) { budget::year prev_year = today.year() - date_type(1); - for (budget::month m = today.month() + 1; m <= 12; m = m + 1) { + for (budget::month m = today.month() + date_type(1); m.is_valid(); ++m) { for (auto& expense : expenses | filter_by_date(prev_year, m)) { expense.date = {today.year(), expense.date.month(), expense.date.day()}; } diff --git a/src/recurring.cpp b/src/recurring.cpp index fb13403..ac303ff 100644 --- a/src/recurring.cpp +++ b/src/recurring.cpp @@ -56,7 +56,7 @@ budget::date last_date(const budget::recurring& recurring) { } bool recurring_not_triggered(const budget::recurring & recurring ) { - return last_date(recurring).year() == 1400; + return last_date(recurring).year() == budget::year(1400); } void generate_recurring(const budget::date & date, const recurring & recurring) { diff --git a/src/report.cpp b/src/report.cpp index 0a507be..29546f8 100644 --- a/src/report.cpp +++ b/src/report.cpp @@ -165,9 +165,9 @@ void budget::report(budget::writer& w, budget::year year, bool filter, const std total_balance = get_base_income(w.cache, budget::date(year, month, 1)) + total_earnings - total_expenses; } - expenses[month - 1] = total_expenses.dollars(); - earnings[month - 1] = total_earnings.dollars(); - balances[month - 1] = total_balance.dollars(); + expenses[month.value - 1] = total_expenses.dollars(); + earnings[month.value - 1] = total_earnings.dollars(); + balances[month.value - 1] = total_balance.dollars(); max_expenses = std::max(max_expenses, total_expenses); max_earnings = std::max(max_earnings, total_earnings); @@ -257,16 +257,14 @@ void budget::report(budget::writer& w, budget::year year, bool filter, const std const auto first_bar = scale_width + 2; - for (auto i = sm; i <= today.month(); ++i) { - const budget::month month = i; - - auto col_start = first_bar + (3 * col_width + 4) * (i - sm); + for (budget::month month = sm; month <= today.month(); ++month) { + auto col_start = first_bar + (3 * col_width + 4) * (month.value - sm.value); //Display month legend auto month_str = month.as_short_string(); write(graph, 1, col_start + 2, month_str); - for (size_t j = 0; j < expenses[month - 1] / precision; ++j) { + for (size_t j = 0; j < expenses[month.value - 1] / precision; ++j) { for (size_t x = 0; x < col_width; ++x) { graph[zero_index + j][col_start + x] = "\033[1;41m \033[0m"; } @@ -274,7 +272,7 @@ void budget::report(budget::writer& w, budget::year year, bool filter, const std col_start += col_width + 1; - for (size_t j = 0; j < earnings[month - 1] / precision; ++j) { + for (size_t j = 0; j < earnings[month.value - 1] / precision; ++j) { for (size_t x = 0; x < col_width; ++x) { graph[zero_index + j][col_start + x] = "\033[1;42m \033[0m"; } @@ -282,14 +280,14 @@ void budget::report(budget::writer& w, budget::year year, bool filter, const std col_start += col_width + 1; - if (balances[month - 1] >= 0) { - for (size_t j = 0; j < balances[month - 1] / precision; ++j) { + if (balances[month.value - 1] >= 0) { + for (size_t j = 0; j < balances[month.value - 1] / precision; ++j) { for (size_t x = 0; x < col_width; ++x) { graph[zero_index + j][col_start + x] = "\033[1;44m \033[0m"; } } } else { - for (size_t j = 0; j < std::abs(balances[month - 1]) / precision; ++j) { + for (size_t j = 0; j < std::abs(balances[month.value - 1]) / precision; ++j) { for (size_t x = 0; x < col_width; ++x) { graph[zero_index - 1 - j][col_start + x] = "\033[1;44m \033[0m"; } @@ -299,7 +297,7 @@ void budget::report(budget::writer& w, budget::year year, bool filter, const std //Display legend - const int start_legend = first_bar + (3 * col_width + 4) * (today.month() - sm + 1) + 4; + const int start_legend = first_bar + (3 * col_width + 4) * (today.month() - sm + date_type(1)) + 4; graph[4][start_legend - 2] = "|"; graph[3][start_legend - 2] = "|"; diff --git a/src/summary.cpp b/src/summary.cpp index cf8b3f3..d98a27a 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -231,9 +231,7 @@ void budget::account_summary(budget::writer& w, budget::month month, budget::yea auto sm = start_month(w.cache, year); - for (unsigned short i = sm; i <= month; ++i) { - const budget::month m = i; - + for (budget::month m = sm; m <= month; ++m) { for (const auto& account : all_accounts(w.cache, year, m)) { auto total_expenses = fold_left_auto(w.cache.expenses() | filter_by_account(account.id) | filter_by_date(year, m) | to_amount); auto total_earnings = fold_left_auto(w.cache.earnings() | filter_by_account(account.id) | filter_by_date(year, m) | to_amount); @@ -241,7 +239,7 @@ void budget::account_summary(budget::writer& w, budget::month month, budget::yea auto balance = account_previous[account.name] + account.amount - total_expenses + total_earnings; auto local_balance = account.amount - total_expenses + total_earnings; - if (i == month) { + if (m == month) { contents.push_back({account.name}); contents.back().push_back(format_money(total_expenses)); @@ -253,7 +251,7 @@ void budget::account_summary(budget::writer& w, budget::month month, budget::yea month_tot_earnings += total_earnings; month_tot_balance += balance; month_tot_local += local_balance; - } else if (month > 1 && m == month - 1) { + } else if (month > budget::month(1) && m == month - date_type(1)) { prev_expenses += total_expenses; prev_earnings += total_earnings; prev_balance += balance; @@ -276,7 +274,7 @@ void budget::account_summary(budget::writer& w, budget::month month, budget::yea contents.back().push_back(format_money(month_tot_balance)); contents.back().push_back(format_money(month_tot_local)); - if(month > 1){ + if(month > budget::month(1)){ contents.push_back({"Previous"}); contents.back().push_back(format_money(prev_expenses));