[glib] datetime: Avoid excessive copies in add_full()
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] datetime: Avoid excessive copies in add_full()
- Date: Wed, 25 Aug 2010 22:06:45 +0000 (UTC)
commit 026375b395fcdc2336666546afd2f21e7ee8bc67
Author: Emmanuele Bassi <ebassi linux intel com>
Date: Wed Aug 25 23:00:31 2010 +0100
datetime: Avoid excessive copies in add_full()
The current implementation of g_date_time_add_full() creates multiple
GDateTime temporary objects and unrefs them immediately; even with the
slice allocator this could result in a performance bottleneck,
especially if the atomic integer operations fall back to slow paths.
We can isolate the components of the add_full() operation and create
internal modifiers that operate on an existing GDateTime; this brings
down the number of GDateTime copies created from six to one.
While at it, the test suite for add_full() should have more checks for
roll-over of months and days.
Signed-off-by: Emmanuele Bassi <ebassi linux intel com>
glib/gdatetime.c | 133 +++++++++++++++++++++++++++++++++--------------
glib/tests/gdatetime.c | 24 +++++---
2 files changed, 108 insertions(+), 49 deletions(-)
---
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index 9efd435..c7972b4 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -277,6 +277,24 @@ get_weekday_name_abbr (gint day)
return NULL;
}
+static inline gint
+date_to_julian (gint year,
+ gint month,
+ gint day)
+{
+ gint a = (14 - month) / 12;
+ gint y = year + 4800 - a;
+ gint m = month + (12 * a) - 3;
+
+ return day
+ + (((153 * m) + 2) / 5)
+ + (y * 365)
+ + (y / 4)
+ - (y / 100)
+ + (y / 400)
+ - 32045;
+}
+
static inline void
g_date_time_add_days_internal (GDateTime *datetime,
gint64 days)
@@ -315,6 +333,69 @@ g_date_time_add_usec (GDateTime *datetime,
datetime->usec = __usec % USEC_PER_DAY;
}
+/*< internal >
+ * g_date_time_add_dmy:
+ * @datetime: a #GDateTime
+ * @years: years to add, in the Gregorian calendar
+ * @months: months to add, in the Gregorian calendar
+ * @days: days to add, in the Gregorian calendar
+ *
+ * Updates @datetime by adding @years, @months and @days to it
+ *
+ * This function modifies the passed #GDateTime so public accessors
+ * should make always pass a copy
+ */
+static inline void
+g_date_time_add_dmy (GDateTime *datetime,
+ gint years,
+ gint months,
+ gint days)
+{
+ gint __year = g_date_time_get_year (datetime);
+ gint __month = g_date_time_get_month (datetime);
+ gint __day = g_date_time_get_day_of_month (datetime);
+ gint step, i;
+ const guint16 *max_days;
+
+ /* subtract one day for leap years */
+ if (GREGORIAN_LEAP (__year) && __month == 2)
+ {
+ if (__day == 29)
+ __day -= 1;
+ }
+
+ __year += years;
+
+ /* add months */
+ step = months > 0 ? 1 : -1;
+ for (i = 0; i < ABS (months); i++)
+ {
+ __month += step;
+
+ if (__month < 1)
+ {
+ __year -= 1;
+ __month = 12;
+ }
+ else if (__month > 12)
+ {
+ __year += 1;
+ __month = 1;
+ }
+ }
+
+ /* clamp the days */
+ max_days = days_in_months[GREGORIAN_LEAP (__year) ? 1 : 0];
+ if (max_days[__month] < __day)
+ __day = max_days[__month];
+
+ /* since the add_days_internal() uses the julian date we need to
+ * update it using the new year/month/day and then add the days
+ */
+ datetime->julian = date_to_julian (__year, __month, __day);
+ g_date_time_add_days_internal (datetime, days);
+}
+
#define ZONEINFO_DIR "zoneinfo"
#define TZ_MAGIC "TZif"
#define TZ_MAGIC_LEN (strlen (TZ_MAGIC))
@@ -970,31 +1051,21 @@ g_date_time_add_full (const GDateTime *datetime,
gint minutes,
gint seconds)
{
- GDateTime *tmp, *dt;
+ GDateTime *dt;
+ gint64 usecs;
g_return_val_if_fail (datetime != NULL, NULL);
- dt = g_date_time_add_years (datetime, years);
- tmp = dt;
-
- dt = g_date_time_add_months (tmp, months);
- g_date_time_unref (tmp);
- tmp = dt;
-
- dt = g_date_time_add_days (tmp, days);
- g_date_time_unref (tmp);
- tmp = dt;
-
- dt = g_date_time_add_hours (tmp, hours);
- g_date_time_unref (tmp);
- tmp = dt;
+ dt = g_date_time_copy (datetime);
- dt = g_date_time_add_minutes (tmp, minutes);
- g_date_time_unref (tmp);
- tmp = dt;
+ /* add date */
+ g_date_time_add_dmy (dt, years, months, days);
- dt = g_date_time_add_seconds (tmp, seconds);
- g_date_time_unref (tmp);
+ /* add time */
+ usecs = (hours * USEC_PER_HOUR)
+ + (minutes * USEC_PER_MINUTE)
+ + (seconds * USEC_PER_SECOND);
+ g_date_time_add_usec (dt, usecs);
return dt;
}
@@ -1144,8 +1215,8 @@ g_date_time_equal (gconstpointer dt1,
a = dt1;
b = dt2;
- a_utc = g_date_time_to_utc ((GDateTime *) a);
- b_utc = g_date_time_to_utc ((GDateTime *) b);
+ a_utc = g_date_time_to_utc (a);
+ b_utc = g_date_time_to_utc (b);
a_epoch = g_date_time_to_epoch (a_utc);
b_epoch = g_date_time_to_epoch (b_utc);
@@ -1573,24 +1644,6 @@ g_date_time_is_daylight_savings (const GDateTime *datetime)
return datetime->tz->is_dst;
}
-static inline gint
-date_to_julian (gint year,
- gint month,
- gint day)
-{
- gint a = (14 - month) / 12;
- gint y = year + 4800 - a;
- gint m = month + (12 * a) - 3;
-
- return day
- + (((153 * m) + 2) / 5)
- + (y * 365)
- + (y / 4)
- - (y / 100)
- + (y / 400)
- - 32045;
-}
-
/**
* g_date_time_new_from_date:
* @year: the Gregorian year
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index d204714..b651b5b 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -543,15 +543,21 @@ test_GDateTime_add_full (void)
g_date_time_unref (dt2); \
} G_STMT_END
- TEST_ADD_FULL (2009, 10, 21, 0, 0, 0,
- 1, 1, 1, 1, 1, 1,
- 2010, 11, 22, 1, 1, 1);
- TEST_ADD_FULL (2000, 1, 1, 1, 1, 1,
- 0, 1, 0, 0, 0, 0,
- 2000, 2, 1, 1, 1, 1);
- TEST_ADD_FULL (2000, 1, 1, 0, 0, 0,
- -1, 1, 0, 0, 0, 0,
- 1999, 2, 1, 0, 0, 0);
+ TEST_ADD_FULL (2009, 10, 21, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 2010, 11, 22, 1, 1, 1);
+ TEST_ADD_FULL (2000, 1, 1, 1, 1, 1,
+ 0, 1, 0, 0, 0, 0,
+ 2000, 2, 1, 1, 1, 1);
+ TEST_ADD_FULL (2000, 1, 1, 0, 0, 0,
+ -1, 1, 0, 0, 0, 0,
+ 1999, 2, 1, 0, 0, 0);
+ TEST_ADD_FULL (2010, 10, 31, 0, 0, 0,
+ 0, 4, 0, 0, 0, 0,
+ 2011, 2, 28, 0, 0, 0);
+ TEST_ADD_FULL (2010, 8, 25, 22, 45, 0,
+ 0, 1, 6, 1, 25, 0,
+ 2010, 10, 2, 0, 10, 0);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]