diff options
-rw-r--r-- | numpy/core/src/multiarray/datetime_busday.c | 310 | ||||
-rw-r--r-- | numpy/core/src/multiarray/datetime_busday.h | 29 | ||||
-rw-r--r-- | numpy/core/src/multiarray/datetime_busdaydef.c | 322 | ||||
-rw-r--r-- | numpy/core/src/multiarray/datetime_busdaydef.h | 32 |
4 files changed, 347 insertions, 346 deletions
diff --git a/numpy/core/src/multiarray/datetime_busday.c b/numpy/core/src/multiarray/datetime_busday.c index 21647d1ea..08b307223 100644 --- a/numpy/core/src/multiarray/datetime_busday.c +++ b/numpy/core/src/multiarray/datetime_busday.c @@ -581,314 +581,6 @@ finish: return 1; } -NPY_NO_EXPORT int -PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask) -{ - PyObject *obj = weekmask_in; - - /* Make obj into an ASCII string if it is UNICODE */ - Py_INCREF(obj); - if (PyUnicode_Check(obj)) { - /* accept unicode input */ - PyObject *obj_str; - obj_str = PyUnicode_AsASCIIString(obj); - if (obj_str == NULL) { - Py_DECREF(obj); - return 0; - } - Py_DECREF(obj); - obj = obj_str; - } - - if (PyBytes_Check(obj)) { - char *str; - Py_ssize_t len; - - if (PyBytes_AsStringAndSize(obj, &str, &len) < 0) { - Py_DECREF(obj); - return 0; - } - - /* Length 7 is a string like "1111100" */ - if (len == 7) { - int i; - for (i = 0; i < 7; ++i) { - switch(str[i]) { - case '0': - weekmask[i] = 0; - break; - case '1': - weekmask[i] = 1; - break; - default: - goto invalid_weekmask_string; - } - } - - goto finish; - } - /* Length divisible by 3 is a string like "Mon" or "MonWedFri" */ - else if (len % 3 == 0) { - int i; - memset(weekmask, 0, 7); - for (i = 0; i < len; i += 3) { - switch (str[i]) { - case 'M': - if (str[i+1] == 'o' && str[i+2] == 'n') { - weekmask[0] = 1; - } - else { - goto invalid_weekmask_string; - } - break; - case 'T': - if (str[i+1] == 'u' && str[i+2] == 'e') { - weekmask[1] = 1; - } - else if (str[i+1] == 'h' && str[i+2] == 'u') { - weekmask[3] = 1; - } - else { - goto invalid_weekmask_string; - } - break; - case 'W': - if (str[i+1] == 'e' && str[i+2] == 'd') { - weekmask[2] = 1; - } - else { - goto invalid_weekmask_string; - } - break; - case 'F': - if (str[i+1] == 'r' && str[i+2] == 'i') { - weekmask[4] = 1; - } - else { - goto invalid_weekmask_string; - } - break; - case 'S': - if (str[i+1] == 'a' && str[i+2] == 't') { - weekmask[5] = 1; - } - else if (str[i+1] == 'u' && str[i+2] == 'n') { - weekmask[6] = 1; - } - else { - goto invalid_weekmask_string; - } - break; - } - } - - goto finish; - } - -invalid_weekmask_string: - PyErr_Format(PyExc_ValueError, - "Invalid business day weekmask string \"%s\"", - str); - Py_DECREF(obj); - return 0; - } - /* Something like [1,1,1,1,1,0,0] */ - else if (PySequence_Check(obj)) { - if (PySequence_Size(obj) != 7 || - (PyArray_Check(obj) && PyArray_NDIM(obj) != 1)) { - PyErr_SetString(PyExc_ValueError, - "A business day weekmask array must have length 7"); - Py_DECREF(obj); - return 0; - } - else { - int i; - PyObject *f; - - for (i = 0; i < 7; ++i) { - long val; - - f = PySequence_GetItem(obj, i); - if (f == NULL) { - Py_DECREF(obj); - return 0; - } - - val = PyInt_AsLong(f); - if (val == -1 && PyErr_Occurred()) { - Py_DECREF(obj); - return 0; - } - if (val == 0) { - weekmask[i] = 0; - } - else if (val == 1) { - weekmask[i] = 1; - } - else { - PyErr_SetString(PyExc_ValueError, - "A business day weekmask array must have all " - "1's and 0's"); - Py_DECREF(obj); - return 0; - } - } - - goto finish; - } - } - - PyErr_SetString(PyExc_ValueError, - "Couldn't convert object into a business day weekmask"); - Py_DECREF(obj); - return 0; - - -finish: - Py_DECREF(obj); - return 1; -} - -static int -qsort_datetime_compare(const void *elem1, const void *elem2) -{ - npy_datetime e1 = *(npy_datetime *)elem1; - npy_datetime e2 = *(npy_datetime *)elem2; - - return (e1 < e2) ? -1 : (e1 == e2) ? 0 : 1; -} - -/* - * Sorts the the array of dates provided in place and removes - * NaT, duplicates and any date which is already excluded on account - * of the weekmask. - * - * Returns the number of dates left after removing weekmask-excluded - * dates. - */ -NPY_NO_EXPORT void -normalize_holidays_list(npy_holidayslist *holidays, npy_bool *weekmask) -{ - npy_datetime *dates = holidays->begin; - npy_intp count = holidays->end - dates; - - npy_datetime lastdate = NPY_DATETIME_NAT; - npy_intp trimcount, i; - int day_of_week; - - /* Sort the dates */ - qsort(dates, count, sizeof(npy_datetime), &qsort_datetime_compare); - - /* Sweep throught the array, eliminating unnecessary values */ - trimcount = 0; - for (i = 0; i < count; ++i) { - npy_datetime date = dates[i]; - - /* Skip any NaT or duplicate */ - if (date != NPY_DATETIME_NAT && date != lastdate) { - /* Get the day of the week (1970-01-05 is Monday) */ - day_of_week = (int)((date - 4) % 7); - if (day_of_week < 0) { - day_of_week += 7; - } - - /* - * If the holiday falls on a possible business day, - * then keep it. - */ - if (weekmask[day_of_week] == 1) { - dates[trimcount++] = date; - lastdate = date; - } - } - } - - /* Adjust the end of the holidays array */ - holidays->end = dates + trimcount; -} - -/* - * Converts a Python input into a non-normalized list of holidays. - * - * IMPORTANT: This function can't do the normalization, because it doesn't - * know the weekmask. You must call 'normalize_holiday_list' - * on the result before using it. - */ -NPY_NO_EXPORT int -PyArray_HolidaysConverter(PyObject *dates_in, npy_holidayslist *holidays) -{ - PyArrayObject *dates = NULL; - PyArray_Descr *date_dtype = NULL; - npy_intp count; - - /* Make 'dates' into an array */ - if (PyArray_Check(dates_in)) { - dates = (PyArrayObject *)dates_in; - Py_INCREF(dates); - } - else { - PyArray_Descr *datetime_dtype; - - /* Use the datetime dtype with generic units so it fills it in */ - datetime_dtype = PyArray_DescrFromType(NPY_DATETIME); - if (datetime_dtype == NULL) { - goto fail; - } - - /* This steals the datetime_dtype reference */ - dates = (PyArrayObject *)PyArray_FromAny(dates_in, datetime_dtype, - 0, 0, 0, dates_in); - if (dates == NULL) { - goto fail; - } - } - - date_dtype = create_datetime_dtype_with_unit(NPY_DATETIME, NPY_FR_D); - if (date_dtype == NULL) { - goto fail; - } - - if (!PyArray_CanCastTypeTo(PyArray_DESCR(dates), - date_dtype, NPY_SAFE_CASTING)) { - PyErr_SetString(PyExc_ValueError, "Cannot safely convert " - "provided holidays input into an array of dates"); - goto fail; - } - if (PyArray_NDIM(dates) != 1) { - PyErr_SetString(PyExc_ValueError, "holidays must be a provided " - "as a one-dimensional array"); - goto fail; - } - - /* Allocate the memory for the dates */ - count = PyArray_DIM(dates, 0); - holidays->begin = PyArray_malloc(sizeof(npy_datetime) * count); - if (holidays->begin == NULL) { - PyErr_NoMemory(); - goto fail; - } - holidays->end = holidays->begin + count; - - /* Cast the data into a raw date array */ - if (PyArray_CastRawArrays(count, - PyArray_BYTES(dates), (char *)holidays->begin, - PyArray_STRIDE(dates, 0), sizeof(npy_datetime), - PyArray_DESCR(dates), date_dtype, - 0) != NPY_SUCCEED) { - goto fail; - } - - Py_DECREF(dates); - Py_DECREF(date_dtype); - - return 1; - -fail: - Py_XDECREF(dates); - Py_XDECREF(date_dtype); - return 0; -} - /* * This is the 'busday_offset' function exposed for calling * from Python. @@ -905,7 +597,7 @@ array_busday_offset(PyObject *NPY_UNUSED(self), PyArrayObject *dates = NULL, *offsets = NULL, *out = NULL, *ret; NPY_BUSDAY_ROLL roll = NPY_BUSDAY_RAISE; npy_bool weekmask[7] = {2, 1, 1, 1, 1, 0, 0}; - PyArray_BusinessDayDef *busdaydef = NULL; + NpyBusinessDayDef *busdaydef = NULL; int i, busdays_in_weekmask; npy_holidayslist holidays = {NULL, NULL}; int allocated_holidays = 1; diff --git a/numpy/core/src/multiarray/datetime_busday.h b/numpy/core/src/multiarray/datetime_busday.h index 8c0dc4482..f1cb68577 100644 --- a/numpy/core/src/multiarray/datetime_busday.h +++ b/numpy/core/src/multiarray/datetime_busday.h @@ -20,34 +20,5 @@ NPY_NO_EXPORT PyObject * array_busday_offset(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds); -/* - * Converts a Python input into a 7-element weekmask, where 0 means - * weekend and 1 means business day. - */ -NPY_NO_EXPORT int -PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask); - -/* - * Sorts the the array of dates provided in place and removes - * NaT, duplicates and any date which is already excluded on account - * of the weekmask. - * - * Returns the number of dates left after removing weekmask-excluded - * dates. - */ -NPY_NO_EXPORT void -normalize_holidays_list(npy_holidayslist *holidays, npy_bool *weekmask); - -/* - * Converts a Python input into a non-normalized list of holidays. - * - * IMPORTANT: This function can't do the normalization, because it doesn't - * know the weekmask. You must call 'normalize_holiday_list' - * on the result before using it. - */ -NPY_NO_EXPORT int -PyArray_HolidaysConverter(PyObject *dates_in, npy_holidayslist *holidays); - - #endif diff --git a/numpy/core/src/multiarray/datetime_busdaydef.c b/numpy/core/src/multiarray/datetime_busdaydef.c index 74b3eeef7..396bf82be 100644 --- a/numpy/core/src/multiarray/datetime_busdaydef.c +++ b/numpy/core/src/multiarray/datetime_busdaydef.c @@ -23,13 +23,321 @@ #include "datetime_busday.h" #include "datetime_busdaydef.h" +NPY_NO_EXPORT int +PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask) +{ + PyObject *obj = weekmask_in; + + /* Make obj into an ASCII string if it is UNICODE */ + Py_INCREF(obj); + if (PyUnicode_Check(obj)) { + /* accept unicode input */ + PyObject *obj_str; + obj_str = PyUnicode_AsASCIIString(obj); + if (obj_str == NULL) { + Py_DECREF(obj); + return 0; + } + Py_DECREF(obj); + obj = obj_str; + } + + if (PyBytes_Check(obj)) { + char *str; + Py_ssize_t len; + + if (PyBytes_AsStringAndSize(obj, &str, &len) < 0) { + Py_DECREF(obj); + return 0; + } + + /* Length 7 is a string like "1111100" */ + if (len == 7) { + int i; + for (i = 0; i < 7; ++i) { + switch(str[i]) { + case '0': + weekmask[i] = 0; + break; + case '1': + weekmask[i] = 1; + break; + default: + goto invalid_weekmask_string; + } + } + + goto finish; + } + /* Length divisible by 3 is a string like "Mon" or "MonWedFri" */ + else if (len % 3 == 0) { + int i; + memset(weekmask, 0, 7); + for (i = 0; i < len; i += 3) { + switch (str[i]) { + case 'M': + if (str[i+1] == 'o' && str[i+2] == 'n') { + weekmask[0] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + case 'T': + if (str[i+1] == 'u' && str[i+2] == 'e') { + weekmask[1] = 1; + } + else if (str[i+1] == 'h' && str[i+2] == 'u') { + weekmask[3] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + case 'W': + if (str[i+1] == 'e' && str[i+2] == 'd') { + weekmask[2] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + case 'F': + if (str[i+1] == 'r' && str[i+2] == 'i') { + weekmask[4] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + case 'S': + if (str[i+1] == 'a' && str[i+2] == 't') { + weekmask[5] = 1; + } + else if (str[i+1] == 'u' && str[i+2] == 'n') { + weekmask[6] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + } + } + + goto finish; + } + +invalid_weekmask_string: + PyErr_Format(PyExc_ValueError, + "Invalid business day weekmask string \"%s\"", + str); + Py_DECREF(obj); + return 0; + } + /* Something like [1,1,1,1,1,0,0] */ + else if (PySequence_Check(obj)) { + if (PySequence_Size(obj) != 7 || + (PyArray_Check(obj) && PyArray_NDIM(obj) != 1)) { + PyErr_SetString(PyExc_ValueError, + "A business day weekmask array must have length 7"); + Py_DECREF(obj); + return 0; + } + else { + int i; + PyObject *f; + + for (i = 0; i < 7; ++i) { + long val; + + f = PySequence_GetItem(obj, i); + if (f == NULL) { + Py_DECREF(obj); + return 0; + } + + val = PyInt_AsLong(f); + if (val == -1 && PyErr_Occurred()) { + Py_DECREF(obj); + return 0; + } + if (val == 0) { + weekmask[i] = 0; + } + else if (val == 1) { + weekmask[i] = 1; + } + else { + PyErr_SetString(PyExc_ValueError, + "A business day weekmask array must have all " + "1's and 0's"); + Py_DECREF(obj); + return 0; + } + } + + goto finish; + } + } + + PyErr_SetString(PyExc_ValueError, + "Couldn't convert object into a business day weekmask"); + Py_DECREF(obj); + return 0; + + +finish: + Py_DECREF(obj); + return 1; +} + +static int +qsort_datetime_compare(const void *elem1, const void *elem2) +{ + npy_datetime e1 = *(npy_datetime *)elem1; + npy_datetime e2 = *(npy_datetime *)elem2; + + return (e1 < e2) ? -1 : (e1 == e2) ? 0 : 1; +} + +/* + * Sorts the the array of dates provided in place and removes + * NaT, duplicates and any date which is already excluded on account + * of the weekmask. + * + * Returns the number of dates left after removing weekmask-excluded + * dates. + */ +NPY_NO_EXPORT void +normalize_holidays_list(npy_holidayslist *holidays, npy_bool *weekmask) +{ + npy_datetime *dates = holidays->begin; + npy_intp count = holidays->end - dates; + + npy_datetime lastdate = NPY_DATETIME_NAT; + npy_intp trimcount, i; + int day_of_week; + + /* Sort the dates */ + qsort(dates, count, sizeof(npy_datetime), &qsort_datetime_compare); + + /* Sweep throught the array, eliminating unnecessary values */ + trimcount = 0; + for (i = 0; i < count; ++i) { + npy_datetime date = dates[i]; + + /* Skip any NaT or duplicate */ + if (date != NPY_DATETIME_NAT && date != lastdate) { + /* Get the day of the week (1970-01-05 is Monday) */ + day_of_week = (int)((date - 4) % 7); + if (day_of_week < 0) { + day_of_week += 7; + } + + /* + * If the holiday falls on a possible business day, + * then keep it. + */ + if (weekmask[day_of_week] == 1) { + dates[trimcount++] = date; + lastdate = date; + } + } + } + + /* Adjust the end of the holidays array */ + holidays->end = dates + trimcount; +} + +/* + * Converts a Python input into a non-normalized list of holidays. + * + * IMPORTANT: This function can't do the normalization, because it doesn't + * know the weekmask. You must call 'normalize_holiday_list' + * on the result before using it. + */ +NPY_NO_EXPORT int +PyArray_HolidaysConverter(PyObject *dates_in, npy_holidayslist *holidays) +{ + PyArrayObject *dates = NULL; + PyArray_Descr *date_dtype = NULL; + npy_intp count; + + /* Make 'dates' into an array */ + if (PyArray_Check(dates_in)) { + dates = (PyArrayObject *)dates_in; + Py_INCREF(dates); + } + else { + PyArray_Descr *datetime_dtype; + + /* Use the datetime dtype with generic units so it fills it in */ + datetime_dtype = PyArray_DescrFromType(NPY_DATETIME); + if (datetime_dtype == NULL) { + goto fail; + } + + /* This steals the datetime_dtype reference */ + dates = (PyArrayObject *)PyArray_FromAny(dates_in, datetime_dtype, + 0, 0, 0, dates_in); + if (dates == NULL) { + goto fail; + } + } + + date_dtype = create_datetime_dtype_with_unit(NPY_DATETIME, NPY_FR_D); + if (date_dtype == NULL) { + goto fail; + } + + if (!PyArray_CanCastTypeTo(PyArray_DESCR(dates), + date_dtype, NPY_SAFE_CASTING)) { + PyErr_SetString(PyExc_ValueError, "Cannot safely convert " + "provided holidays input into an array of dates"); + goto fail; + } + if (PyArray_NDIM(dates) != 1) { + PyErr_SetString(PyExc_ValueError, "holidays must be a provided " + "as a one-dimensional array"); + goto fail; + } + + /* Allocate the memory for the dates */ + count = PyArray_DIM(dates, 0); + holidays->begin = PyArray_malloc(sizeof(npy_datetime) * count); + if (holidays->begin == NULL) { + PyErr_NoMemory(); + goto fail; + } + holidays->end = holidays->begin + count; + + /* Cast the data into a raw date array */ + if (PyArray_CastRawArrays(count, + PyArray_BYTES(dates), (char *)holidays->begin, + PyArray_STRIDE(dates, 0), sizeof(npy_datetime), + PyArray_DESCR(dates), date_dtype, + 0) != NPY_SUCCEED) { + goto fail; + } + + Py_DECREF(dates); + Py_DECREF(date_dtype); + + return 1; + +fail: + Py_XDECREF(dates); + Py_XDECREF(date_dtype); + return 0; +} + static PyObject * busdaydef_new(PyTypeObject *subtype, PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds)) { - PyArray_BusinessDayDef *self; + NpyBusinessDayDef *self; - self = (PyArray_BusinessDayDef *)subtype->tp_alloc(subtype, 0); + self = (NpyBusinessDayDef *)subtype->tp_alloc(subtype, 0); if (self != NULL) { /* Start with an empty holidays list */ self->holidays.begin = NULL; @@ -50,7 +358,7 @@ busdaydef_new(PyTypeObject *subtype, } static int -busdaydef_init(PyArray_BusinessDayDef *self, PyObject *args, PyObject *kwds) +busdaydef_init(NpyBusinessDayDef *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"weekmask", "holidays", NULL}; int i, busdays_in_weekmask; @@ -101,7 +409,7 @@ busdaydef_init(PyArray_BusinessDayDef *self, PyObject *args, PyObject *kwds) } static void -busdaydef_dealloc(PyArray_BusinessDayDef *self) +busdaydef_dealloc(NpyBusinessDayDef *self) { /* Clear the holidays */ if (self->holidays.begin != NULL) { @@ -114,7 +422,7 @@ busdaydef_dealloc(PyArray_BusinessDayDef *self) } static PyObject * -busdaydef_weekmask_get(PyArray_BusinessDayDef *self) +busdaydef_weekmask_get(NpyBusinessDayDef *self) { PyArrayObject *ret; npy_intp size = 7; @@ -132,7 +440,7 @@ busdaydef_weekmask_get(PyArray_BusinessDayDef *self) } static PyObject * -busdaydef_holidays_get(PyArray_BusinessDayDef *self) +busdaydef_holidays_get(NpyBusinessDayDef *self) { PyArrayObject *ret; PyArray_Descr *date_dtype; @@ -178,7 +486,7 @@ NPY_NO_EXPORT PyTypeObject NpyBusinessDayDef_Type = { 0, /* ob_size */ #endif "numpy.busdaydef", /* tp_name */ - sizeof(PyArray_BusinessDayDef), /* tp_basicsize */ + sizeof(NpyBusinessDayDef), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)busdaydef_dealloc, /* tp_dealloc */ diff --git a/numpy/core/src/multiarray/datetime_busdaydef.h b/numpy/core/src/multiarray/datetime_busdaydef.h index dafc5c07d..64e5244a8 100644 --- a/numpy/core/src/multiarray/datetime_busdaydef.h +++ b/numpy/core/src/multiarray/datetime_busdaydef.h @@ -6,11 +6,41 @@ typedef struct { npy_holidayslist holidays; int busdays_in_weekmask; npy_bool weekmask[7]; -} PyArray_BusinessDayDef; +} NpyBusinessDayDef; NPY_NO_EXPORT PyTypeObject NpyBusinessDayDef_Type; #define NpyBusinessDayDef_Check(op) PyObject_TypeCheck(op, \ &NpyBusinessDayDef_Type) +/* + * Converts a Python input into a 7-element weekmask, where 0 means + * weekend and 1 means business day. + */ +NPY_NO_EXPORT int +PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask); + +/* + * Sorts the the array of dates provided in place and removes + * NaT, duplicates and any date which is already excluded on account + * of the weekmask. + * + * Returns the number of dates left after removing weekmask-excluded + * dates. + */ +NPY_NO_EXPORT void +normalize_holidays_list(npy_holidayslist *holidays, npy_bool *weekmask); + +/* + * Converts a Python input into a non-normalized list of holidays. + * + * IMPORTANT: This function can't do the normalization, because it doesn't + * know the weekmask. You must call 'normalize_holiday_list' + * on the result before using it. + */ +NPY_NO_EXPORT int +PyArray_HolidaysConverter(PyObject *dates_in, npy_holidayslist *holidays); + + + #endif |