gnucash stable: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Thu Jun 27 17:13:24 EDT 2024


Updated	 via  https://github.com/Gnucash/gnucash/commit/ad7a51a6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d1807b6c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6cac9d0e (commit)
	from  https://github.com/Gnucash/gnucash/commit/63927aaa (commit)



commit ad7a51a6ef9e4c8cdf632ac1b1d91c129f0435d1
Merge: 63927aaa88 d1807b6c15
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Jun 27 13:21:49 2024 -0700

    Merge Chris Lam's 'acc-children-vector' into stable.


commit d1807b6c15177e49c47427eefa2f11cf61fb4c83
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Jun 3 15:24:04 2024 +0800

    [engine.i] move gnc_accounts_and_all_descendants to engine.i

diff --git a/bindings/engine-common.i b/bindings/engine-common.i
index cd9fd4bb98..4d360f481e 100644
--- a/bindings/engine-common.i
+++ b/bindings/engine-common.i
@@ -50,14 +50,10 @@ AccountList * gnc_account_get_descendants (const Account *account);
 %newobject gnc_account_get_descendants_sorted;
 AccountList * gnc_account_get_descendants_sorted (const Account *account);
 
-%newobject gnc_accounts_and_all_descendants;
-AccountList * gnc_accounts_and_all_descendants (AccountList *accounts);
-
 %ignore gnc_account_get_children;
 %ignore gnc_account_get_children_sorted;
 %ignore gnc_account_get_descendants;
 %ignore gnc_account_get_descendants_sorted;
-%ignore gnc_accounts_and_all_descendants;
 %include <Account.h>
 
 %include <Transaction.h>
diff --git a/bindings/engine.i b/bindings/engine.i
index 20158bf52f..5620f38e1c 100644
--- a/bindings/engine.i
+++ b/bindings/engine.i
@@ -54,6 +54,8 @@
 #include "gncTaxTable.h"
 #include "gncVendor.h"
 
+#include <numeric>
+#include <unordered_set>
 %}
 #if defined(SWIGGUILE) //Always C++
 %{
@@ -64,6 +66,8 @@ using AccountVec = std::vector<Account*>;
 SplitsVec gnc_get_match_commodity_splits (AccountVec accounts, bool use_end_date,
                                           time64 end_date, gnc_commodity *comm, bool sort);
 
+AccountVec gnc_accounts_and_all_descendants (AccountVec accounts);
+
 extern "C"
 {
 SCM scm_init_sw_engine_module (void);
@@ -155,6 +159,22 @@ SplitsVec gnc_get_match_commodity_splits (AccountVec accounts, bool use_end_date
     return rv;
 }
 
+using AccountSet = std::unordered_set<Account*>;
+static void maybe_add_descendants (Account* acc, AccountSet* accset)
+{
+    if (accset->insert (acc).second)
+        gnc_account_foreach_child (acc, (AccountCb)maybe_add_descendants, accset);
+};
+
+AccountVec
+gnc_accounts_and_all_descendants (AccountVec accounts)
+{
+    AccountSet accset;
+    for (auto a : accounts)
+        maybe_add_descendants (a, &accset);
+    return AccountVec (accset.begin(), accset.end());
+}
+
 %}
 
 /* NB: The object ownership annotations should already cover all the
diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 8945a6e1c6..81a10129b5 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -6383,24 +6383,6 @@ gboolean xaccAccountRegister (void)
     return qof_object_register (&account_object_def);
 }
 
-using AccountSet = std::unordered_set<Account*>;
-static void maybe_add_descendants (Account* acc, gpointer arg)
-{
-    g_return_if_fail (acc);
-
-    if (static_cast <AccountSet*> (arg)->insert (acc).second)
-        std::for_each (GET_PRIVATE(acc)->children.begin(), GET_PRIVATE(acc)->children.end(),
-                       [&](auto acc){ maybe_add_descendants (acc, arg); });
-};
-
-GList *
-gnc_accounts_and_all_descendants (GList *accounts)
-{
-    AccountSet accset;
-    g_list_foreach (accounts, (GFunc) maybe_add_descendants, &accset);
-    return std::accumulate (accset.begin(), accset.end(), (GList*) nullptr, g_list_prepend);
-}
-
 /* ======================= UNIT TESTING ACCESS =======================
  * The following functions are for unit testing use only.
  */
diff --git a/libgnucash/engine/Account.h b/libgnucash/engine/Account.h
index 51379dacd6..842db88486 100644
--- a/libgnucash/engine/Account.h
+++ b/libgnucash/engine/Account.h
@@ -1687,8 +1687,6 @@ typedef enum
     const char * dxaccAccountGetQuoteTZ (const Account *account);
     /** @} */
 
-    GList * gnc_accounts_and_all_descendants (GList *accounts);
-
     /** @name Account parameter names
      @{
     */

commit 6cac9d0ebb67a9b9f6d5424b6c837b1489946a04
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Jun 3 08:31:09 2024 +0800

    [Account.cpp] priv->children is a vector<Account*>

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 94dd328681..8945a6e1c6 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -301,7 +301,6 @@ gnc_account_init(Account* acc)
 
     priv = GET_PRIVATE(acc);
     priv->parent   = nullptr;
-    priv->children = nullptr;
 
     priv->accountName = qof_string_cache_insert("");
     priv->accountCode = qof_string_cache_insert("");
@@ -332,6 +331,7 @@ gnc_account_init(Account* acc)
     priv->lower_balance_limit = {};
     priv->include_sub_account_balances = {};
 
+    new (&priv->children) AccountVec ();
     new (&priv->splits) SplitsVec ();
     priv->splits_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
     priv->sort_dirty = FALSE;
@@ -1347,7 +1347,7 @@ xaccCloneAccount(const Account *from, QofBook *book)
 \********************************************************************/
 
 static void
-xaccFreeOneChildAccount (Account *acc, gpointer dummy)
+xaccFreeOneChildAccount (Account *acc)
 {
     /* FIXME: this code is kind of hacky.  actually, all this code
      * seems to assume that the account edit levels are all 1. */
@@ -1359,19 +1359,13 @@ xaccFreeOneChildAccount (Account *acc, gpointer dummy)
 static void
 xaccFreeAccountChildren (Account *acc)
 {
-    AccountPrivate *priv;
-    GList *children;
-
+    auto priv{GET_PRIVATE(acc)};
     /* Copy the list since it will be modified */
-    priv = GET_PRIVATE(acc);
-    children = g_list_copy(priv->children);
-    g_list_foreach(children, (GFunc)xaccFreeOneChildAccount, nullptr);
-    g_list_free(children);
+    auto children = priv->children;
+    std::for_each (children.begin(), children.end(), xaccFreeOneChildAccount);
 
     /* The foreach should have removed all the children already. */
-    if (priv->children)
-        g_list_free(priv->children);
-    priv->children = nullptr;
+    priv->children.clear();
 }
 
 /* The xaccFreeAccount() routine releases memory associated with the
@@ -1395,7 +1389,7 @@ xaccFreeAccount (Account *acc)
     if (!qof_instance_get_destroying (acc))
             qof_instance_set_destroying(acc, TRUE);
 
-    if (priv->children)
+    if (!priv->children.empty())
     {
         PERR (" instead of calling xaccFreeAccount(), please call\n"
               " xaccAccountBeginEdit(); xaccAccountDestroy();\n");
@@ -1457,7 +1451,6 @@ xaccFreeAccount (Account *acc)
     priv->filter = nullptr;
 
     priv->parent = nullptr;
-    priv->children = nullptr;
 
     priv->balance  = gnc_numeric_zero();
     priv->noclosing_balance = gnc_numeric_zero();
@@ -1471,6 +1464,7 @@ xaccFreeAccount (Account *acc)
     priv->balance_dirty = FALSE;
     priv->sort_dirty = FALSE;
     priv->splits.~SplitsVec();
+    priv->children.~AccountVec();
     g_hash_table_destroy (priv->splits_hash);
 
     /* qof_instance_release (&acc->inst); */
@@ -1607,51 +1601,36 @@ xaccAccountDestroy (Account *acc)
 
 /********************************************************************\
 \********************************************************************/
-static gint
-compare_account_by_name (gconstpointer a, gconstpointer b)
-{
-    AccountPrivate *priv_a, *priv_b;
-    if (a && !b) return 1;
-    if (b && !a) return -1;
-    if (!a && !b) return 0;
-    priv_a = GET_PRIVATE((Account*)a);
-    priv_b = GET_PRIVATE((Account*)b);
-    if ((priv_a->accountCode && strlen (priv_a->accountCode)) ||
-        (priv_b->accountCode && strlen (priv_b->accountCode)))
-        return g_strcmp0 (priv_a->accountCode, priv_b->accountCode);
-    return g_strcmp0 (priv_a->accountName, priv_b->accountName);
-}
 
 static gboolean
-xaccAcctChildrenEqual(const GList *na,
-                      const GList *nb,
+xaccAcctChildrenEqual(const AccountVec& na,
+                      const AccountVec& nb,
                       gboolean check_guids)
 {
-    if ((!na && nb) || (na && !nb))
-    {
-        PINFO ("only one has accounts");
-        return(FALSE);
-    }
-    if (g_list_length ((GList*)na) != g_list_length ((GList*)nb))
+    if (na.size() != nb.size())
     {
         PINFO ("Accounts have different numbers of children");
         return (FALSE);
     }
 
-    while (na)
+    for (auto aa : na)
     {
-        Account *aa = static_cast<Account*>(na->data);
-        Account *ab;
-        GList *node = g_list_find_custom ((GList*)nb, aa,
-                                          (GCompareFunc)compare_account_by_name);
-
-        if (!node)
+        auto it_b = std::find_if (nb.begin(), nb.end(), [aa](auto ab) -> bool
+        {
+            if (!aa) return (!ab);
+            if (!ab) return false;
+            auto code_a{GET_PRIVATE(aa)->accountCode};
+            auto code_b{GET_PRIVATE(ab)->accountCode};
+            if ((code_a && *code_a) || (code_b && *code_b)) return !g_strcmp0 (code_a, code_b);
+            return !g_strcmp0 (GET_PRIVATE(aa)->accountName, GET_PRIVATE(ab)->accountName);
+        });
+
+        if (it_b == nb.end())
         {
             PINFO ("Unable to find matching child account.");
             return FALSE;
         }
-        ab = static_cast<Account*>(node->data);
-        if (!xaccAccountEqual(aa, ab, check_guids))
+        else if (auto ab = *it_b; !xaccAccountEqual(aa, ab, check_guids))
         {
             char sa[GUID_ENCODING_LENGTH + 1];
             char sb[GUID_ENCODING_LENGTH + 1];
@@ -1663,8 +1642,6 @@ xaccAcctChildrenEqual(const GList *na,
 
             return(FALSE);
         }
-
-        na = na->next;
     }
 
     return(TRUE);
@@ -2105,16 +2082,13 @@ void
 xaccClearMarkDown (Account *acc, short val)
 {
     AccountPrivate *priv;
-    GList *node;
 
     g_return_if_fail(GNC_IS_ACCOUNT(acc));
 
     priv = GET_PRIVATE(acc);
     priv->mark = val;
-    for (node = priv->children; node; node = node->next)
-    {
-        xaccClearMarkDown(static_cast<Account*>(node->data), val);
-    }
+    std::for_each (priv->children.begin(), priv->children.end(),
+                   [val](auto acc){ xaccClearMarkDown(acc, val); });
 }
 
 /********************************************************************\
@@ -2782,29 +2756,20 @@ static void
 account_foreach_descendant (const Account *acc, AccountCb thunk,
                             void* user_data, bool sort)
 {
-    GList *children;
-
     g_return_if_fail (GNC_IS_ACCOUNT(acc));
     g_return_if_fail (thunk);
 
     auto priv{GET_PRIVATE(acc)};
+    auto children = priv->children;
     if (sort)
-    {
-        children = g_list_copy (priv->children);
-        children = g_list_sort (children, (GCompareFunc)xaccAccountOrder);
-    }
-    else
-        children = priv->children;
+        std::sort (children.begin(), children.end(),
+                   [](auto a, auto b) { return xaccAccountOrder (a, b) < 0; });
 
-    for (auto node = children; node; node = node->next)
+    for (auto child : children)
     {
-        auto child = static_cast<Account*>(node->data);
         thunk (child, user_data);
         account_foreach_descendant (child, thunk, user_data, sort);
     }
-
-    if (sort)
-        g_list_free (children);
 }
 
 void
@@ -2854,7 +2819,7 @@ gnc_account_append_child (Account *new_parent, Account *child)
         }
     }
     cpriv->parent = new_parent;
-    ppriv->children = g_list_append(ppriv->children, child);
+    ppriv->children.push_back (child);
     qof_instance_set_dirty(&new_parent->inst);
     qof_instance_set_dirty(&child->inst);
 
@@ -2892,9 +2857,10 @@ gnc_account_remove_child (Account *parent, Account *child)
 
     /* Gather event data */
     ed.node = parent;
-    ed.idx = g_list_index(ppriv->children, child);
+    ed.idx = gnc_account_child_index (parent, child);
 
-    ppriv->children = g_list_remove(ppriv->children, child);
+    ppriv->children.erase (std::remove (ppriv->children.begin(), ppriv->children.end(), child),
+                           ppriv->children.end());
 
     /* Now send the event. */
     qof_event_gen(&child->inst, QOF_EVENT_REMOVE, &ed);
@@ -2940,29 +2906,23 @@ GList *
 gnc_account_get_children (const Account *account)
 {
     g_return_val_if_fail(GNC_IS_ACCOUNT(account), nullptr);
-    return g_list_copy(GET_PRIVATE(account)->children);
+    auto& children = GET_PRIVATE(account)->children;
+    return std::accumulate (children.rbegin(), children.rend(), static_cast<GList*>(nullptr),
+                            g_list_prepend);
 }
 
 GList *
 gnc_account_get_children_sorted (const Account *account)
 {
-    AccountPrivate *priv;
-
-    /* errors */
     g_return_val_if_fail(GNC_IS_ACCOUNT(account), nullptr);
-
-    /* optimizations */
-    priv = GET_PRIVATE(account);
-    if (!priv->children)
-        return nullptr;
-    return g_list_sort(g_list_copy(priv->children), (GCompareFunc)xaccAccountOrder);
+    return g_list_sort(gnc_account_get_children (account), (GCompareFunc)xaccAccountOrder);
 }
 
 gint
 gnc_account_n_children (const Account *account)
 {
     g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
-    return g_list_length(GET_PRIVATE(account)->children);
+    return GET_PRIVATE(account)->children.size();
 }
 
 gint
@@ -2970,14 +2930,17 @@ gnc_account_child_index (const Account *parent, const Account *child)
 {
     g_return_val_if_fail(GNC_IS_ACCOUNT(parent), -1);
     g_return_val_if_fail(GNC_IS_ACCOUNT(child), -1);
-    return g_list_index(GET_PRIVATE(parent)->children, child);
+    auto& children = GET_PRIVATE(parent)->children;
+    return std::distance (children.begin(), std::find (children.begin(), children.end(), child));
 }
 
 Account *
 gnc_account_nth_child (const Account *parent, gint num)
 {
     g_return_val_if_fail(GNC_IS_ACCOUNT(parent), nullptr);
-    return static_cast<Account*>(g_list_nth_data(GET_PRIVATE(parent)->children, num));
+    if ((size_t)num >= GET_PRIVATE(parent)->children.size())
+        return nullptr;
+    return static_cast<Account*>(GET_PRIVATE(parent)->children.at (num));
 }
 
 static void
@@ -3018,21 +2981,15 @@ gint
 gnc_account_get_tree_depth (const Account *account)
 {
     AccountPrivate *priv;
-    GList *node;
-    gint depth = 0, child_depth;
-
     g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
 
     priv = GET_PRIVATE(account);
-    if (!priv->children)
+    if (!priv->children.size())
         return 1;
 
-    for (node = priv->children; node; node = g_list_next(node))
-    {
-        child_depth = gnc_account_get_tree_depth(static_cast<Account const *>(node->data));
-        depth = MAX(depth, child_depth);
-    }
-    return depth + 1;
+    return 1 + std::accumulate (priv->children.begin(), priv->children.end(),
+                                0, [](auto a, auto b)
+                                { return std::max (a, gnc_account_get_tree_depth (b)); });
 }
 
 static void
@@ -3068,18 +3025,20 @@ account_foreach_descendant_breadthfirst_until (const Account *acc,
                                                AccountCb2 thunk,
                                                gpointer user_data)
 {
-    gpointer result {nullptr};
-
     g_return_val_if_fail (GNC_IS_ACCOUNT(acc), nullptr);
     g_return_val_if_fail (thunk, nullptr);
 
-    for (auto node = GET_PRIVATE(acc)->children; !result && node; node = node->next)
-        result = thunk (static_cast<Account*>(node->data), user_data);
+    auto& children{GET_PRIVATE(acc)->children};
 
-    for (auto node = GET_PRIVATE(acc)->children; !result && node; node = node->next)
-        result = account_foreach_descendant_breadthfirst_until (static_cast<Account*>(node->data), thunk, user_data);
+    for (auto acc : children)
+        if (auto result = thunk (acc, user_data))
+            return result;
 
-    return result;
+    for (auto acc: children)
+        if (auto result = account_foreach_descendant_breadthfirst_until (acc, thunk, user_data))
+            return result;
+
+    return nullptr;
 }
 
 static gpointer
@@ -3131,20 +3090,13 @@ static Account *
 gnc_account_lookup_by_full_name_helper (const Account *parent,
                                         gchar **names)
 {
-    const AccountPrivate *priv, *ppriv;
-    Account *found;
-    GList *node;
-
     g_return_val_if_fail(GNC_IS_ACCOUNT(parent), nullptr);
     g_return_val_if_fail(names, nullptr);
 
     /* Look for the first name in the children. */
-    ppriv = GET_PRIVATE(parent);
-    for (node = ppriv->children; node; node = node->next)
+    for (auto account : GET_PRIVATE(parent)->children)
     {
-        Account *account = static_cast<Account*>(node->data);
-
-        priv = GET_PRIVATE(account);
+        auto priv = GET_PRIVATE(account);
         if (g_strcmp0(priv->accountName, names[0]) == 0)
         {
             /* We found an account.  If the next entry is nullptr, there is
@@ -3153,15 +3105,12 @@ gnc_account_lookup_by_full_name_helper (const Account *parent,
                 return account;
 
             /* No children?  We're done. */
-            if (!priv->children)
+            if (priv->children.empty())
                 return nullptr;
 
             /* There's stuff left to search for.  Search recursively. */
-            found = gnc_account_lookup_by_full_name_helper(account, &names[1]);
-            if (found != nullptr)
-            {
+            if (auto found = gnc_account_lookup_by_full_name_helper(account, &names[1]))
                 return found;
-            }
         }
     }
 
@@ -3202,9 +3151,8 @@ gnc_account_lookup_by_type_and_commodity (Account* root,
 {
     GList *retval{};
     auto rpriv{GET_PRIVATE(root)};
-    for (auto node = rpriv->children; node; node = node->next)
+    for (auto account : rpriv->children)
     {
-        auto account{static_cast<Account*>(node->data)};
         if (xaccAccountGetType (account) == acctype)
         {
             if (commodity &&
@@ -3220,9 +3168,8 @@ gnc_account_lookup_by_type_and_commodity (Account* root,
     }
 
     if (!retval) // Recurse through the children
-        for (auto node = rpriv->children; node; node = node->next)
+        for (auto account : rpriv->children)
         {
-            auto account{static_cast<Account*>(node->data)};
             auto result = gnc_account_lookup_by_type_and_commodity(account,
                                                                    name,
                                                                    acctype,
@@ -3238,17 +3185,10 @@ gnc_account_foreach_child (const Account *acc,
                            AccountCb thunk,
                            gpointer user_data)
 {
-    const AccountPrivate *priv;
-    GList *node;
-
     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)
-    {
-        thunk (static_cast<Account*>(node->data), user_data);
-    }
+    std::for_each (GET_PRIVATE(acc)->children.begin(), GET_PRIVATE(acc)->children.end(),
+                   [user_data, thunk](auto a){ thunk (a, user_data); });
 }
 
 void
@@ -3269,11 +3209,8 @@ gnc_account_foreach_descendant_until (const Account *acc,
     g_return_val_if_fail (GNC_IS_ACCOUNT(acc), nullptr);
     g_return_val_if_fail (thunk, nullptr);
 
-    auto priv{GET_PRIVATE(acc)};
-
-    for (auto node = priv->children; node; node = node->next)
+    for (auto child : GET_PRIVATE(acc)->children)
     {
-        auto child = static_cast<Account*>(node->data);
         result = thunk (child, user_data);
         if (result) break;
 
@@ -4044,12 +3981,8 @@ gboolean gnc_account_and_descendants_empty (Account *acc)
     g_return_val_if_fail (GNC_IS_ACCOUNT (acc), FALSE);
     auto priv = GET_PRIVATE (acc);
     if (!priv->splits.empty()) return FALSE;
-    for (auto *n = priv->children; n; n = n->next)
-    {
-	if (!gnc_account_and_descendants_empty (static_cast<Account*>(n->data)))
-	    return FALSE;
-    }
-    return TRUE;
+    return std::all_of (priv->children.begin(), priv->children.end(),
+                        gnc_account_and_descendants_empty);
 }
 
 LotList *
@@ -5396,23 +5329,20 @@ xaccAccountFindTransByDesc(const Account *acc, const char *description)
 void
 gnc_account_join_children (Account *to_parent, Account *from_parent)
 {
-    AccountPrivate *from_priv;
-    GList *children, *node;
 
     /* errors */
     g_return_if_fail(GNC_IS_ACCOUNT(to_parent));
     g_return_if_fail(GNC_IS_ACCOUNT(from_parent));
 
     /* optimizations */
-    from_priv = GET_PRIVATE(from_parent);
-    if (!from_priv->children)
+    auto from_priv = GET_PRIVATE(from_parent);
+    if (from_priv->children.empty())
         return;
 
     ENTER (" ");
-    children = g_list_copy(from_priv->children);
-    for (node = children; node; node = g_list_next(node))
-        gnc_account_append_child(to_parent, static_cast <Account*> (node->data));
-    g_list_free(children);
+    auto children = from_priv->children;
+    for (auto child : children)
+        gnc_account_append_child(to_parent, child);
     LEAVE (" ");
 }
 /********************************************************************\
@@ -5421,22 +5351,17 @@ gnc_account_join_children (Account *to_parent, Account *from_parent)
 void
 gnc_account_merge_children (Account *parent)
 {
-    AccountPrivate *ppriv, *priv_a, *priv_b;
-    GList *node_a, *node_b, *work, *worker;
-
     g_return_if_fail(GNC_IS_ACCOUNT(parent));
 
-    ppriv = GET_PRIVATE(parent);
-    for (node_a = ppriv->children; node_a; node_a = node_a->next)
+    auto ppriv = GET_PRIVATE(parent);
+    for (auto it_a = ppriv->children.begin(); it_a != ppriv->children.end(); it_a++)
     {
-        Account *acc_a = static_cast <Account*> (node_a->data);
-
-        priv_a = GET_PRIVATE(acc_a);
-        for (node_b = node_a->next; node_b; node_b = g_list_next(node_b))
+        auto acc_a = *it_a;
+        auto priv_a = GET_PRIVATE(acc_a);
+        for (auto it_b = std::next(it_a); it_b != ppriv->children.end(); it_b++)
         {
-            Account *acc_b = static_cast <Account*> (node_b->data);
-
-            priv_b = GET_PRIVATE(acc_b);
+            auto acc_b = *it_b;
+            auto priv_b = GET_PRIVATE(acc_b);
             if (0 != null_strcmp(priv_a->accountName, priv_b->accountName))
                 continue;
             if (0 != null_strcmp(priv_a->accountCode, priv_b->accountCode))
@@ -5455,12 +5380,11 @@ gnc_account_merge_children (Account *parent)
                 continue;
 
             /* consolidate children */
-            if (priv_b->children)
+            if (!priv_b->children.empty())
             {
-                work = g_list_copy(priv_b->children);
-                for (worker = work; worker; worker = g_list_next(worker))
-                    gnc_account_append_child (acc_a, (Account *)worker->data);
-                g_list_free(work);
+                auto work = priv_b->children;
+                for (auto w : work)
+                    gnc_account_append_child (acc_a, w);
 
                 qof_event_gen (&acc_a->inst, QOF_EVENT_MODIFY, nullptr);
                 qof_event_gen (&acc_b->inst, QOF_EVENT_MODIFY, nullptr);
@@ -5475,7 +5399,7 @@ gnc_account_merge_children (Account *parent)
 
             /* move back one before removal. next iteration around the loop
              * will get the node after node_b */
-            node_b = g_list_previous(node_b);
+            it_b--;
 
             /* The destroy function will remove from list -- node_a is ok,
              * it's before node_b */
@@ -5582,10 +5506,9 @@ gnc_account_tree_staged_transaction_traversal (const Account *acc,
 
     /* depth first traversal */
     priv = GET_PRIVATE(acc);
-    for (auto acc_p = priv->children; acc_p; acc_p = g_list_next(acc_p))
+    for (auto acc_p : priv->children)
     {
-        retval = gnc_account_tree_staged_transaction_traversal(static_cast <Account*> (acc_p->data),
-                stage, thunk, cb_data);
+        retval = gnc_account_tree_staged_transaction_traversal(acc_p, stage, thunk, cb_data);
         if (retval) return retval;
     }
 
@@ -6466,7 +6389,8 @@ static void maybe_add_descendants (Account* acc, gpointer arg)
     g_return_if_fail (acc);
 
     if (static_cast <AccountSet*> (arg)->insert (acc).second)
-        g_list_foreach (GET_PRIVATE(acc)->children, (GFunc) maybe_add_descendants, arg);
+        std::for_each (GET_PRIVATE(acc)->children.begin(), GET_PRIVATE(acc)->children.end(),
+                       [&](auto acc){ maybe_add_descendants (acc, arg); });
 };
 
 GList *
diff --git a/libgnucash/engine/Account.hpp b/libgnucash/engine/Account.hpp
index 332e45ff7b..4c5920428e 100644
--- a/libgnucash/engine/Account.hpp
+++ b/libgnucash/engine/Account.hpp
@@ -38,6 +38,7 @@
 #include <Account.h>
 
 using SplitsVec = std::vector<Split*>;
+using AccountVec = std::vector<Account*>;
 
 const SplitsVec xaccAccountGetSplits (const Account*);
 
diff --git a/libgnucash/engine/AccountP.hpp b/libgnucash/engine/AccountP.hpp
index d71f4ef313..64e6f09bf3 100644
--- a/libgnucash/engine/AccountP.hpp
+++ b/libgnucash/engine/AccountP.hpp
@@ -99,7 +99,7 @@ typedef struct AccountPrivate
      * hierarchy, of accounts that have sub-accounts ("detail accounts").
      */
     Account *parent;    /* back-pointer to parent */
-    GList *children;    /* list of sub-accounts */
+    std::vector<Account*> children;    /* list of sub-accounts */
 
     /* protected data - should only be set by backends */
     gnc_numeric starting_balance;
diff --git a/libgnucash/engine/test/utest-Account.cpp b/libgnucash/engine/test/utest-Account.cpp
index 6a64a362c4..260170dda4 100644
--- a/libgnucash/engine/test/utest-Account.cpp
+++ b/libgnucash/engine/test/utest-Account.cpp
@@ -808,11 +808,11 @@ test_xaccFreeAccountChildren (Fixture *fixture, gconstpointer pData)
 {
     Account *root = gnc_account_get_root (fixture->acct);
     AccountPrivate *priv = fixture->func->get_private (root);
-    g_assert_cmpuint (g_list_length (priv->children), > , 0);
+    g_assert_cmpuint (priv->children.size(), > , 0);
     fixture->func->xaccFreeAccountChildren (root);
     /* We'd like to check for the child actually having been freed, but
      * there's not good way to do that. */
-    g_assert_cmpuint (g_list_length (priv->children), == , 0);
+    g_assert_cmpuint (priv->children.size(), == , 0);
     qof_book_destroy (gnc_account_get_book (root));
     /* No need to unref the root account, qof_book_destroy did that. */
     g_free (fixture->func);
@@ -880,7 +880,7 @@ test_xaccFreeAccount (Fixture *fixture, gconstpointer pData)
     }
     xaccAccountSetCommodity (parent, commodity);
     /* Check that we've got children, lots, and splits to remove */
-    g_assert_true (p_priv->children != NULL);
+    g_assert_true (!p_priv->children.empty());
     g_assert_true (p_priv->lots != NULL);
     g_assert_true (p_priv->splits.size());
     g_assert_true (p_priv->parent != NULL);
@@ -981,7 +981,7 @@ test_xaccAccountCommitEdit (Fixture *fixture, gconstpointer pData)
     }
     xaccAccountSetCommodity (parent, commodity);
     /* Check that we've got children, lots, and splits to remove */
-    g_assert_true (p_priv->children != NULL);
+    g_assert_true (!p_priv->children.empty());
     g_assert_true (p_priv->lots != NULL);
     g_assert_true (p_priv->splits.size());
     g_assert_true (p_priv->parent != NULL);
@@ -996,7 +996,7 @@ test_xaccAccountCommitEdit (Fixture *fixture, gconstpointer pData)
     /* Make sure that the account didn't get destroyed */
     test_signal_assert_hits (sig1, 1);
     test_signal_assert_hits (sig2, 0);
-    g_assert_true (p_priv->children != NULL);
+    g_assert_true (!p_priv->children.empty());
     g_assert_true (p_priv->lots != NULL);
     g_assert_true (p_priv->splits.size());
     g_assert_true (p_priv->parent != NULL);
@@ -1737,6 +1737,12 @@ test_qofAccountSetParent (Fixture *fixture, gconstpointer pData)
     g_assert_true (qof_instance_get_dirty (QOF_INSTANCE (root)));
     g_assert_true (qof_instance_get_dirty (QOF_INSTANCE (old_parent)));
 }
+
+static bool has_child (const std::vector<Account*>& children, Account* child)
+{
+    return std::any_of (children.begin(), children.end(), [child](auto a){ return a == child; });
+}
+
 /* gnc_account_append_child
 void
 gnc_account_append_child (Account *new_parent, Account *child)// C: 29 in 18 SCM: 7 in 4*/
@@ -1776,7 +1782,7 @@ test_gnc_account_append_remove_child (Fixture *fixture, gconstpointer pData)
     g_assert_cmpint (check_err->hits, ==, 0);
     g_assert_true (qof_instance_get_dirty (QOF_INSTANCE (froot)));
     g_assert_true (qof_instance_get_dirty (QOF_INSTANCE (account)));
-    g_assert_true (g_list_find (frpriv->children, account));
+    g_assert_true (has_child (frpriv->children, account));
     g_assert_true (qof_collection_lookup_entity (
                   qof_book_get_collection (fbook, GNC_ID_ACCOUNT),
                   acct_guid));
@@ -1802,8 +1808,8 @@ test_gnc_account_append_remove_child (Fixture *fixture, gconstpointer pData)
                   qof_book_get_collection (book, GNC_ID_ACCOUNT),
                   acct_guid));
     g_assert_true (qof_instance_get_dirty (QOF_INSTANCE (fixture->acct)));
-    g_assert_true (g_list_find (frpriv->children, account) == NULL);
-    g_assert_true (g_list_find (apriv->children, account));
+    g_assert_true (has_child (frpriv->children, account) == false);
+    g_assert_true (has_child (apriv->children, account));
 
     test_signal_free (sig1);
     test_signal_free (sig2);
@@ -1823,7 +1829,7 @@ test_gnc_account_append_remove_child (Fixture *fixture, gconstpointer pData)
 
     gnc_account_remove_child (fixture->acct, account);
     g_assert_true (gnc_account_get_parent (account) == NULL);
-    g_assert_true (g_list_find (apriv->children, account) == NULL);
+    g_assert_true (has_child (apriv->children, account) == false);
     test_signal_assert_hits (sig1, 1);
     test_signal_assert_hits (sig2, 1);
     g_assert_cmpint (check_warn->hits, ==, 1);



Summary of changes:
 bindings/engine-common.i                 |   4 -
 bindings/engine.i                        |  20 +++
 libgnucash/engine/Account.cpp            | 268 ++++++++++---------------------
 libgnucash/engine/Account.h              |   2 -
 libgnucash/engine/Account.hpp            |   1 +
 libgnucash/engine/AccountP.hpp           |   2 +-
 libgnucash/engine/test/utest-Account.cpp |  24 +--
 7 files changed, 124 insertions(+), 197 deletions(-)



More information about the gnucash-changes mailing list