Skip to content

Commit

Permalink
Refactor with ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
wichtounet committed Jul 21, 2023
1 parent 76176df commit 7654db7
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 122 deletions.
1 change: 1 addition & 0 deletions include/expenses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <vector>
#include <string>
#include <map>
#include <ranges>

#include "module_traits.hpp"
#include "money.hpp"
Expand Down
61 changes: 61 additions & 0 deletions include/views.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//=======================================================================
// Copyright (c) 2013-2020 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
// http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <ranges>

namespace budget {

inline auto filter_by_account(size_t account_id) {
return std::views::filter([&account_id] (const auto & expense) { return expense.account == account_id; });
}

inline auto filter_by_name(const std::string & name) {
return std::views::filter([&name] (const auto & account) { return account.name == name; });
}

inline auto only_open_ended() {
return std::views::filter([] (const auto & account) { return account.until == budget::date(2099,12,31); });
}

inline auto not_open_ended() {
return std::views::filter([] (const auto & account) { return account.until != budget::date(2099,12,31); });
}

inline auto active_today() {
auto today = budget::local_day();
return std::views::filter([today] (const auto & account) { return account.since < today && account.until > today; });
}

inline auto active_at_date(budget::date date) {
return std::views::filter([date] (const auto & account) { return account.since < date && account.until > date; });
}

inline auto since(budget::date since) {
return std::views::filter([since] (const auto & expense) { return expense.date >= since; });
}

// TODO(C+23) In the future, we can simply ranges::to<std::vector> but it is not yet implemented with GCC

template <std::ranges::range R>
auto to_vector(R&& r) {
std::vector<std::ranges::range_value_t<R>> v;

// if we can get a size, reserve that much
if constexpr (requires { std::ranges::size(r); }) {
v.reserve(std::ranges::size(r));
}

for (auto&& e : r) {
v.emplace_back(static_cast<decltype(e)&&>(e));
}

return v;
}

} //end of namespace budget
191 changes: 69 additions & 122 deletions src/accounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@
#include "earnings.hpp"
#include "expenses.hpp"
#include "writer.hpp"
#include "views.hpp"

using namespace budget;

namespace ranges = std::ranges;
namespace views = std::ranges::views;

namespace {

static data_handler<account> accounts { "accounts", "accounts.data" };

size_t get_account_id(std::string name, budget::year year, budget::month month){
budget::date date(year, month, 5);

for(auto& account : accounts.data()){
if(account.since < date && account.until > date && account.name == name){
return account.id;
}
for (auto& account : all_accounts() | filter_by_name(name) | active_at_date({year, month, 5})) {
return account.id;
}

return 0;
Expand Down Expand Up @@ -85,21 +85,19 @@ void budget::archive_accounts_impl(bool month){
until_date = since_date - days(1);
}

for (auto& account : all_accounts()) {
if (account.until == budget::date(2099, 12, 31)) {
budget::account copy;
copy.guid = generate_guid();
copy.name = account.name;
copy.amount = account.amount;
copy.until = budget::date(2099, 12, 31);
copy.since = since_date;
for (auto& account : all_accounts() | only_open_ended()) {
budget::account copy;
copy.guid = generate_guid();
copy.name = account.name;
copy.amount = account.amount;
copy.until = budget::date(2099, 12, 31);
copy.since = since_date;

account.until = until_date;
account.until = until_date;

copies.push_back(std::move(copy));
copies.push_back(std::move(copy));

sources.push_back(account.id);
}
sources.push_back(account.id);
}

std::unordered_map<size_t, size_t> mapping;
Expand All @@ -112,19 +110,15 @@ void budget::archive_accounts_impl(bool month){
mapping[sources[i]] = id;
}

for (auto& expense : all_expenses()) {
if (expense.date >= since_date) {
if (mapping.find(expense.account) != mapping.end()) {
expense.account = mapping[expense.account];
}
for (auto& expense : all_expenses() | since(since_date)) {
if (mapping.contains(expense.account)) {
expense.account = mapping[expense.account];
}
}

for (auto& earning : all_earnings()) {
if (earning.date >= since_date) {
if (mapping.find(earning.account) != mapping.end()) {
earning.account = mapping[earning.account];
}
for (auto& earning : all_earnings() | since(since_date)) {
if (mapping.contains(earning.account)) {
earning.account = mapping[earning.account];
}
}

Expand Down Expand Up @@ -179,16 +173,12 @@ void budget::accounts_module::handle(const std::vector<std::string>& args){
id = get_account(name, today.year(), today.month()).id;
}

for(auto& expense : all_expenses()){
if(expense.account == id){
throw budget_exception("There are still some expenses linked to this account, cannot delete it");
}
if (!ranges::empty(all_expenses() | filter_by_account(id))) {
throw budget_exception("There are still some expenses linked to this account, cannot delete it");
}

for(auto& earning : all_earnings()){
if(earning.account == id){
throw budget_exception("There are still some earnings linked to this account, cannot delete it");
}
if (!ranges::empty(all_earnings() | filter_by_account(id))) {
throw budget_exception("There are still some earnings linked to this account, cannot delete it");
}

accounts.remove(id);
Expand Down Expand Up @@ -217,11 +207,9 @@ void budget::accounts_module::handle(const std::vector<std::string>& args){
//Verify that there are no OTHER account with this name
//in the current set of accounts (taking archiving into account)

for(auto& other_account : all_accounts()){
if(other_account.id != id && other_account.until >= today && other_account.since <= today){
if(other_account.name == account.name){
throw budget_exception("There is already an account with the name " + account.name);
}
for(auto& other_account : all_accounts() | active_today() | filter_by_name(account.name)){
if(other_account.id != id) {
throw budget_exception("There is already an account with the name " + account.name);
}
}

Expand Down Expand Up @@ -285,51 +273,43 @@ void budget::accounts_module::handle(const std::vector<std::string>& args){
//Make sure that we find the destination for
//each source accounts

for(auto& account : all_accounts()){
if(account.name == source_account_name){
auto destination_id = get_account_id(destination_account_name, account.since.year(), account.since.month());
for(auto& account : all_accounts() | filter_by_name(source_account_name)){
auto destination_id = get_account_id(destination_account_name, account.since.year(), account.since.month());

if(!destination_id){
std::cout << "Impossible to find the corresponding account for account " << account.id
<< ". This may come from a migration issue. Open an issue on Github if you think that this is a bug" << std::endl;
if(!destination_id){
std::cout << "Impossible to find the corresponding account for account " << account.id
<< ". This may come from a migration issue. Open an issue on Github if you think that this is a bug" << std::endl;

return;
}
return;
}
}

std::vector<size_t> deleted;

//Perform the migration

for(auto& account : all_accounts()){
if(account.name == source_account_name){
auto source_id = account.id;
auto destination_account = get_account(destination_account_name, account.since.year(), account.since.month());
auto destination_id = destination_account.id;
for(auto& account : all_accounts() | filter_by_name(source_account_name)){
auto source_id = account.id;
auto destination_account = get_account(destination_account_name, account.since.year(), account.since.month());
auto destination_id = destination_account.id;

std::cout << "Migrate account " << source_id << " to account " << destination_id << std::endl;
std::cout << "Migrate account " << source_id << " to account " << destination_id << std::endl;

destination_account.amount += account.amount;
destination_account.amount += account.amount;

for (auto& expense : all_expenses()) {
if (expense.account == source_id) {
expense.account = destination_id;
indirect_edit_expense(expense, false);
}
}
for (auto& expense : all_expenses() | filter_by_account(source_id)) {
expense.account = destination_id;
indirect_edit_expense(expense, false);
}

for (auto& earning : all_earnings()) {
if (earning.account == source_id) {
earning.account = destination_id;
indirect_edit_earning(earning, false);
}
}
for (auto& earning : all_earnings() | filter_by_account(source_id)) {
earning.account = destination_id;
indirect_edit_earning(earning, false);
}

accounts.indirect_edit(destination_account);
accounts.indirect_edit(destination_account);

deleted.push_back(source_id);
}
deleted.push_back(source_id);
}

set_expenses_changed();
Expand Down Expand Up @@ -394,12 +374,8 @@ budget::account budget::get_account(size_t id){
}

budget::account budget::get_account(std::string name, budget::year year, budget::month month){
budget::date date(year, month, 5);

for (auto& account : accounts.data()) {
if (account.since < date && account.until > date && account.name == name) {
return account;
}
for (auto& account : all_accounts() | active_at_date({year, month, 5}) | filter_by_name(name)) {
return account;
}

cpp_unreachable("The account does not exist");
Expand Down Expand Up @@ -428,13 +404,7 @@ void budget::account::load(data_reader & reader){
}

bool budget::account_exists(const std::string& name){
for(auto& account : accounts.data()){
if(account.name == name){
return true;
}
}

return false;
return !ranges::empty(all_accounts() | filter_by_name(name));
}

std::vector<account> budget::all_accounts(){
Expand All @@ -447,17 +417,7 @@ std::vector<budget::account> budget::current_accounts(data_cache & cache){
}

std::vector<account> budget::all_accounts(data_cache & cache, budget::year year, budget::month month){
std::vector<account> accounts;

budget::date date(year, month, 5);

for(auto& account : cache.accounts()){
if(account.since < date && account.until > date){
accounts.push_back(account);
}
}

return accounts;
return to_vector(cache.accounts() | active_at_date({year, month, 5}));
}

void budget::set_accounts_changed(){
Expand All @@ -469,14 +429,7 @@ void budget::set_accounts_next_id(size_t next_id){
}

std::vector<std::string> budget::all_account_names(){
std::vector<std::string> account_names;

data_cache cache;
for (auto& account : current_accounts(cache)) {
account_names.push_back(account.name);
}

return account_names;
return to_vector(all_accounts() | active_today() | views::transform([](auto & account) { return account.name; }) | views::as_rvalue);
}

void budget::show_accounts(budget::writer& w){
Expand All @@ -489,26 +442,22 @@ void budget::show_accounts(budget::writer& w){

money total;

for(auto& account : accounts.data()){
if(account.until == budget::date(2099,12,31)){
total += account.amount;
}
for(auto& account : all_accounts() | only_open_ended()){
total += account.amount;
}

// Display the accounts

for(auto& account : accounts.data()){
if(account.until == budget::date(2099,12,31)){
float part = 100.0 * (account.amount.value / float(total.value));
for(auto& account : all_accounts() | only_open_ended()){
float part = 100.0 * (account.amount.value / float(total.value));

char buffer[32];
snprintf(buffer, 32, "%.2f%%", part);
char buffer[32];
snprintf(buffer, 32, "%.2f%%", part);

contents.push_back({to_string(account.id), account.name,
to_string(account.amount),
buffer,
"::edit::accounts::" + to_string(account.id)});
}
contents.push_back({to_string(account.id), account.name,
to_string(account.amount),
buffer,
"::edit::accounts::" + to_string(account.id)});
}

contents.push_back({"", "Total", to_string(total), "", ""});
Expand Down Expand Up @@ -556,11 +505,9 @@ bool budget::edit_account(const budget::account& account){
budget::date budget::find_new_since(){
budget::date date(1400,1,1);

for(auto& account : all_accounts()){
if(account.until != budget::date(2099,12,31)){
if(account.until - days(1) > date){
date = account.until - days(1);
}
for(auto& account : all_accounts() | not_open_ended()){
if(account.until - days(1) > date){
date = account.until - days(1);
}
}

Expand Down

0 comments on commit 7654db7

Please sign in to comment.