From 746ab554a540c1fe3b77250beda9fcf22d88c8cd Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Tue, 9 Apr 2024 21:23:04 +0800 Subject: [PATCH 1/6] gnc_commodity_table_get_namespaces returns std::vector --- bindings/guile/gnc-optiondb.i | 24 +++------- gnucash/gnome-utils/dialog-commodity.cpp | 24 +++++----- gnucash/gnome/dialog-price-edit-db.cpp | 6 +-- .../csv-imp/assistant-csv-price-import.cpp | 8 ++-- .../csv-imp/gnc-imp-props-tx.cpp | 10 ++--- .../import-commodity-matcher.cpp | 10 ++--- libgnucash/app-utils/gnc-quotes.cpp | 8 +--- libgnucash/backend/xml/io-gncxml-v2.cpp | 28 ++++-------- libgnucash/engine/gnc-commodity.cpp | 44 +++++++------------ libgnucash/engine/gnc-commodity.h | 9 ---- libgnucash/engine/gnc-commodity.hpp | 9 ++++ libgnucash/engine/gnc-optiondb.cpp | 10 ++--- .../engine/test-core/test-engine-stuff.cpp | 23 +++------- 13 files changed, 76 insertions(+), 137 deletions(-) diff --git a/bindings/guile/gnc-optiondb.i b/bindings/guile/gnc-optiondb.i index 5e8a3df693..ec810d5fc0 100644 --- a/bindings/guile/gnc-optiondb.i +++ b/bindings/guile/gnc-optiondb.i @@ -64,6 +64,7 @@ namespace std { %begin %{ +#include #include #include #include @@ -1975,26 +1976,13 @@ gnc_register_multichoice_callback_option(GncOptionDBPtr& db, const char* key, const char* doc_string, const char *value) { - gnc_commodity* commodity{}; const auto book{qof_session_get_book(gnc_get_current_session())}; const auto commodity_table{gnc_commodity_table_get_table(book)}; - const auto namespaces{gnc_commodity_table_get_namespaces(commodity_table)}; - GncOption* rv = nullptr; - for (auto node = namespaces; node && commodity == nullptr; - node = g_list_next(node)) - { - commodity = gnc_commodity_table_lookup(commodity_table, - (const char*)(node->data), - value); - - if (commodity) - { - rv = gnc_make_commodity_option(section, name, key, doc_string, commodity); - break; - } - } - g_list_free (namespaces); - return rv; + for (const auto& name_space : gnc_commodity_table_get_namespaces(commodity_table)) + if (auto commodity = gnc_commodity_table_lookup (commodity_table, name_space.c_str(), + value)) + return gnc_make_commodity_option(section, name, key, doc_string, commodity); + return nullptr; } static GncOption* diff --git a/gnucash/gnome-utils/dialog-commodity.cpp b/gnucash/gnome-utils/dialog-commodity.cpp index 743b6c2a22..7a5a372755 100644 --- a/gnucash/gnome-utils/dialog-commodity.cpp +++ b/gnucash/gnome-utils/dialog-commodity.cpp @@ -42,12 +42,15 @@ #include "dialog-commodity.h" #include "dialog-utils.h" +#include "gnc-commodity.hpp" #include "gnc-engine.h" #include "gnc-gtk-utils.h" #include "gnc-gui-query.h" #include "gnc-ui-util.h" #include "gnc-ui.h" +#include + /* This static indicates the debugging module that this .o belongs to. */ static QofLogModule log_module = GNC_MOD_GUI; @@ -560,7 +563,7 @@ gnc_ui_update_namespace_picker (GtkWidget *cbwe, GtkComboBox *combo_box; GtkTreeModel *model; GtkTreeIter iter, match; - GList *namespaces, *node; + std::vector namespaces; gboolean matched = FALSE; g_return_if_fail(GTK_IS_COMBO_BOX (cbwe)); @@ -582,12 +585,10 @@ gnc_ui_update_namespace_picker (GtkWidget *cbwe, case DIAG_COMM_NON_CURRENCY_SELECT: namespaces = gnc_commodity_table_get_namespaces (gnc_get_current_commodities()); - node = g_list_find_custom (namespaces, GNC_COMMODITY_NS_CURRENCY, collate); - if (node) - { - namespaces = g_list_remove_link (namespaces, node); - g_list_free_1 (node); - } + + if (auto it = std::find (namespaces.begin(), namespaces.end(), GNC_COMMODITY_NS_CURRENCY); + it != namespaces.end()) + namespaces.erase (it); if (gnc_commodity_namespace_is_iso (init_string)) init_string = nullptr; @@ -595,7 +596,7 @@ gnc_ui_update_namespace_picker (GtkWidget *cbwe, case DIAG_COMM_CURRENCY: default: - namespaces = g_list_prepend (nullptr, (gpointer)GNC_COMMODITY_NS_CURRENCY); + namespaces = { GNC_COMMODITY_NS_CURRENCY }; break; } @@ -623,10 +624,10 @@ gnc_ui_update_namespace_picker (GtkWidget *cbwe, } /* add all others to the combobox */ - namespaces = g_list_sort(namespaces, collate); - for (node = namespaces; node; node = node->next) + std::sort (namespaces.begin(), namespaces.end()); + for (const auto& ns_str : namespaces) { - auto ns = static_cast(node->data); + auto ns = ns_str.c_str(); /* Skip template, legacy and currency namespaces. The latter was added as first entry earlier */ if ((g_utf8_collate(ns, GNC_COMMODITY_NS_LEGACY) == 0) || @@ -650,7 +651,6 @@ gnc_ui_update_namespace_picker (GtkWidget *cbwe, if (matched) gtk_combo_box_set_active_iter (combo_box, &match); - g_list_free(namespaces); } diff --git a/gnucash/gnome/dialog-price-edit-db.cpp b/gnucash/gnome/dialog-price-edit-db.cpp index c129a0f8ab..9966beab02 100644 --- a/gnucash/gnome/dialog-price-edit-db.cpp +++ b/gnucash/gnome/dialog-price-edit-db.cpp @@ -242,11 +242,10 @@ gnc_prices_dialog_load_view (GtkTreeView *view, GNCPriceDB *pdb) auto oldest = gnc_time (nullptr); auto model = gtk_tree_view_get_model (view); const auto commodity_table = gnc_get_current_commodities (); - auto namespace_list = gnc_commodity_table_get_namespaces (commodity_table); - for (auto node_n = namespace_list; node_n; node_n = g_list_next (node_n)) + for (const auto& tmp_namespace_str : gnc_commodity_table_get_namespaces (commodity_table)) { - auto tmp_namespace = static_cast(node_n->data); + auto tmp_namespace = tmp_namespace_str.c_str(); DEBUG("Looking at namespace %s", tmp_namespace); auto commodity_list = gnc_commodity_table_get_commodities (commodity_table, tmp_namespace); for (auto node_c = commodity_list; node_c; node_c = g_list_next (node_c)) @@ -281,7 +280,6 @@ gnc_prices_dialog_load_view (GtkTreeView *view, GNCPriceDB *pdb) } g_list_free (commodity_list); } - g_list_free (namespace_list); return oldest; } diff --git a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp index 3543b51747..bb2bfb4e65 100644 --- a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp +++ b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp @@ -40,6 +40,7 @@ #include "gnc-uri-utils.h" #include "gnc-ui-util.h" #include "dialog-utils.h" +#include "gnc-commodity.hpp" #include "gnc-component-manager.h" @@ -446,8 +447,6 @@ GtkTreeModel *get_model (bool all_commodity) GtkTreeModel *store, *model; const gnc_commodity_table *commodity_table = gnc_get_current_commodities (); gnc_commodity *tmp_commodity = nullptr; - char *tmp_namespace = nullptr; - GList *namespace_list = gnc_commodity_table_get_namespaces (commodity_table); GtkTreeIter iter; store = GTK_TREE_MODEL(gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, @@ -460,9 +459,9 @@ GtkTreeModel *get_model (bool all_commodity) gtk_list_store_set (GTK_LIST_STORE(store), &iter, DISPLAYED_COMM, " ", SORT_COMM, " ", COMM_PTR, nullptr, SEP, false, -1); - for (auto node = namespace_list; node; node = g_list_next (node)) + for (const auto& tmp_namespace_str : gnc_commodity_table_get_namespaces (commodity_table)) { - tmp_namespace = (char*)node->data; + auto tmp_namespace = tmp_namespace_str.c_str(); DEBUG("Looking at namespace %s", tmp_namespace); /* Hide the template entry */ @@ -506,7 +505,6 @@ GtkTreeModel *get_model (bool all_commodity) } } } - g_list_free (namespace_list); g_object_unref (store); return model; diff --git a/gnucash/import-export/csv-imp/gnc-imp-props-tx.cpp b/gnucash/import-export/csv-imp/gnc-imp-props-tx.cpp index 760623b943..dd09938c5e 100644 --- a/gnucash/import-export/csv-imp/gnc-imp-props-tx.cpp +++ b/gnucash/import-export/csv-imp/gnc-imp-props-tx.cpp @@ -32,6 +32,7 @@ #include "gnc-ui-util.h" #include "Account.h" #include "Transaction.h" +#include "gnc-commodity.hpp" #include "gnc-pricedb.h" #include @@ -201,19 +202,16 @@ gnc_commodity* parse_commodity (const std::string& comm_str) if (!comm) { /* If that fails try mnemonic in all other namespaces */ - auto namespaces = gnc_commodity_table_get_namespaces(table); - for (auto ns = namespaces; ns; ns = ns->next) + for (const auto& ns_str : gnc_commodity_table_get_namespaces(table)) { - gchar* ns_str = (gchar*)ns->data; - if (g_utf8_collate(ns_str, GNC_COMMODITY_NS_CURRENCY) == 0) + if (ns_str == GNC_COMMODITY_NS_CURRENCY) continue; comm = gnc_commodity_table_lookup (table, - ns_str, comm_str.c_str()); + ns_str.c_str(), comm_str.c_str()); if (comm) break; } - g_list_free (namespaces); } if (!comm) diff --git a/gnucash/import-export/import-commodity-matcher.cpp b/gnucash/import-export/import-commodity-matcher.cpp index afd5d58949..24aff8e180 100644 --- a/gnucash/import-export/import-commodity-matcher.cpp +++ b/gnucash/import-export/import-commodity-matcher.cpp @@ -34,6 +34,7 @@ #include "Account.h" #include "Transaction.h" #include "dialog-commodity.h" +#include "gnc-commodity.hpp" #include "gnc-engine.h" #include "gnc-ui-util.h" @@ -64,11 +65,10 @@ gnc_commodity * gnc_import_select_commodity(const char * cusip, DEBUG("Looking for commodity with exchange_code: %s", cusip); g_assert(commodity_table); - GList *namespace_list = gnc_commodity_table_get_namespaces(commodity_table); - for (GList *n = namespace_list; !retval && n; n = g_list_next (n)) + for (const auto& ns_str : gnc_commodity_table_get_namespaces(commodity_table)) { - auto ns = static_cast(n->data); + auto ns = ns_str.c_str(); DEBUG("Looking at namespace %s", ns); GList *comm_list = gnc_commodity_table_get_commodities (commodity_table, ns); for (GList *m = comm_list; !retval && m; m = g_list_next (m)) @@ -82,10 +82,10 @@ gnc_commodity * gnc_import_select_commodity(const char * cusip, } } g_list_free (comm_list); + if (retval) + break; } - g_list_free(namespace_list); - if (retval == NULL && ask_on_unknown != 0) { const gchar *message = diff --git a/libgnucash/app-utils/gnc-quotes.cpp b/libgnucash/app-utils/gnc-quotes.cpp index 1fdf64a385..ac3938cf86 100644 --- a/libgnucash/app-utils/gnc-quotes.cpp +++ b/libgnucash/app-utils/gnc-quotes.cpp @@ -989,8 +989,6 @@ CommVec gnc_quotes_get_quotable_commodities (const gnc_commodity_table * table) { gnc_commodity_namespace * ns = NULL; - const char *name_space; - GList * nslist, * tmp; CommVec l; regex_t pattern; const char *expression = gnc_prefs_get_namespace_regexp (); @@ -1007,10 +1005,9 @@ gnc_quotes_get_quotable_commodities (const gnc_commodity_table * table) return CommVec (); } - nslist = gnc_commodity_table_get_namespaces (table); - for (tmp = nslist; tmp; tmp = tmp->next) + for (const auto& name_space_str : gnc_commodity_table_get_namespaces (table)) { - name_space = static_cast (tmp->data); + auto name_space = name_space_str.c_str(); if (regexec (&pattern, name_space, 0, NULL, 0) == 0) { // DEBUG ("Running list of %s commodities", name_space); @@ -1023,7 +1020,6 @@ gnc_quotes_get_quotable_commodities (const gnc_commodity_table * table) } } } - g_list_free (nslist); regfree (&pattern); } else diff --git a/libgnucash/backend/xml/io-gncxml-v2.cpp b/libgnucash/backend/xml/io-gncxml-v2.cpp index 562d685cfd..f0c2411e74 100644 --- a/libgnucash/backend/xml/io-gncxml-v2.cpp +++ b/libgnucash/backend/xml/io-gncxml-v2.cpp @@ -46,6 +46,7 @@ #include #include +#include "gnc-commodity.hpp" #include "gnc-engine.h" #include "gnc-pricedb-p.h" #include "Scrub.h" @@ -929,14 +930,6 @@ write_counts (FILE* out, ...) return success; } -static gint -compare_namespaces (gconstpointer a, gconstpointer b) -{ - const gchar* sa = (const gchar*) a; - const gchar* sb = (const gchar*) b; - return (g_strcmp0 (sa, sb)); -} - static gint compare_commodity_ids (gconstpointer a, gconstpointer b) { @@ -1039,25 +1032,20 @@ gboolean write_commodities (FILE* out, QofBook* book, sixtp_gdv2* gd) { gnc_commodity_table* tbl; - GList* namespaces; - GList* lp; gboolean success = TRUE; tbl = gnc_commodity_table_get_table (book); - namespaces = gnc_commodity_table_get_namespaces (tbl); - if (namespaces) - { - namespaces = g_list_sort (namespaces, compare_namespaces); - } + auto namespaces = gnc_commodity_table_get_namespaces (tbl); - for (lp = namespaces; success && lp; lp = lp->next) + std::sort (namespaces.begin(), namespaces.end()); + + for (const auto& name_space : namespaces) { GList* comms, *lp2; xmlNodePtr comnode; - comms = gnc_commodity_table_get_commodities (tbl, - static_cast (lp->data)); + comms = gnc_commodity_table_get_commodities (tbl, name_space.c_str()); comms = g_list_sort (comms, compare_commodity_ids); for (lp2 = comms; lp2; lp2 = lp2->next) @@ -1080,10 +1068,10 @@ write_commodities (FILE* out, QofBook* book, sixtp_gdv2* gd) } g_list_free (comms); + if (!success) + break; } - if (namespaces) g_list_free (namespaces); - return success; } diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp index 6a25851a7a..48f708fb00 100644 --- a/libgnucash/engine/gnc-commodity.cpp +++ b/libgnucash/engine/gnc-commodity.cpp @@ -1923,18 +1923,9 @@ gnc_commodity_table_has_namespace(const gnc_commodity_table * table, } static void -hash_keys_helper(gpointer key, gpointer value, gpointer data) +hash_keys_helper (const char* key, gnc_commodity* value, std::vector *l) { - auto l = (GList**)data; - *l = g_list_prepend(*l, key); -} - -static GList * -g_hash_table_keys(GHashTable * table) -{ - GList * l = nullptr; - g_hash_table_foreach(table, &hash_keys_helper, (gpointer) &l); - return l; + l->push_back (key); } static void @@ -1957,13 +1948,15 @@ g_hash_table_values(GHashTable * table) * see if any commodities in the namespace exist ********************************************************************/ -GList * +std::vector gnc_commodity_table_get_namespaces(const gnc_commodity_table * table) { + std::vector rv; if (!table) - return nullptr; + return rv; - return g_hash_table_keys(table->ns_table); + g_hash_table_foreach(table->ns_table, (GHFunc)hash_keys_helper, &rv); + return rv; } GList * @@ -2012,20 +2005,17 @@ gnc_commodity_is_currency(const gnc_commodity *cm) static CommodityList* commodity_table_get_all_noncurrency_commodities(const gnc_commodity_table* table) { - GList *node = nullptr, *nslist = gnc_commodity_table_get_namespaces(table); - CommodityList *retval = nullptr; - for (node = nslist; node; node=g_list_next(node)) + CommodityList *retval = NULL; + for (const auto& name_space : gnc_commodity_table_get_namespaces(table)) { - gnc_commodity_namespace *ns = nullptr; - if (g_strcmp0((char*)(node->data), GNC_COMMODITY_NS_CURRENCY) == 0 - || g_strcmp0((char*)(node->data), GNC_COMMODITY_NS_TEMPLATE) == 0) + gnc_commodity_namespace *ns = NULL; + if (name_space == GNC_COMMODITY_NS_CURRENCY || name_space == GNC_COMMODITY_NS_TEMPLATE) continue; - ns = gnc_commodity_table_find_namespace(table, (char*)(node->data)); + ns = gnc_commodity_table_find_namespace(table, name_space.c_str()); if (!ns) continue; retval = g_list_concat(g_hash_table_values(ns->cm_table), retval); } - g_list_free(nslist); return retval; } @@ -2079,8 +2069,6 @@ CommodityList * gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table) { gnc_commodity_namespace * ns = nullptr; - const char *name_space; - GList * nslist, * tmp; GList * l = nullptr; regex_t pattern; const char *expression = gnc_prefs_get_namespace_regexp(); @@ -2097,11 +2085,10 @@ gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table) return nullptr; } - nslist = gnc_commodity_table_get_namespaces(table); - for (tmp = nslist; tmp; tmp = tmp->next) + for (const auto& name_space_str : gnc_commodity_table_get_namespaces(table)) { - name_space = static_cast(tmp->data); - if (regexec(&pattern, name_space, 0, nullptr, 0) == 0) + auto name_space = name_space_str.c_str(); + if (regexec(&pattern, name_space, 0, NULL, 0) == 0) { DEBUG("Running list of %s commodities", name_space); ns = gnc_commodity_table_find_namespace(table, name_space); @@ -2111,7 +2098,6 @@ gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table) } } } - g_list_free(nslist); regfree(&pattern); } else diff --git a/libgnucash/engine/gnc-commodity.h b/libgnucash/engine/gnc-commodity.h index 6bef47643e..1438ccd94c 100644 --- a/libgnucash/engine/gnc-commodity.h +++ b/libgnucash/engine/gnc-commodity.h @@ -829,15 +829,6 @@ GList * gnc_commodity_namespace_get_commodity_list(const gnc_commodity_namespace int gnc_commodity_table_has_namespace(const gnc_commodity_table * table, const char * commodity_namespace); -/** Return a list of all namespaces in the commodity table. This - * returns both system and user defined namespaces. - * - * @return A pointer to the list of names. NULL if an invalid - * argument was supplied. - * - * @note It is the callers responsibility to free the list. */ -GList * gnc_commodity_table_get_namespaces(const gnc_commodity_table * t); - /** Return a list of all namespace data structures in the commodity table. This * returns both system and user defined namespace structures. * diff --git a/libgnucash/engine/gnc-commodity.hpp b/libgnucash/engine/gnc-commodity.hpp index 223d9abe72..57dfbcda08 100644 --- a/libgnucash/engine/gnc-commodity.hpp +++ b/libgnucash/engine/gnc-commodity.hpp @@ -34,6 +34,7 @@ #define GNC_COMMODITY_HPP #include +#include #include @@ -51,6 +52,14 @@ using CommVec = std::vector; void gnc_quote_source_set_fq_installed (const char* version_string, const std::vector& sources_list); + +/** Return a list of all namespaces in the commodity table. This + * returns both system and user defined namespaces. + * + * @return A vector to the list of names. An empty vector if an + * invalid argument was supplied. */ +std::vector gnc_commodity_table_get_namespaces (const gnc_commodity_table * t); + #endif /* GNC_COMMODITY_HPP */ /** @} */ /** @} */ diff --git a/libgnucash/engine/gnc-optiondb.cpp b/libgnucash/engine/gnc-optiondb.cpp index 17d23d8fb6..fee7e0d57b 100644 --- a/libgnucash/engine/gnc-optiondb.cpp +++ b/libgnucash/engine/gnc-optiondb.cpp @@ -31,6 +31,7 @@ #include "kvp-frame.hpp" #include "qofbookslots.h" #include "guid.hpp" +#include "gnc-commodity.hpp" #include "gnc-optiondb.h" #include "gnc-optiondb.hpp" #include "gnc-optiondb-impl.hpp" @@ -693,13 +694,9 @@ gnc_register_commodity_option(GncOptionDB* db, const char* section, gnc_commodity* commodity{}; const auto book{qof_session_get_book(gnc_get_current_session())}; const auto commodity_table{gnc_commodity_table_get_table(book)}; - const auto namespaces{gnc_commodity_table_get_namespaces(commodity_table)}; - for (auto node = namespaces; node && commodity == nullptr; - node = g_list_next(node)) + for (const auto& name_space : gnc_commodity_table_get_namespaces(commodity_table)) { - commodity = gnc_commodity_table_lookup(commodity_table, - (const char*)(node->data), - value); + commodity = gnc_commodity_table_lookup(commodity_table, name_space.c_str(), value); if (commodity) break; } @@ -707,7 +704,6 @@ gnc_register_commodity_option(GncOptionDB* db, const char* section, commodity, GncOptionUIType::COMMODITY}}; db->register_option(section, std::move(option)); - g_list_free (namespaces); } void diff --git a/libgnucash/engine/test-core/test-engine-stuff.cpp b/libgnucash/engine/test-core/test-engine-stuff.cpp index 3baf38f78d..58ba9ccd0f 100644 --- a/libgnucash/engine/test-core/test-engine-stuff.cpp +++ b/libgnucash/engine/test-core/test-engine-stuff.cpp @@ -58,6 +58,7 @@ #include "Account.h" #include "AccountP.hpp" +#include "gnc-commodity.hpp" #include "gnc-engine.h" #include "gnc-session.h" #include "Transaction.h" @@ -446,21 +447,19 @@ get_random_commodity_namespace(void) static gnc_commodity * get_random_commodity_from_table (gnc_commodity_table *table) { - GList *namespaces; gnc_commodity *com = NULL; g_return_val_if_fail (table, NULL); - namespaces = gnc_commodity_table_get_namespaces (table); + auto namespaces = gnc_commodity_table_get_namespaces (table); do { GList *commodities; - char *name_space; - name_space = static_cast(get_random_list_element (namespaces)); + auto name_space = namespaces.at (get_random_int_in_range (0, namespaces.size() - 1)); - commodities = gnc_commodity_table_get_commodities (table, name_space); + commodities = gnc_commodity_table_get_commodities (table, name_space.c_str()); if (!commodities) continue; @@ -471,9 +470,6 @@ get_random_commodity_from_table (gnc_commodity_table *table) } while (!com); - - g_list_free (namespaces); - return com; } @@ -557,16 +553,13 @@ make_random_changes_to_commodity (gnc_commodity *com) void make_random_changes_to_commodity_table (gnc_commodity_table *table) { - GList *namespaces; - GList *node; - g_return_if_fail (table); - namespaces = gnc_commodity_table_get_namespaces (table); + auto namespaces = gnc_commodity_table_get_namespaces (table); - for (node = namespaces; node; node = node->next) + for (const auto& ns_str : namespaces) { - auto ns = static_cast(node->data); + auto ns = ns_str.c_str(); GList *commodities; GList *com_node; @@ -586,8 +579,6 @@ make_random_changes_to_commodity_table (gnc_commodity_table *table) g_list_free (commodities); } - - g_list_free (namespaces); } /* ================================================================= */ /* Price stuff */ From ecdb04e0c0c7f7dad572958fca7cdc617dcb5279 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Tue, 30 Apr 2024 23:20:20 +0800 Subject: [PATCH 2/6] gnc_commodity_table_get_commodities returns std::vector --- bindings/engine-common.i | 1 - bindings/engine.i | 2 +- common/base-typemaps.i | 43 ++++++++++- gnucash/gnome-utils/dialog-commodity.cpp | 9 +-- gnucash/gnome-utils/gnc-currency-edit.cpp | 11 +-- gnucash/gnome/dialog-price-edit-db.cpp | 5 +- .../csv-imp/assistant-csv-price-import.cpp | 7 +- .../import-commodity-matcher.cpp | 6 +- libgnucash/backend/xml/io-gncxml-v2.cpp | 18 ++--- libgnucash/engine/gnc-commodity.cpp | 76 +++++++++---------- libgnucash/engine/gnc-commodity.h | 37 --------- libgnucash/engine/gnc-commodity.hpp | 34 +++++++++ .../engine/test-core/test-engine-stuff.cpp | 21 +---- 13 files changed, 132 insertions(+), 138 deletions(-) diff --git a/bindings/engine-common.i b/bindings/engine-common.i index 4d360f481e..b0397a479e 100644 --- a/bindings/engine-common.i +++ b/bindings/engine-common.i @@ -32,7 +32,6 @@ static const GncGUID * gncAccountGetGUID(Account *x) %typemap(newfree) TransList * "g_list_free($1);" %typemap(newfree) PriceList * "g_list_free($1);" %typemap(newfree) LotList * "g_list_free($1);" -%typemap(newfree) CommodityList * "g_list_free($1);" %typemap(freearg) AccountList * "g_list_free($1);" diff --git a/bindings/engine.i b/bindings/engine.i index 4b7adbafe7..c9970d943f 100644 --- a/bindings/engine.i +++ b/bindings/engine.i @@ -84,7 +84,7 @@ GLIST_HELPER_INOUT(LotList, SWIGTYPE_p_GNCLot); GLIST_HELPER_INOUT(AccountList, SWIGTYPE_p_Account); GLIST_HELPER_INOUT(PriceList, SWIGTYPE_p_GNCPrice); // TODO: free PriceList? -GLIST_HELPER_INOUT(CommodityList, SWIGTYPE_p_gnc_commodity); +VECTOR_HELPER_INOUT(CommVec, SWIGTYPE_p_gnc_commodity, gnc_commodity); VECTOR_HELPER_INOUT(SplitsVec, SWIGTYPE_p_Split, Split); VECTORREF_HELPER_INOUT(SplitsVec&, SWIGTYPE_p_Split, Split); VECTOR_HELPER_INOUT(AccountVec, SWIGTYPE_p_Account, Account); diff --git a/common/base-typemaps.i b/common/base-typemaps.i index 2a878a0122..0ecb449ff4 100644 --- a/common/base-typemaps.i +++ b/common/base-typemaps.i @@ -289,7 +289,7 @@ typedef char gchar; } } -%typemap(out) GList *, CommodityList *, SplitList *, AccountList *, LotList *, +%typemap(out) GList *, SplitList *, AccountList *, LotList *, MonetaryList *, PriceList *, EntryList * { gpointer data; GList *l; @@ -332,4 +332,45 @@ typedef char gchar; } $result = list; } + +%typemap(out) CommodityVec +{ + PyObject *list = PyList_New(0); + for (auto data : $1) + { + if (GNC_IS_ACCOUNT(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_Account, 0)); + else if (GNC_IS_SPLIT(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_Split, 0)); + else if (GNC_IS_TRANSACTION(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_Transaction, 0)); + else if (GNC_IS_COMMODITY(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_gnc_commodity, 0)); + else if (GNC_IS_COMMODITY_NAMESPACE(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_gnc_commodity_namespace, 0)); + else if (GNC_IS_LOT(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_GNCLot, 0)); + else if (GNC_IS_PRICE(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_GNCPrice, 0)); + else if (GNC_IS_INVOICE(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p__gncInvoice, 0)); + else if (GNC_IS_ENTRY(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p__gncEntry, 0)); + else if (GNC_IS_CUSTOMER(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p__gncCustomer, 0)); + else if (GNC_IS_VENDOR(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p__gncVendor, 0)); + else if (GNC_IS_EMPLOYEE(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p__gncEmployee, 0)); + else if (GNC_IS_JOB(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p__gncJob, 0)); + else if (GNC_IS_TAXTABLE(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p__gncTaxTable, 0)); + else if ($1_descriptor == $descriptor(MonetaryList *)) + PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(gnc_monetary *), 0)); + else + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_void, 0)); + } + $result = list; +} #endif diff --git a/gnucash/gnome-utils/dialog-commodity.cpp b/gnucash/gnome-utils/dialog-commodity.cpp index 7a5a372755..5f64ee845c 100644 --- a/gnucash/gnome-utils/dialog-commodity.cpp +++ b/gnucash/gnome-utils/dialog-commodity.cpp @@ -445,7 +445,6 @@ gnc_ui_update_commodity_picker (GtkWidget *cbwe, const gchar * name_space, const gchar * init_string) { - GList * commodities; GList * iterator = nullptr; GList * commodity_items = nullptr; GtkComboBox *combo_box; @@ -471,14 +470,10 @@ gnc_ui_update_commodity_picker (GtkWidget *cbwe, gtk_combo_box_set_active(combo_box, -1); table = gnc_commodity_table_get_table (gnc_get_current_book ()); - commodities = gnc_commodity_table_get_commodities(table, name_space); - for (iterator = commodities; iterator; iterator = iterator->next) + for (auto comm : gnc_commodity_table_get_commodities(table, name_space)) { - commodity_items = - g_list_prepend (commodity_items, - (gpointer) gnc_commodity_get_printname(GNC_COMMODITY(iterator->data))); + commodity_items = g_list_prepend (commodity_items, (gpointer) gnc_commodity_get_printname(comm)); } - g_list_free(commodities); commodity_items = g_list_sort(commodity_items, collate); for (iterator = commodity_items; iterator; iterator = iterator->next) diff --git a/gnucash/gnome-utils/gnc-currency-edit.cpp b/gnucash/gnome-utils/gnc-currency-edit.cpp index 0481e5b45f..307f626cf2 100644 --- a/gnucash/gnome-utils/gnc-currency-edit.cpp +++ b/gnucash/gnome-utils/gnc-currency-edit.cpp @@ -48,6 +48,8 @@ #include +#include + #include #include #include @@ -56,6 +58,7 @@ #include "gnc-currency-edit.h" #include "gnc-commodity.h" +#include "gnc-commodity.hpp" #include "gnc-gtk-utils.h" #include "gnc-ui-util.h" #include "gnc-engine.h" @@ -311,12 +314,10 @@ add_item(gnc_commodity *commodity, GNCCurrencyEdit *gce) static void fill_currencies(GNCCurrencyEdit *gce) { - GList *currencies; - - currencies = gnc_commodity_table_get_commodities + auto currencies = gnc_commodity_table_get_commodities (gnc_get_current_commodities (), GNC_COMMODITY_NS_CURRENCY); - g_list_foreach(currencies, (GFunc)add_item, gce); - g_list_free(currencies); + std::for_each (currencies.begin(), currencies.end(), + [gce](auto comm){ add_item (comm, gce); }); } diff --git a/gnucash/gnome/dialog-price-edit-db.cpp b/gnucash/gnome/dialog-price-edit-db.cpp index 9966beab02..8052b873c0 100644 --- a/gnucash/gnome/dialog-price-edit-db.cpp +++ b/gnucash/gnome/dialog-price-edit-db.cpp @@ -247,10 +247,8 @@ gnc_prices_dialog_load_view (GtkTreeView *view, GNCPriceDB *pdb) { auto tmp_namespace = tmp_namespace_str.c_str(); DEBUG("Looking at namespace %s", tmp_namespace); - auto commodity_list = gnc_commodity_table_get_commodities (commodity_table, tmp_namespace); - for (auto node_c = commodity_list; node_c; node_c = g_list_next (node_c)) + for (auto tmp_commodity : gnc_commodity_table_get_commodities (commodity_table, tmp_namespace)) { - auto tmp_commodity = static_cast(node_c->data); auto num = gnc_pricedb_num_prices (pdb, tmp_commodity); DEBUG("Looking at commodity %s, Number of prices %d", gnc_commodity_get_fullname (tmp_commodity), num); @@ -278,7 +276,6 @@ gnc_prices_dialog_load_view (GtkTreeView *view, GNCPriceDB *pdb) g_list_free_full (list, (GDestroyNotify)gnc_price_unref); } } - g_list_free (commodity_list); } return oldest; diff --git a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp index bb2bfb4e65..15b4bfc18d 100644 --- a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp +++ b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp @@ -446,7 +446,6 @@ GtkTreeModel *get_model (bool all_commodity) { GtkTreeModel *store, *model; const gnc_commodity_table *commodity_table = gnc_get_current_commodities (); - gnc_commodity *tmp_commodity = nullptr; GtkTreeIter iter; store = GTK_TREE_MODEL(gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, @@ -469,8 +468,6 @@ GtkTreeModel *get_model (bool all_commodity) { if ((g_utf8_collate (tmp_namespace, GNC_COMMODITY_NS_CURRENCY ) == 0) || (all_commodity == true)) { - auto comm_list = gnc_commodity_table_get_commodities (commodity_table, tmp_namespace); - // if this is the CURRENCY, add a row to be identified as a separator row if ((g_utf8_collate (tmp_namespace, GNC_COMMODITY_NS_CURRENCY) == 0) && (all_commodity == true)) { @@ -479,11 +476,10 @@ GtkTreeModel *get_model (bool all_commodity) SORT_COMM, "CURRENCY-", COMM_PTR, nullptr, SEP, true, -1); } - for (auto node = comm_list; node; node = g_list_next (node)) + for (auto tmp_commodity : gnc_commodity_table_get_commodities (commodity_table, tmp_namespace)) { const gchar *name_str; gchar *sort_str; - tmp_commodity = (gnc_commodity*)node->data; DEBUG("Looking at commodity %s", gnc_commodity_get_fullname (tmp_commodity)); name_str = gnc_commodity_get_printname (tmp_commodity); @@ -501,7 +497,6 @@ GtkTreeModel *get_model (bool all_commodity) g_free (sort_str); } - g_list_free (comm_list); } } } diff --git a/gnucash/import-export/import-commodity-matcher.cpp b/gnucash/import-export/import-commodity-matcher.cpp index 24aff8e180..948f32b036 100644 --- a/gnucash/import-export/import-commodity-matcher.cpp +++ b/gnucash/import-export/import-commodity-matcher.cpp @@ -70,18 +70,16 @@ gnc_commodity * gnc_import_select_commodity(const char * cusip, { auto ns = ns_str.c_str(); DEBUG("Looking at namespace %s", ns); - GList *comm_list = gnc_commodity_table_get_commodities (commodity_table, ns); - for (GList *m = comm_list; !retval && m; m = g_list_next (m)) + for (auto com : gnc_commodity_table_get_commodities (commodity_table, ns)) { - auto com = static_cast(m->data); DEBUG("Looking at commodity %s", gnc_commodity_get_fullname (com)); if (!g_strcmp0 (gnc_commodity_get_cusip (com), cusip)) { retval = com; DEBUG("Commodity %s matches.", gnc_commodity_get_fullname (com)); + break; } } - g_list_free (comm_list); if (retval) break; } diff --git a/libgnucash/backend/xml/io-gncxml-v2.cpp b/libgnucash/backend/xml/io-gncxml-v2.cpp index f0c2411e74..13cbde5d0b 100644 --- a/libgnucash/backend/xml/io-gncxml-v2.cpp +++ b/libgnucash/backend/xml/io-gncxml-v2.cpp @@ -931,12 +931,9 @@ write_counts (FILE* out, ...) } static gint -compare_commodity_ids (gconstpointer a, gconstpointer b) +compare_commodity_less (gnc_commodity* a, gnc_commodity* b) { - const gnc_commodity* ca = (const gnc_commodity*) a; - const gnc_commodity* cb = (const gnc_commodity*) b; - return (g_strcmp0 (gnc_commodity_get_mnemonic (ca), - gnc_commodity_get_mnemonic (cb))); + return (g_strcmp0 (gnc_commodity_get_mnemonic (a), gnc_commodity_get_mnemonic (b)) < 0); } static gboolean write_pricedb (FILE* out, QofBook* book, sixtp_gdv2* gd); @@ -1042,16 +1039,14 @@ write_commodities (FILE* out, QofBook* book, sixtp_gdv2* gd) for (const auto& name_space : namespaces) { - GList* comms, *lp2; xmlNodePtr comnode; - comms = gnc_commodity_table_get_commodities (tbl, name_space.c_str()); - comms = g_list_sort (comms, compare_commodity_ids); + auto comms = gnc_commodity_table_get_commodities (tbl, name_space.c_str()); + std::sort (comms.begin(), comms.end(), compare_commodity_less); - for (lp2 = comms; lp2; lp2 = lp2->next) + for (auto comm : comms) { - comnode = gnc_commodity_dom_tree_create (static_cast - (lp2->data)); + comnode = gnc_commodity_dom_tree_create (comm); if (comnode == NULL) continue; @@ -1067,7 +1062,6 @@ write_commodities (FILE* out, QofBook* book, sixtp_gdv2* gd) sixtp_run_callback (gd, "commodities"); } - g_list_free (comms); if (!success) break; } diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp index 48f708fb00..6eb64b7675 100644 --- a/libgnucash/engine/gnc-commodity.cpp +++ b/libgnucash/engine/gnc-commodity.cpp @@ -1763,29 +1763,15 @@ gnc_commodity_table_find_full(const gnc_commodity_table * table, const char * name_space, const char * fullname) { - gnc_commodity * retval = nullptr; - GList * all; - GList * iterator; - if (!fullname || (fullname[0] == '\0')) return nullptr; - all = gnc_commodity_table_get_commodities(table, name_space); + auto commodities{gnc_commodity_table_get_commodities(table, name_space)}; + auto it = std::find_if (commodities.begin(), commodities.end(), + [fullname](auto comm) + { return !g_strcmp0 (fullname, gnc_commodity_get_printname(comm)); }); - for (iterator = all; iterator; iterator = iterator->next) - { - auto commodity = GNC_COMMODITY (iterator->data); - if (!strcmp(fullname, - gnc_commodity_get_printname(commodity))) - { - retval = commodity; - break; - } - } - - g_list_free (all); - - return retval; + return it == commodities.end() ? nullptr : *it;; } @@ -2002,10 +1988,10 @@ gnc_commodity_is_currency(const gnc_commodity *cm) * list commodities in a given namespace ********************************************************************/ -static CommodityList* +static CommVec commodity_table_get_all_noncurrency_commodities(const gnc_commodity_table* table) { - CommodityList *retval = NULL; + CommVec retval; for (const auto& name_space : gnc_commodity_table_get_namespaces(table)) { gnc_commodity_namespace *ns = NULL; @@ -2014,26 +2000,33 @@ commodity_table_get_all_noncurrency_commodities(const gnc_commodity_table* table ns = gnc_commodity_table_find_namespace(table, name_space.c_str()); if (!ns) continue; - retval = g_list_concat(g_hash_table_values(ns->cm_table), retval); + auto val = g_hash_table_values(ns->cm_table); + for (auto n = val; n; n = n->next) + retval.push_back (GNC_COMMODITY(n->data)); + g_list_free (val); } return retval; } -CommodityList * +CommVec gnc_commodity_table_get_commodities(const gnc_commodity_table * table, const char * name_space) { - gnc_commodity_namespace * ns = nullptr; + CommVec retval; if (!table) - return nullptr; + return retval; if (g_strcmp0(name_space, GNC_COMMODITY_NS_NONISO_GUI) == 0) return commodity_table_get_all_noncurrency_commodities(table); - ns = gnc_commodity_table_find_namespace(table, name_space); + auto ns = gnc_commodity_table_find_namespace(table, name_space); if (!ns) - return nullptr; + return retval; - return g_hash_table_values(ns->cm_table); + auto val = g_hash_table_values(ns->cm_table); + for (auto n = val; n; n = n->next) + retval.push_back (GNC_COMMODITY(n->data)); + g_list_free (val); + return retval; } /******************************************************************** @@ -2044,45 +2037,45 @@ gnc_commodity_table_get_commodities(const gnc_commodity_table * table, static void get_quotables_helper1(gpointer key, gpointer value, gpointer data) { - auto comm = GNC_COMMODITY(value); + auto comm{GNC_COMMODITY(value)}; + auto rv{static_cast(data)}; gnc_commodityPrivate* priv = GET_PRIVATE(comm); - auto l = static_cast(data); if (!priv->quote_flag || !priv->quote_source || !priv->quote_source->get_supported()) return; - *l = g_list_prepend(*l, value); + rv->push_back (comm); } static gboolean get_quotables_helper2 (gnc_commodity *comm, gpointer data) { - auto l = static_cast(data); gnc_commodityPrivate* priv = GET_PRIVATE(comm); + auto rv{static_cast(data)}; if (!priv->quote_flag || priv->quote_source || !priv->quote_source->get_supported()) return TRUE; - *l = g_list_prepend(*l, comm); + rv->push_back (comm); return TRUE; } -CommodityList * +CommVec gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table) { gnc_commodity_namespace * ns = nullptr; - GList * l = nullptr; + CommVec rv; regex_t pattern; const char *expression = gnc_prefs_get_namespace_regexp(); ENTER("table=%p, expression=%s", table, expression); if (!table) - return nullptr; + return {}; if (expression && *expression) { if (regcomp(&pattern, expression, REG_EXTENDED | REG_ICASE) != 0) { LEAVE("Cannot compile regex"); - return nullptr; + return {}; } for (const auto& name_space_str : gnc_commodity_table_get_namespaces(table)) @@ -2094,7 +2087,7 @@ gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table) ns = gnc_commodity_table_find_namespace(table, name_space); if (ns) { - g_hash_table_foreach(ns->cm_table, &get_quotables_helper1, (gpointer) &l); + g_hash_table_foreach(ns->cm_table, get_quotables_helper1, &rv); } } } @@ -2102,11 +2095,10 @@ gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table) } else { - gnc_commodity_table_foreach_commodity(table, get_quotables_helper2, - (gpointer) &l); + gnc_commodity_table_foreach_commodity(table, get_quotables_helper2, &rv); } - LEAVE("list head %p", l); - return l; + LEAVE("list head %p", &rv); + return rv; } /******************************************************************** diff --git a/libgnucash/engine/gnc-commodity.h b/libgnucash/engine/gnc-commodity.h index 1438ccd94c..8b05ede069 100644 --- a/libgnucash/engine/gnc-commodity.h +++ b/libgnucash/engine/gnc-commodity.h @@ -115,8 +115,6 @@ GType gnc_commodity_namespace_get_type(void); */ #define GNC_COMMODITY_MAX_FRACTION 1000000000 -typedef GList CommodityList; - /** @name Commodity Quote Source functions @{ */ @@ -888,41 +886,6 @@ void gnc_commodity_table_delete_namespace(gnc_commodity_table * table, * commodities, or the routine was passed a bad argument. */ guint gnc_commodity_table_get_size(const gnc_commodity_table* tbl); -/** Return a list of all commodities in the commodity table that are - * in the given namespace. - * - * @param table A pointer to the commodity table - * - * @param commodity_namespace A string indicating which commodities should be - * returned. It is a required argument. - * - * @return A pointer to the list of commodities. NULL if an invalid - * argument was supplied, or the namespace could not be found. - * - * @note It is the callers responsibility to free the list. */ -CommodityList * gnc_commodity_table_get_commodities( - const gnc_commodity_table * table, const char * commodity_namespace); - -/** This function returns a list of commodities for which price quotes - * should be retrieved. It will scan the entire commodity table (or - * a subset) and check each commodity to see if the price_quote_flag - * field has been set. All matching commodities are queued onto a - * list, and the head of that list is returned. Use the command-line - * given expression as a filter on the commodities to be returned. If - * non-null, only commodities in namespace that match the specified - * regular expression are checked. If none was given, all - * commodities are checked. - * - * @param table A pointer to the commodity table - * - * @return A pointer to a list of commodities. NULL if invalid - * arguments were supplied or if there no commodities are flagged for - * quote retrieval. - * - * @note It is the callers responsibility to free the list. */ -CommodityList * gnc_commodity_table_get_quotable_commodities( - const gnc_commodity_table * table); - /** Call a function once for each commodity in the commodity table. * This table walk returns whenever the end of the table is reached, * or the function returns FALSE. diff --git a/libgnucash/engine/gnc-commodity.hpp b/libgnucash/engine/gnc-commodity.hpp index 57dfbcda08..00e02e01e4 100644 --- a/libgnucash/engine/gnc-commodity.hpp +++ b/libgnucash/engine/gnc-commodity.hpp @@ -60,6 +60,40 @@ void gnc_quote_source_set_fq_installed (const char* version_string, * invalid argument was supplied. */ std::vector gnc_commodity_table_get_namespaces (const gnc_commodity_table * t); + +/** Return a vector of all commodities in the commodity table that are + * in the given namespace. + * + * @param table A pointer to the commodity table + * + * @param commodity_namespace A string indicating which commodities should be + * returned. It is a required argument. + * + * @return A pointer to the list of commodities. NULL if an invalid + * argument was supplied, or the namespace could not be found. + */ + +CommVec gnc_commodity_table_get_commodities (const gnc_commodity_table *, const char *); + +/** This function returns a vector of commodities for which price + * quotes should be retrieved. It will scan the entire commodity + * table (or a subset) and check each commodity to see if the + * price_quote_flag field has been set. All matching commodities are + * queued onto a list, and the head of that list is returned. Use + * the command-line given expression as a filter on the commodities + * to be returned. If non-null, only commodities in namespace that + * match the specified regular expression are checked. If none was + * given, all commodities are checked. + * + * @param table A pointer to the commodity table + * + * @return A pointer to a list of commodities. NULL if invalid + * arguments were supplied or if there no commodities are flagged for + * quote retrieval. + */ + +CommVec gnc_commodity_table_get_quotable_commodities (const gnc_commodity_table*); + #endif /* GNC_COMMODITY_HPP */ /** @} */ /** @} */ diff --git a/libgnucash/engine/test-core/test-engine-stuff.cpp b/libgnucash/engine/test-core/test-engine-stuff.cpp index 58ba9ccd0f..7c781ced92 100644 --- a/libgnucash/engine/test-core/test-engine-stuff.cpp +++ b/libgnucash/engine/test-core/test-engine-stuff.cpp @@ -455,18 +455,11 @@ get_random_commodity_from_table (gnc_commodity_table *table) do { - GList *commodities; - auto name_space = namespaces.at (get_random_int_in_range (0, namespaces.size() - 1)); - commodities = gnc_commodity_table_get_commodities (table, name_space.c_str()); - if (!commodities) - continue; - - com = static_cast(get_random_list_element (commodities)); - - g_list_free (commodities); + auto commodities = gnc_commodity_table_get_commodities (table, name_space.c_str()); + com = commodities[std::rand() % commodities.size()]; } while (!com); @@ -560,24 +553,16 @@ make_random_changes_to_commodity_table (gnc_commodity_table *table) for (const auto& ns_str : namespaces) { auto ns = ns_str.c_str(); - GList *commodities; - GList *com_node; if (gnc_commodity_namespace_is_iso (ns)) continue; - commodities = gnc_commodity_table_get_commodities (table, ns); - - for (com_node = commodities; com_node; com_node = com_node->next) + for (auto com : gnc_commodity_table_get_commodities (table, ns)) { - auto com = static_cast(com_node->data); - gnc_commodity_table_remove (table, com); make_random_changes_to_commodity (com); gnc_commodity_table_insert (table, com); } - - g_list_free (commodities); } } /* ================================================================= */ From 2f4ab3c026ba91b1efeb8e0c0ba7991148e89b79 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Tue, 30 Apr 2024 23:35:13 +0800 Subject: [PATCH 3/6] [gnucash/*.cpp] use c++ algorithms with commodities --- gnucash/gnome-utils/dialog-commodity.cpp | 29 +++++-------------- .../import-commodity-matcher.cpp | 19 ++++++------ 2 files changed, 17 insertions(+), 31 deletions(-) diff --git a/gnucash/gnome-utils/dialog-commodity.cpp b/gnucash/gnome-utils/dialog-commodity.cpp index 5f64ee845c..87880a8b1e 100644 --- a/gnucash/gnome-utils/dialog-commodity.cpp +++ b/gnucash/gnome-utils/dialog-commodity.cpp @@ -429,15 +429,6 @@ gnc_ui_select_commodity_namespace_changed_cb (GtkComboBox *cbwe, /******************************************************************** * gnc_ui_update_commodity_picker ********************************************************************/ -static int -collate(gconstpointer a, gconstpointer b) -{ - if (!a) - return -1; - if (!b) - return 1; - return g_utf8_collate (static_cast(a), static_cast(b)); -} void @@ -445,15 +436,13 @@ gnc_ui_update_commodity_picker (GtkWidget *cbwe, const gchar * name_space, const gchar * init_string) { - GList * iterator = nullptr; - GList * commodity_items = nullptr; + std::vector commodity_items; GtkComboBox *combo_box; GtkEntry *entry; GtkTreeModel *model; GtkTreeIter iter; gnc_commodity_table *table; gint current = 0, match = 0; - gchar *name; g_return_if_fail(GTK_IS_COMBO_BOX(cbwe)); g_return_if_fail(name_space); @@ -470,25 +459,23 @@ gnc_ui_update_commodity_picker (GtkWidget *cbwe, gtk_combo_box_set_active(combo_box, -1); table = gnc_commodity_table_get_table (gnc_get_current_book ()); + for (auto comm : gnc_commodity_table_get_commodities(table, name_space)) - { - commodity_items = g_list_prepend (commodity_items, (gpointer) gnc_commodity_get_printname(comm)); - } + commodity_items.push_back (gnc_commodity_get_printname(comm)); - commodity_items = g_list_sort(commodity_items, collate); - for (iterator = commodity_items; iterator; iterator = iterator->next) + std::sort (commodity_items.end(), commodity_items.begin()); + + for (auto name : commodity_items) { - name = (char *)iterator->data; gtk_list_store_append(GTK_LIST_STORE(model), &iter); - gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, name, -1); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, name.c_str(), -1); - if (init_string && g_utf8_collate(name, init_string) == 0) + if (init_string && name == init_string) match = current; current++; } gtk_combo_box_set_active(combo_box, match); - g_list_free(commodity_items); } diff --git a/gnucash/import-export/import-commodity-matcher.cpp b/gnucash/import-export/import-commodity-matcher.cpp index 948f32b036..cbf27fa839 100644 --- a/gnucash/import-export/import-commodity-matcher.cpp +++ b/gnucash/import-export/import-commodity-matcher.cpp @@ -24,6 +24,7 @@ @author Copyright (C) 2002 Benoit Grégoire */ #include +#include #include #include @@ -70,18 +71,16 @@ gnc_commodity * gnc_import_select_commodity(const char * cusip, { auto ns = ns_str.c_str(); DEBUG("Looking at namespace %s", ns); - for (auto com : gnc_commodity_table_get_commodities (commodity_table, ns)) + auto commodities{gnc_commodity_table_get_commodities (commodity_table, ns)}; + auto it = std::find_if (commodities.begin(), commodities.end(), + [cusip](auto com) + { return !g_strcmp0 (gnc_commodity_get_cusip (com), cusip); }); + if (it != commodities.end()) { - DEBUG("Looking at commodity %s", gnc_commodity_get_fullname (com)); - if (!g_strcmp0 (gnc_commodity_get_cusip (com), cusip)) - { - retval = com; - DEBUG("Commodity %s matches.", gnc_commodity_get_fullname (com)); - break; - } - } - if (retval) + retval = *it; + DEBUG("Commodity %s matches.", gnc_commodity_get_fullname (*it)); break; + }; } if (retval == NULL && ask_on_unknown != 0) From 2ddb1919535aba3a08e5283bbd9867a1cbc447b4 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Wed, 1 May 2024 07:39:12 +0800 Subject: [PATCH 4/6] gnc_commodity_namespace->cm_table is an unordered_map --- libgnucash/engine/gnc-commodity.cpp | 70 ++++++++++------------------- 1 file changed, 23 insertions(+), 47 deletions(-) diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp index 6eb64b7675..79081e9a4e 100644 --- a/libgnucash/engine/gnc-commodity.cpp +++ b/libgnucash/engine/gnc-commodity.cpp @@ -107,13 +107,15 @@ struct _GncCommodityClass static void commodity_free(gnc_commodity * cm); static void gnc_commodity_set_default_symbol(gnc_commodity *, const char *); +using StrCommodityMap = std::unordered_map; + struct gnc_commodity_namespace_s { QofInstance inst; const gchar *name; gboolean iso4217; - GHashTable * cm_table; + StrCommodityMap cm_table; GList * cm_list; }; @@ -1659,7 +1661,7 @@ gnc_commodity_obtain_twin (const gnc_commodity *from, QofBook *book) static void count_coms(gpointer key, gpointer value, gpointer user_data) { - GHashTable *tbl = ((gnc_commodity_namespace*)value)->cm_table; + auto tbl = ((gnc_commodity_namespace*)value)->cm_table; guint *count = (guint*)user_data; if (g_strcmp0((char*)key, GNC_COMMODITY_NS_CURRENCY) == 0) @@ -1670,7 +1672,7 @@ count_coms(gpointer key, gpointer value, gpointer user_data) if (!value) return; - *count += g_hash_table_size(tbl); + *count += tbl.size(); } guint @@ -1712,7 +1714,7 @@ gnc_commodity_table_lookup(const gnc_commodity_table * table, if (it != gnc_new_iso_codes.end()) mnemonic = it->second.c_str(); } - return GNC_COMMODITY(g_hash_table_lookup(nsp->cm_table, (gpointer)mnemonic)); + return GNC_COMMODITY(nsp->cm_table[mnemonic]); } else { @@ -1838,10 +1840,8 @@ gnc_commodity_table_insert(gnc_commodity_table * table, nsp = gnc_commodity_table_add_namespace(table, ns_name, book); PINFO ("insert %p %s into nsp=%p %s", priv->mnemonic, priv->mnemonic, - nsp->cm_table, nsp->name); - g_hash_table_insert(nsp->cm_table, - (gpointer)CACHE_INSERT(priv->mnemonic), - (gpointer)comm); + &nsp->cm_table, nsp->name); + nsp->cm_table [priv->mnemonic] = comm; nsp->cm_list = g_list_append(nsp->cm_list, comm); qof_event_gen (&comm->inst, QOF_EVENT_ADD, nullptr); @@ -1877,7 +1877,7 @@ gnc_commodity_table_remove(gnc_commodity_table * table, if (!nsp) return; nsp->cm_list = g_list_remove(nsp->cm_list, comm); - g_hash_table_remove (nsp->cm_table, priv->mnemonic); + nsp->cm_table.erase (priv->mnemonic); /* XXX minor mem leak, should remove the key as well */ } @@ -1914,21 +1914,6 @@ hash_keys_helper (const char* key, gnc_commodity* value, std::vectorpush_back (key); } -static void -hash_values_helper(gpointer key, gpointer value, gpointer data) -{ - auto l = (GList**)data; - *l = g_list_prepend(*l, value); -} - -static GList * -g_hash_table_values(GHashTable * table) -{ - GList * l = nullptr; - g_hash_table_foreach(table, &hash_values_helper, (gpointer) &l); - return l; -} - /******************************************************************** * gnc_commodity_table_get_namespaces * see if any commodities in the namespace exist @@ -2000,10 +1985,8 @@ commodity_table_get_all_noncurrency_commodities(const gnc_commodity_table* table ns = gnc_commodity_table_find_namespace(table, name_space.c_str()); if (!ns) continue; - auto val = g_hash_table_values(ns->cm_table); - for (auto n = val; n; n = n->next) - retval.push_back (GNC_COMMODITY(n->data)); - g_list_free (val); + std::for_each (ns->cm_table.begin(), ns->cm_table.end(), + [&retval](auto it){ retval.push_back (it.second); }); } return retval; } @@ -2022,10 +2005,8 @@ gnc_commodity_table_get_commodities(const gnc_commodity_table * table, if (!ns) return retval; - auto val = g_hash_table_values(ns->cm_table); - for (auto n = val; n; n = n->next) - retval.push_back (GNC_COMMODITY(n->data)); - g_list_free (val); + std::for_each (ns->cm_table.begin(), ns->cm_table.end(), + [&retval](auto it){ retval.push_back (it.second); }); return retval; } @@ -2087,7 +2068,9 @@ gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table) ns = gnc_commodity_table_find_namespace(table, name_space); if (ns) { - g_hash_table_foreach(ns->cm_table, get_quotables_helper1, &rv); + std::for_each (ns->cm_table.begin(), ns->cm_table.end(), + [&rv](auto it) + { get_quotables_helper1 (nullptr, it.second, &rv); }); } } } @@ -2138,7 +2121,7 @@ gnc_commodity_table_add_namespace(gnc_commodity_table * table, if (!ns) { ns = static_cast(g_object_new(GNC_TYPE_COMMODITY_NAMESPACE, nullptr)); - ns->cm_table = g_hash_table_new(g_str_hash, g_str_equal); + new (&ns->cm_table) StrCommodityMap (); ns->name = CACHE_INSERT(static_cast(name_space)); ns->iso4217 = gnc_commodity_namespace_is_iso(name_space); qof_instance_init_data (&ns->inst, GNC_ID_COMMODITY_NAMESPACE, book); @@ -2180,15 +2163,6 @@ gnc_commodity_find_commodity_by_guid(const GncGUID *guid, QofBook *book) * delete a namespace ********************************************************************/ -static int -ns_helper(gpointer key, gpointer value, gpointer user_data) -{ - auto c = GNC_COMMODITY(value); - gnc_commodity_destroy(c); - CACHE_REMOVE(static_cast(key)); /* key is commodity mnemonic */ - return TRUE; -} - void gnc_commodity_table_delete_namespace(gnc_commodity_table * table, const char * name_space) @@ -2208,8 +2182,9 @@ gnc_commodity_table_delete_namespace(gnc_commodity_table * table, g_list_free(ns->cm_list); ns->cm_list = nullptr; - g_hash_table_foreach_remove(ns->cm_table, ns_helper, nullptr); - g_hash_table_destroy(ns->cm_table); + std::for_each (ns->cm_table.begin(), ns->cm_table.end(), + [](auto it){ gnc_commodity_destroy (it.second); }); + ns->cm_table.~StrCommodityMap (); CACHE_REMOVE(ns->name); qof_event_gen (&ns->inst, QOF_EVENT_DESTROY, nullptr); @@ -2245,8 +2220,9 @@ iter_commodity (gpointer key, gpointer value, gpointer user_data) static void iter_namespace (gpointer key, gpointer value, gpointer user_data) { - GHashTable *namespace_hash = ((gnc_commodity_namespace *) value)->cm_table; - g_hash_table_foreach (namespace_hash, iter_commodity, user_data); + auto namespace_hash = ((gnc_commodity_namespace *) value)->cm_table; + std::for_each (namespace_hash.begin(), namespace_hash.end(), + [user_data](auto it){ iter_commodity (nullptr, it.second, user_data); }); } gboolean From c514003d2c27d9264d508b1ec307807f75b0ccc5 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Wed, 1 May 2024 08:31:53 +0800 Subject: [PATCH 5/6] gnc_commodity_table->ns_table is an unordered_map --- libgnucash/engine/gnc-commodity.cpp | 41 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp index 79081e9a4e..824b93677a 100644 --- a/libgnucash/engine/gnc-commodity.cpp +++ b/libgnucash/engine/gnc-commodity.cpp @@ -108,6 +108,7 @@ static void commodity_free(gnc_commodity * cm); static void gnc_commodity_set_default_symbol(gnc_commodity *, const char *); using StrCommodityMap = std::unordered_map; +using StrCommodityNSMap = std::unordered_map; struct gnc_commodity_namespace_s { @@ -126,7 +127,7 @@ struct _GncCommodityNamespaceClass struct gnc_commodity_table_s { - GHashTable * ns_table; + StrCommodityNSMap ns_table; GList * ns_list; }; @@ -1616,7 +1617,7 @@ gnc_commodity_table * gnc_commodity_table_new(void) { gnc_commodity_table * retval = g_new0(gnc_commodity_table, 1); - retval->ns_table = g_hash_table_new(&g_str_hash, &g_str_equal); + new (&retval->ns_table) StrCommodityNSMap (); retval->ns_list = nullptr; return retval; } @@ -1659,12 +1660,12 @@ gnc_commodity_obtain_twin (const gnc_commodity *from, QofBook *book) ********************************************************************/ static void -count_coms(gpointer key, gpointer value, gpointer user_data) +count_coms(const std::string key, gpointer value, gpointer user_data) { auto tbl = ((gnc_commodity_namespace*)value)->cm_table; guint *count = (guint*)user_data; - if (g_strcmp0((char*)key, GNC_COMMODITY_NS_CURRENCY) == 0) + if (key == GNC_COMMODITY_NS_CURRENCY) { /* don't count default commodities */ return; @@ -1680,9 +1681,9 @@ gnc_commodity_table_get_size(const gnc_commodity_table* tbl) { guint count = 0; g_return_val_if_fail(tbl, 0); - g_return_val_if_fail(tbl->ns_table, 0); - g_hash_table_foreach(tbl->ns_table, count_coms, (gpointer)&count); + std::for_each (tbl->ns_table.begin(), tbl->ns_table.end(), + [&count](auto it){ count_coms (it.first, it.second, &count); }); return count; } @@ -1908,12 +1909,6 @@ gnc_commodity_table_has_namespace(const gnc_commodity_table * table, } } -static void -hash_keys_helper (const char* key, gnc_commodity* value, std::vector *l) -{ - l->push_back (key); -} - /******************************************************************** * gnc_commodity_table_get_namespaces * see if any commodities in the namespace exist @@ -1926,7 +1921,8 @@ gnc_commodity_table_get_namespaces(const gnc_commodity_table * table) if (!table) return rv; - g_hash_table_foreach(table->ns_table, (GHFunc)hash_keys_helper, &rv); + std::for_each (table->ns_table.begin(), table->ns_table.end(), + [&rv](auto it){ rv.push_back (it.first); }); return rv; } @@ -2127,9 +2123,7 @@ gnc_commodity_table_add_namespace(gnc_commodity_table * table, qof_instance_init_data (&ns->inst, GNC_ID_COMMODITY_NAMESPACE, book); qof_event_gen (&ns->inst, QOF_EVENT_CREATE, nullptr); - g_hash_table_insert(table->ns_table, - (gpointer) ns->name, - (gpointer) ns); + table->ns_table[ns->name] = ns; table->ns_list = g_list_append(table->ns_list, ns); qof_event_gen (&ns->inst, QOF_EVENT_ADD, nullptr); } @@ -2145,7 +2139,12 @@ gnc_commodity_table_find_namespace(const gnc_commodity_table * table, return nullptr; name_space = gnc_commodity_table_map_namespace(name_space); - return static_cast(g_hash_table_lookup(table->ns_table, (gpointer)name_space)); + + auto it = table->ns_table.find(name_space); + if (it == table->ns_table.end()) + return nullptr; + else + return it->second; } @@ -2176,7 +2175,7 @@ gnc_commodity_table_delete_namespace(gnc_commodity_table * table, return; qof_event_gen (&ns->inst, QOF_EVENT_REMOVE, nullptr); - g_hash_table_remove(table->ns_table, name_space); + table->ns_table.erase (name_space); table->ns_list = g_list_remove(table->ns_list, ns); g_list_free(ns->cm_list); @@ -2238,7 +2237,8 @@ gnc_commodity_table_foreach_commodity (const gnc_commodity_table * tbl, iter_data.func = f; iter_data.user_data = user_data; - g_hash_table_foreach(tbl->ns_table, iter_namespace, (gpointer)&iter_data); + std::for_each (tbl->ns_table.begin(), tbl->ns_table.end(), + [&iter_data](auto it){ iter_namespace (nullptr, it.second, &iter_data); }); return iter_data.ok; } @@ -2266,8 +2266,7 @@ gnc_commodity_table_destroy(gnc_commodity_table * t) g_list_free(t->ns_list); t->ns_list = nullptr; - g_hash_table_destroy(t->ns_table); - t->ns_table = nullptr; + t->ns_table.~StrCommodityNSMap(); LEAVE ("table=%p", t); g_free(t); } From f1d145f8c0a18e9112630b842cfdeb3d06e7fa21 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Fri, 7 Jun 2024 23:09:41 +0800 Subject: [PATCH 6/6] fake fix for tests --- bindings/python/gnucash_core.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bindings/python/gnucash_core.py b/bindings/python/gnucash_core.py index 993ad8919b..27ee2897d5 100644 --- a/bindings/python/gnucash_core.py +++ b/bindings/python/gnucash_core.py @@ -791,6 +791,14 @@ class GncCommodityTable(GnuCashCoreClass): which includes most of the world's currencies. """ + def get_quotable_commodities (self): + print ("hello from get_quotable_commodities") + return + + def get_commodities(self): + print ("hello from get_commodities") + return + def _get_namespaces_py(self): return [ns.get_name() for ns in self.get_namespaces_list()]