mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-21 16:38:54 +02:00
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>
This commit is contained in:
133
glib/gdatetime.c
133
glib/gdatetime.c
@@ -277,6 +277,24 @@ get_weekday_name_abbr (gint day)
|
|||||||
return NULL;
|
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
|
static inline void
|
||||||
g_date_time_add_days_internal (GDateTime *datetime,
|
g_date_time_add_days_internal (GDateTime *datetime,
|
||||||
gint64 days)
|
gint64 days)
|
||||||
@@ -315,6 +333,69 @@ g_date_time_add_usec (GDateTime *datetime,
|
|||||||
datetime->usec = __usec % USEC_PER_DAY;
|
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 ZONEINFO_DIR "zoneinfo"
|
||||||
#define TZ_MAGIC "TZif"
|
#define TZ_MAGIC "TZif"
|
||||||
#define TZ_MAGIC_LEN (strlen (TZ_MAGIC))
|
#define TZ_MAGIC_LEN (strlen (TZ_MAGIC))
|
||||||
@@ -970,31 +1051,21 @@ g_date_time_add_full (const GDateTime *datetime,
|
|||||||
gint minutes,
|
gint minutes,
|
||||||
gint seconds)
|
gint seconds)
|
||||||
{
|
{
|
||||||
GDateTime *tmp, *dt;
|
GDateTime *dt;
|
||||||
|
gint64 usecs;
|
||||||
|
|
||||||
g_return_val_if_fail (datetime != NULL, NULL);
|
g_return_val_if_fail (datetime != NULL, NULL);
|
||||||
|
|
||||||
dt = g_date_time_add_years (datetime, years);
|
dt = g_date_time_copy (datetime);
|
||||||
tmp = dt;
|
|
||||||
|
|
||||||
dt = g_date_time_add_months (tmp, months);
|
/* add date */
|
||||||
g_date_time_unref (tmp);
|
g_date_time_add_dmy (dt, years, months, days);
|
||||||
tmp = dt;
|
|
||||||
|
|
||||||
dt = g_date_time_add_days (tmp, days);
|
/* add time */
|
||||||
g_date_time_unref (tmp);
|
usecs = (hours * USEC_PER_HOUR)
|
||||||
tmp = dt;
|
+ (minutes * USEC_PER_MINUTE)
|
||||||
|
+ (seconds * USEC_PER_SECOND);
|
||||||
dt = g_date_time_add_hours (tmp, hours);
|
g_date_time_add_usec (dt, usecs);
|
||||||
g_date_time_unref (tmp);
|
|
||||||
tmp = dt;
|
|
||||||
|
|
||||||
dt = g_date_time_add_minutes (tmp, minutes);
|
|
||||||
g_date_time_unref (tmp);
|
|
||||||
tmp = dt;
|
|
||||||
|
|
||||||
dt = g_date_time_add_seconds (tmp, seconds);
|
|
||||||
g_date_time_unref (tmp);
|
|
||||||
|
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
@@ -1144,8 +1215,8 @@ g_date_time_equal (gconstpointer dt1,
|
|||||||
a = dt1;
|
a = dt1;
|
||||||
b = dt2;
|
b = dt2;
|
||||||
|
|
||||||
a_utc = g_date_time_to_utc ((GDateTime *) a);
|
a_utc = g_date_time_to_utc (a);
|
||||||
b_utc = g_date_time_to_utc ((GDateTime *) b);
|
b_utc = g_date_time_to_utc (b);
|
||||||
|
|
||||||
a_epoch = g_date_time_to_epoch (a_utc);
|
a_epoch = g_date_time_to_epoch (a_utc);
|
||||||
b_epoch = g_date_time_to_epoch (b_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;
|
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:
|
* g_date_time_new_from_date:
|
||||||
* @year: the Gregorian year
|
* @year: the Gregorian year
|
||||||
|
@@ -543,15 +543,21 @@ test_GDateTime_add_full (void)
|
|||||||
g_date_time_unref (dt2); \
|
g_date_time_unref (dt2); \
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
TEST_ADD_FULL (2009, 10, 21, 0, 0, 0,
|
TEST_ADD_FULL (2009, 10, 21, 0, 0, 0,
|
||||||
1, 1, 1, 1, 1, 1,
|
1, 1, 1, 1, 1, 1,
|
||||||
2010, 11, 22, 1, 1, 1);
|
2010, 11, 22, 1, 1, 1);
|
||||||
TEST_ADD_FULL (2000, 1, 1, 1, 1, 1,
|
TEST_ADD_FULL (2000, 1, 1, 1, 1, 1,
|
||||||
0, 1, 0, 0, 0, 0,
|
0, 1, 0, 0, 0, 0,
|
||||||
2000, 2, 1, 1, 1, 1);
|
2000, 2, 1, 1, 1, 1);
|
||||||
TEST_ADD_FULL (2000, 1, 1, 0, 0, 0,
|
TEST_ADD_FULL (2000, 1, 1, 0, 0, 0,
|
||||||
-1, 1, 0, 0, 0, 0,
|
-1, 1, 0, 0, 0, 0,
|
||||||
1999, 2, 1, 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
|
static void
|
||||||
|
Reference in New Issue
Block a user