From d2db43019c0be28f95233aaa7a5e97f80a1f96f8 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Tue, 3 Aug 2021 22:02:12 +0800 Subject: [PATCH 1/8] [account.cpp] internal function account_foreach_descendant fast and efficient --- libgnucash/engine/Account.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index 8f12f0c64d..85a3ce909a 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -2691,6 +2691,36 @@ DxaccAccountSetCurrency (Account * acc, gnc_commodity * currency) /********************************************************************\ \********************************************************************/ +static void +account_foreach_descendant (const Account *acc, AccountCb thunk, + void* user_data, bool sort) +{ + gpointer result = nullptr; + GList *children; + + g_return_if_fail (GNC_IS_ACCOUNT(acc)); + g_return_if_fail (thunk); + + auto priv{GET_PRIVATE(acc)}; + if (sort) + { + children = g_list_copy (priv->children); + children = g_list_sort (children, (GCompareFunc)xaccAccountOrder); + } + else + children = priv->children; + + for (auto node = children; node; node = node->next) + { + auto child = static_cast(node->data); + thunk (child, user_data); + account_foreach_descendant (child, thunk, user_data, sort); + } + + if (sort) + g_list_free (children); +} + void gnc_account_append_child (Account *new_parent, Account *child) { From e6c33a39bc7ead9ea0d687efd4439f1c2913ff22 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Tue, 3 Aug 2021 22:04:55 +0800 Subject: [PATCH 2/8] [account.cpp] refactor gnc_account_get_descendants{_sorted} --- libgnucash/engine/Account.cpp | 51 +++++++++-------------------------- 1 file changed, 13 insertions(+), 38 deletions(-) diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index 85a3ce909a..b74ca52421 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -2951,52 +2951,27 @@ gnc_account_get_tree_depth (const Account *account) return depth + 1; } +static void +collect_acct (Account *account, gpointer user_data) +{ + auto listptr{static_cast(user_data)}; + *listptr = g_list_prepend (*listptr, account); +} + GList * gnc_account_get_descendants (const Account *account) { - AccountPrivate *priv; - GList *child, *descendants; - - g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL); - - priv = GET_PRIVATE(account); - if (!priv->children) - return NULL; - - descendants = NULL; - for (child = priv->children; child; child = g_list_next(child)) - { - descendants = g_list_append(descendants, child->data); - descendants = g_list_concat(descendants, - gnc_account_get_descendants(static_cast(child->data))); - } - return descendants; + GList* list = nullptr; + account_foreach_descendant (account, collect_acct, &list, FALSE); + return g_list_reverse (list); } GList * gnc_account_get_descendants_sorted (const Account *account) { - AccountPrivate *priv; - GList *child, *children, *descendants; - - /* errors */ - g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL); - - /* optimizations */ - priv = GET_PRIVATE(account); - if (!priv->children) - return NULL; - - descendants = NULL; - children = g_list_sort(g_list_copy(priv->children), (GCompareFunc)xaccAccountOrder); - for (child = children; child; child = g_list_next(child)) - { - descendants = g_list_append(descendants, child->data); - descendants = g_list_concat(descendants, - gnc_account_get_descendants_sorted(static_cast(child->data))); - } - g_list_free(children); - return descendants; + GList* list = nullptr; + account_foreach_descendant (account, collect_acct, &list, TRUE); + return g_list_reverse (list); } Account * From bebc366e88344b5e226538d79908244900e19878 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Tue, 3 Aug 2021 22:07:18 +0800 Subject: [PATCH 3/8] [account.cpp] refactor gnc_account_n_descendants --- libgnucash/engine/Account.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index b74ca52421..215de97516 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -2894,20 +2894,18 @@ gnc_account_nth_child (const Account *parent, gint num) return static_cast(g_list_nth_data(GET_PRIVATE(parent)->children, num)); } +static void +count_acct (Account *account, gpointer user_data) +{ + auto count {static_cast(user_data)}; + ++*count; +} + gint gnc_account_n_descendants (const Account *account) { - AccountPrivate *priv; - GList *node; - gint count = 0; - - g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0); - - priv = GET_PRIVATE(account); - for (node = priv->children; node; node = g_list_next(node)) - { - count += gnc_account_n_descendants(static_cast(node->data)) + 1; - } + int count {0}; + account_foreach_descendant (account, count_acct, &count, FALSE); return count; } From 09e2e7613c47943c9f333445d75484d9744a6376 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Tue, 3 Aug 2021 22:08:11 +0800 Subject: [PATCH 4/8] [account.cpp] refactor gnc_account_lookup_by_name --- libgnucash/engine/Account.cpp | 36 ++++++++--------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index 215de97516..9ac2a8b782 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -2972,37 +2972,17 @@ gnc_account_get_descendants_sorted (const Account *account) return g_list_reverse (list); } +static gpointer +is_acct_name (Account *account, gpointer user_data) +{ + auto name {static_cast(user_data)}; + return (g_strcmp0 (name, xaccAccountGetName (account)) ? nullptr : account); +} + Account * gnc_account_lookup_by_name (const Account *parent, const char * name) { - AccountPrivate *cpriv, *ppriv; - Account *child, *result; - GList *node; - - g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL); - g_return_val_if_fail(name, NULL); - - /* first, look for accounts hanging off the current node */ - ppriv = GET_PRIVATE(parent); - for (node = ppriv->children; node; node = node->next) - { - child = static_cast(node->data); - cpriv = GET_PRIVATE(child); - if (g_strcmp0(cpriv->accountName, name) == 0) - return child; - } - - /* if we are still here, then we haven't found the account yet. - * Recursively search each of the child accounts next */ - for (node = ppriv->children; node; node = node->next) - { - child = static_cast(node->data); - result = gnc_account_lookup_by_name (child, name); - if (result) - return result; - } - - return NULL; + return (Account*)gnc_account_foreach_descendant_until (parent, is_acct_name, (char*)name); } Account * From 5698b67bf563ec6ed6f0016a9edbd65af932ed50 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Tue, 3 Aug 2021 22:08:21 +0800 Subject: [PATCH 5/8] [account.cpp] refactor gnc_account_lookup_by_code --- libgnucash/engine/Account.cpp | 36 ++++++++--------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index 9ac2a8b782..5dd1570411 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -2985,37 +2985,17 @@ gnc_account_lookup_by_name (const Account *parent, const char * name) return (Account*)gnc_account_foreach_descendant_until (parent, is_acct_name, (char*)name); } +static gpointer +is_acct_code (Account *account, gpointer user_data) +{ + auto name {static_cast(user_data)}; + return (g_strcmp0 (name, xaccAccountGetCode (account)) ? nullptr : account); +} + Account * gnc_account_lookup_by_code (const Account *parent, const char * code) { - AccountPrivate *cpriv, *ppriv; - Account *child, *result; - GList *node; - - g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL); - g_return_val_if_fail(code, NULL); - - /* first, look for accounts hanging off the current node */ - ppriv = GET_PRIVATE(parent); - for (node = ppriv->children; node; node = node->next) - { - child = static_cast(node->data); - cpriv = GET_PRIVATE(child); - if (g_strcmp0(cpriv->accountCode, code) == 0) - return child; - } - - /* if we are still here, then we haven't found the account yet. - * Recursively search each of the child accounts next */ - for (node = ppriv->children; node; node = node->next) - { - child = static_cast(node->data); - result = gnc_account_lookup_by_code (child, code); - if (result) - return result; - } - - return NULL; + return (Account*)gnc_account_foreach_descendant_until (parent, is_acct_code, (char*)code); } static gpointer From 17953441cba7ee73b2e794c9e46affd5a2955a27 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Fri, 6 Aug 2021 00:22:49 +0800 Subject: [PATCH 6/8] [account.cpp] refactor gnc_account_foreach_descendant --- libgnucash/engine/Account.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index 5dd1570411..d3a64f5a85 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -2695,7 +2695,6 @@ static void account_foreach_descendant (const Account *acc, AccountCb thunk, void* user_data, bool sort) { - gpointer result = nullptr; GList *children; g_return_if_fail (GNC_IS_ACCOUNT(acc)); @@ -3146,20 +3145,7 @@ gnc_account_foreach_descendant (const Account *acc, AccountCb thunk, gpointer user_data) { - const AccountPrivate *priv; - GList *node; - Account *child; - - g_return_if_fail(GNC_IS_ACCOUNT(acc)); - g_return_if_fail(thunk); - - priv = GET_PRIVATE(acc); - for (node = priv->children; node; node = node->next) - { - child = static_cast(node->data); - thunk(child, user_data); - gnc_account_foreach_descendant(child, thunk, user_data); - } + account_foreach_descendant (acc, thunk, user_data, FALSE); } gpointer From 67bd513514b1490a9521b520e812a5d3f243185b Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Fri, 6 Aug 2021 00:23:02 +0800 Subject: [PATCH 7/8] [account.cpp] rewrite gnc_account_foreach_descendant_until in C++ --- libgnucash/engine/Account.cpp | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index d3a64f5a85..c66657b23f 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -3153,28 +3153,24 @@ gnc_account_foreach_descendant_until (const Account *acc, AccountCb2 thunk, gpointer user_data) { - const AccountPrivate *priv; - GList *node; - Account *child; - gpointer result; + gpointer result {nullptr}; - g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL); - g_return_val_if_fail(thunk, NULL); + g_return_val_if_fail (GNC_IS_ACCOUNT(acc), nullptr); + g_return_val_if_fail (thunk, nullptr); - priv = GET_PRIVATE(acc); - for (node = priv->children; node; node = node->next) + auto priv{GET_PRIVATE(acc)}; + + for (auto node = priv->children; node; node = node->next) { - child = static_cast(node->data); - result = thunk(child, user_data); - if (result) - return(result); - - result = gnc_account_foreach_descendant_until(child, thunk, user_data); - if (result) - return(result); + auto child = static_cast(node->data); + result = thunk (child, user_data); + if (result) break; + + result = gnc_account_foreach_descendant_until (child, thunk, user_data); + if (result) break; } - return NULL; + return result; } From 0420ae6a6607f32ba348dafbf57af93db9782561 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Fri, 6 Aug 2021 08:01:06 +0800 Subject: [PATCH 8/8] [account.cpp] refactor gnc_account_list_name_violations --- libgnucash/engine/Account.cpp | 45 ++++++++++++++++------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index c66657b23f..78755e38d5 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -262,34 +262,29 @@ gchar *gnc_account_name_violations_errmsg (const gchar *separator, GList* invali return message; } -GList *gnc_account_list_name_violations (QofBook *book, const gchar *separator) +struct ViolationData { - Account *root_account = gnc_book_get_root_account(book); - GList *accounts, *node; - GList *invalid_list = NULL; - - g_return_val_if_fail (separator != NULL, NULL); - - if (root_account == NULL) - return NULL; - - accounts = gnc_account_get_descendants (root_account); - for (node = accounts; node; node = g_list_next(node)) - { - Account *acct = (Account*)node->data; - gchar *acct_name = g_strdup ( xaccAccountGetName ( acct ) ); + GList *list; + const gchar *separator; +}; - if ( g_strstr_len ( acct_name, -1, separator ) ) - invalid_list = g_list_prepend ( invalid_list, (gpointer) acct_name ); - else - g_free ( acct_name ); - } - if (accounts != NULL) - { - g_list_free(accounts); - } +static void +check_acct_name (Account *acct, gpointer user_data) +{ + auto cb {static_cast(user_data)}; + auto name {xaccAccountGetName (acct)}; + if (g_strstr_len (name, -1, cb->separator)) + cb->list = g_list_prepend (cb->list, g_strdup (name)); +} - return invalid_list; +GList *gnc_account_list_name_violations (QofBook *book, const gchar *separator) +{ + g_return_val_if_fail (separator != NULL, nullptr); + if (!book) return nullptr; + ViolationData cb = { nullptr, separator }; + gnc_account_foreach_descendant (gnc_book_get_root_account (book), + (AccountCb)check_acct_name, &cb); + return cb.list; } /********************************************************************\