diff options
author | Paul Ganssle <pganssle@users.noreply.github.com> | 2018-01-16 18:06:31 (GMT) |
---|---|---|
committer | Alexander Belopolsky <abalkin@users.noreply.github.com> | 2018-01-16 18:06:31 (GMT) |
commit | 9f1b7b93f5f0ef589e7b272e127cacf4ce5d23f1 (patch) | |
tree | 60cf60454cad0f99056713510c1c91744d7e7ff8 /Modules | |
parent | 6b5a27975a415108a5eac12ee302bf2b3233f4d4 (diff) | |
download | cpython-9f1b7b93f5f0ef589e7b272e127cacf4ce5d23f1.zip cpython-9f1b7b93f5f0ef589e7b272e127cacf4ce5d23f1.tar.gz cpython-9f1b7b93f5f0ef589e7b272e127cacf4ce5d23f1.tar.bz2 |
bpo-32403: Faster date and datetime constructors (#4993)
* Add tests for date subclass alternate constructors
* Switch over alternate date constructors to fast path
* Switch datetime constructors to fastpath, fix bpo-32404
* Add fast path for datetime in date subclass constructor
* Set fold in constructor in datetime.combine
* Add news entries.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_datetimemodule.c | 120 |
1 files changed, 75 insertions, 45 deletions
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index e68c7c0..d1f48e5 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -847,6 +847,27 @@ new_date_ex(int year, int month, int day, PyTypeObject *type) #define new_date(year, month, day) \ new_date_ex(year, month, day, &PyDateTime_DateType) +// Forward declaration +static PyObject * new_datetime_ex(int, int, int, int, int, int, int, + PyObject*, PyTypeObject*); + +/* Create date instance with no range checking, or call subclass constructor */ +static PyObject * +new_date_subclass_ex(int year, int month, int day, PyObject *cls) { + PyObject *result; + // We have "fast path" constructors for two subclasses: date and datetime + if ((PyTypeObject *)cls == &PyDateTime_DateType) { + result = new_date_ex(year, month, day, (PyTypeObject *)cls); + } else if ((PyTypeObject *)cls == &PyDateTime_DateTimeType) { + result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None, + (PyTypeObject *)cls); + } else { + result = PyObject_CallFunction(cls, "iii", year, month, day); + } + + return result; +} + /* Create a datetime instance with no range checking. */ static PyObject * new_datetime_ex2(int year, int month, int day, int hour, int minute, @@ -894,6 +915,40 @@ new_datetime_ex(int year, int month, int day, int hour, int minute, new_datetime_ex2(y, m, d, hh, mm, ss, us, tzinfo, fold, \ &PyDateTime_DateTimeType) +static PyObject * +new_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute, + int second, int usecond, PyObject *tzinfo, + int fold, PyObject *cls) { + PyObject* dt; + if ((PyTypeObject*)cls == &PyDateTime_DateTimeType) { + // Use the fast path constructor + dt = new_datetime(year, month, day, hour, minute, second, usecond, + tzinfo, fold); + } else { + // Subclass + dt = PyObject_CallFunction(cls, "iiiiiiiO", + year, + month, + day, + hour, + minute, + second, + usecond, + tzinfo); + } + + return dt; +} + +static PyObject * +new_datetime_subclass_ex(int year, int month, int day, int hour, int minute, + int second, int usecond, PyObject *tzinfo, + PyObject *cls) { + return new_datetime_subclass_fold_ex(year, month, day, hour, minute, + second, usecond, tzinfo, 0, + cls); +} + /* Create a time instance with no range checking. */ static PyObject * new_time_ex2(int hour, int minute, int second, int usecond, @@ -2743,10 +2798,10 @@ date_local_from_object(PyObject *cls, PyObject *obj) if (_PyTime_localtime(t, &tm) != 0) return NULL; - return PyObject_CallFunction(cls, "iii", - tm.tm_year + 1900, - tm.tm_mon + 1, - tm.tm_mday); + return new_date_subclass_ex(tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + cls); } /* Return new date from current time. @@ -2809,8 +2864,7 @@ date_fromordinal(PyObject *cls, PyObject *args) ">= 1"); else { ord_to_ymd(ordinal, &year, &month, &day); - result = PyObject_CallFunction(cls, "iii", - year, month, day); + result = new_date_subclass_ex(year, month, day, cls); } } return result; @@ -2845,14 +2899,7 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) { return NULL; } - PyObject *result; - if ( (PyTypeObject*)cls == &PyDateTime_DateType ) { - result = new_date_ex(year, month, day, (PyTypeObject*)cls); - } else { - result = PyObject_CallFunction(cls, "iii", year, month, day); - } - - return result; + return new_date_subclass_ex(year, month, day, cls); } @@ -4596,9 +4643,8 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, fold = 1; } } - return new_datetime_ex2(year, month, day, hour, - minute, second, us, tzinfo, fold, - (PyTypeObject *)cls); + return new_datetime_subclass_fold_ex(year, month, day, hour, minute, + second, us, tzinfo, fold, cls); } /* Internal helper. @@ -4764,17 +4810,16 @@ datetime_combine(PyObject *cls, PyObject *args, PyObject *kw) else tzinfo = Py_None; } - result = PyObject_CallFunction(cls, "iiiiiiiO", - GET_YEAR(date), - GET_MONTH(date), - GET_DAY(date), - TIME_GET_HOUR(time), - TIME_GET_MINUTE(time), - TIME_GET_SECOND(time), - TIME_GET_MICROSECOND(time), - tzinfo); - if (result) - DATE_SET_FOLD(result, TIME_GET_FOLD(time)); + result = new_datetime_subclass_fold_ex(GET_YEAR(date), + GET_MONTH(date), + GET_DAY(date), + TIME_GET_HOUR(time), + TIME_GET_MINUTE(time), + TIME_GET_SECOND(time), + TIME_GET_MICROSECOND(time), + tzinfo, + TIME_GET_FOLD(time), + cls); } return result; } @@ -4832,23 +4877,8 @@ datetime_fromisoformat(PyObject* cls, PyObject *dtstr) { return NULL; } - PyObject* dt; - if ( (PyTypeObject*)cls == &PyDateTime_DateTimeType ) { - // Use the fast path constructor - dt = new_datetime(year, month, day, hour, minute, second, microsecond, - tzinfo, 0); - } else { - // Subclass - dt = PyObject_CallFunction(cls, "iiiiiiiO", - year, - month, - day, - hour, - minute, - second, - microsecond, - tzinfo); - } + PyObject *dt = new_datetime_subclass_ex(year, month, day, hour, minute, + second, microsecond, tzinfo, cls); Py_DECREF(tzinfo); return dt; |