mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Improve performance of price editor dialog.
Add new functions to get the number of prices and the get a price by index for a given commodity. Use these instead of building a list of all prices several times for each price.
This commit is contained in:
parent
601abdf47d
commit
ed776a73f0
@ -1407,11 +1407,21 @@ gnc_pricedb_remove_old_prices(GNCPriceDB *db,
|
||||
/* ==================================================================== */
|
||||
/* lookup/query functions */
|
||||
|
||||
static PriceList *pricedb_price_list_merge (PriceList *a, PriceList *b);
|
||||
|
||||
static void
|
||||
hash_values_helper(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
GList ** l = data;
|
||||
*l = g_list_concat(*l, g_list_copy (value));
|
||||
if (*l)
|
||||
{
|
||||
GList *new_l;
|
||||
new_l = pricedb_price_list_merge(*l, value);
|
||||
g_list_free (*l);
|
||||
*l = new_l;
|
||||
}
|
||||
else
|
||||
*l = g_list_copy (value);
|
||||
}
|
||||
|
||||
static PriceList *
|
||||
@ -1511,10 +1521,7 @@ pricedb_get_prices_internal(GNCPriceDB *db, const gnc_commodity *commodity,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (forward_list && !currency)
|
||||
/* Multiple currencies, reverse_list doesn't exist and
|
||||
forward_list must be sorted */
|
||||
forward_list = g_list_sort (forward_list, compare_prices_by_date);
|
||||
|
||||
return forward_list;
|
||||
}
|
||||
|
||||
@ -1933,7 +1940,124 @@ gnc_pricedb_get_prices(GNCPriceDB *db,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return the number of prices in the data base for the given commodity
|
||||
*/
|
||||
static void
|
||||
price_count_helper(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
int *result = data;
|
||||
GList *price_list = value;
|
||||
|
||||
*result += g_list_length(price_list);
|
||||
}
|
||||
|
||||
int
|
||||
gnc_pricedb_num_prices(GNCPriceDB *db,
|
||||
const gnc_commodity *c)
|
||||
{
|
||||
int result = 0;
|
||||
GHashTable *currency_hash;
|
||||
|
||||
if (!db || !c) return 0;
|
||||
ENTER ("db=%p commodity=%p", db, c);
|
||||
|
||||
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
|
||||
if (currency_hash)
|
||||
{
|
||||
g_hash_table_foreach(currency_hash, price_count_helper, (gpointer)&result);
|
||||
}
|
||||
|
||||
LEAVE ("count=%d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return the nth price for the given commodity
|
||||
*/
|
||||
GNCPrice *
|
||||
gnc_pricedb_nth_price (GNCPriceDB *db,
|
||||
const gnc_commodity *c,
|
||||
const int n)
|
||||
{
|
||||
GNCPrice *result = NULL;
|
||||
GHashTable *currency_hash;
|
||||
|
||||
if (!db || !c || n < 0) return NULL;
|
||||
ENTER ("db=%p commodity=%p index=%d", db, c, n);
|
||||
|
||||
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
|
||||
if (currency_hash)
|
||||
{
|
||||
int num_currencies = g_hash_table_size(currency_hash);
|
||||
if (num_currencies == 1)
|
||||
{
|
||||
/* Optimize the case of prices in only one currency, it's common
|
||||
and much faster */
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
g_hash_table_iter_init(&iter, currency_hash);
|
||||
if (g_hash_table_iter_next(&iter, &key, &value))
|
||||
{
|
||||
PriceList *prices = value;
|
||||
result = g_list_nth_data(prices, n);
|
||||
}
|
||||
}
|
||||
else if (num_currencies > 1)
|
||||
{
|
||||
/* Prices for multiple currencies, must find the nth entry in the
|
||||
merged currency list. */
|
||||
GList **price_array = (GList **)g_new(gpointer, num_currencies);
|
||||
GList **next_list;
|
||||
int i, j;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
/* Build an array of all the currencies this commodity has prices for */
|
||||
for (i = 0, g_hash_table_iter_init(&iter, currency_hash);
|
||||
g_hash_table_iter_next(&iter, &key, &value) && i < num_currencies;
|
||||
i++)
|
||||
{
|
||||
price_array[i] = value;
|
||||
}
|
||||
|
||||
/* Iterate n times to get the nth price, each time finding the currency
|
||||
with the latest price */
|
||||
for (i = 0; i <= n; i++)
|
||||
{
|
||||
next_list = NULL;
|
||||
for (j = 0; j < num_currencies; j++)
|
||||
{
|
||||
/* Save this entry if it's the first one or later than
|
||||
the saved one. */
|
||||
if (price_array[j] != NULL &&
|
||||
(next_list == NULL || *next_list == NULL ||
|
||||
compare_prices_by_date((*next_list)->data, (price_array[j])->data) > 0))
|
||||
{
|
||||
next_list = &price_array[j];
|
||||
}
|
||||
}
|
||||
/* next_list points to the list with the latest price unless all
|
||||
the lists are empty */
|
||||
if (next_list && *next_list)
|
||||
{
|
||||
result = (*next_list)->data;
|
||||
*next_list = (*next_list)->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* all the lists are empty, "n" is greater than the number
|
||||
of prices for this commodity. */
|
||||
result = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_free(price_array);
|
||||
}
|
||||
}
|
||||
|
||||
LEAVE ("price=%p", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
GNCPrice *
|
||||
gnc_pricedb_lookup_day(GNCPriceDB *db,
|
||||
const gnc_commodity *c,
|
||||
|
@ -587,6 +587,27 @@ gboolean gnc_pricedb_foreach_price(GNCPriceDB *db,
|
||||
gpointer user_data,
|
||||
gboolean stable_order);
|
||||
|
||||
/** @brief Get the number of prices, in any currency, for a given commodity.
|
||||
* @param db The pricedb
|
||||
* @param c The commodity
|
||||
* @return The number of prices in the database for this commody, zero if none
|
||||
*/
|
||||
int
|
||||
gnc_pricedb_num_prices(GNCPriceDB *db,
|
||||
const gnc_commodity *c);
|
||||
|
||||
/** @brief Get the nth price for the given commodity in reverse date order
|
||||
* @param db The pricedb
|
||||
* @param c The commodity whose nth price is needed
|
||||
* @param n Zero based index of the price wanted
|
||||
* @return The nth price for this commodity in reverse chronological order, without
|
||||
* regard for what currency the price is in
|
||||
*/
|
||||
GNCPrice *
|
||||
gnc_pricedb_nth_price (GNCPriceDB *db,
|
||||
const gnc_commodity *c,
|
||||
const int n);
|
||||
|
||||
/* The following two convenience functions are used to test the xml backend */
|
||||
/** @brief Return the number of prices in the database.
|
||||
*
|
||||
|
@ -594,10 +594,8 @@ gnc_tree_model_price_get_iter (GtkTreeModel *tree_model,
|
||||
}
|
||||
|
||||
/* Verify the third part of the path: the price. */
|
||||
price_list = gnc_pricedb_get_prices(priv->price_db, commodity, NULL);
|
||||
i = gtk_tree_path_get_indices (path)[2];
|
||||
price = g_list_nth_data (price_list, i);
|
||||
gnc_price_list_destroy(price_list);
|
||||
price = gnc_pricedb_nth_price(priv->price_db, commodity, i);
|
||||
/* There's a race condition here that I can't resolve.
|
||||
* Comment this check out for now, and we'll handle the
|
||||
* resulting problem elsewhere. */
|
||||
@ -860,9 +858,7 @@ gnc_tree_model_price_iter_next (GtkTreeModel *tree_model,
|
||||
{
|
||||
commodity = gnc_price_get_commodity((GNCPrice*)iter->user_data2);
|
||||
n = GPOINTER_TO_INT(iter->user_data3) + 1;
|
||||
list = gnc_pricedb_get_prices(priv->price_db, commodity, NULL);
|
||||
iter->user_data2 = g_list_nth_data(list, n);
|
||||
gnc_price_list_destroy(list);
|
||||
iter->user_data2 = gnc_pricedb_nth_price(priv->price_db, commodity, n);
|
||||
if (iter->user_data2 == NULL)
|
||||
{
|
||||
LEAVE("no next iter");
|
||||
@ -936,18 +932,18 @@ gnc_tree_model_price_iter_children (GtkTreeModel *tree_model,
|
||||
|
||||
if (parent->user_data == ITER_IS_COMMODITY)
|
||||
{
|
||||
GNCPrice *price;
|
||||
commodity = (gnc_commodity *)parent->user_data2;
|
||||
list = gnc_pricedb_get_prices(priv->price_db, commodity, NULL);
|
||||
if (list == NULL)
|
||||
price = gnc_pricedb_nth_price(priv->price_db, commodity, 0);
|
||||
if (price == NULL)
|
||||
{
|
||||
LEAVE("no prices");
|
||||
return FALSE;
|
||||
}
|
||||
iter->stamp = model->stamp;
|
||||
iter->user_data = ITER_IS_PRICE;
|
||||
iter->user_data2 = g_list_nth_data(list, 0);
|
||||
iter->user_data2 = price;
|
||||
iter->user_data3 = GINT_TO_POINTER(0);
|
||||
gnc_price_list_destroy(list);
|
||||
LEAVE("price iter %p (%s)", iter, iter_to_string(model, iter));
|
||||
return TRUE;
|
||||
}
|
||||
@ -1038,9 +1034,7 @@ gnc_tree_model_price_iter_n_children (GtkTreeModel *tree_model,
|
||||
if (iter->user_data == ITER_IS_COMMODITY)
|
||||
{
|
||||
commodity = (gnc_commodity *)iter->user_data2;
|
||||
list = gnc_pricedb_get_prices(priv->price_db, commodity, NULL);
|
||||
n = g_list_length(list);
|
||||
gnc_price_list_destroy(list);
|
||||
n = gnc_pricedb_num_prices(priv->price_db, commodity);
|
||||
LEAVE("price list length %d", n);
|
||||
return n;
|
||||
}
|
||||
@ -1099,13 +1093,11 @@ gnc_tree_model_price_iter_nth_child (GtkTreeModel *tree_model,
|
||||
if (parent->user_data == ITER_IS_COMMODITY)
|
||||
{
|
||||
commodity = (gnc_commodity *)parent->user_data2;
|
||||
list = gnc_pricedb_get_prices(priv->price_db, commodity, NULL);
|
||||
|
||||
iter->stamp = model->stamp;
|
||||
iter->user_data = ITER_IS_PRICE;
|
||||
iter->user_data2 = g_list_nth_data(list, n);
|
||||
iter->user_data2 = gnc_pricedb_nth_price(priv->price_db, commodity, n);
|
||||
iter->user_data3 = GINT_TO_POINTER(n);
|
||||
gnc_price_list_destroy(list);
|
||||
LEAVE("price iter %p (%s)", iter, iter_to_string(model, iter));
|
||||
return iter->user_data2 != NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user