Skip to content

Commit a032d2e

Browse files
committed
Minor fiddling to make the next part easier. Introduced an internal
HASTZINFO() macro.
1 parent 74a032e commit a032d2e

2 files changed

Lines changed: 61 additions & 38 deletions

File tree

Include/datetime.h

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,35 +27,52 @@
2727
/* # of bytes for year, month, day, hour, minute, second, and usecond. */
2828
#define _PyDateTime_DATETIME_DATASIZE 10
2929

30-
#define _PyTZINFO_HEAD \
31-
PyObject_HEAD \
32-
long hashcode; \
33-
char hastzinfo; /* boolean flag */
3430

3531
typedef struct
3632
{
3733
PyObject_HEAD
38-
long hashcode;
39-
unsigned char data[_PyDateTime_DATE_DATASIZE];
40-
} PyDateTime_Date;
34+
long hashcode; /* -1 when unknown */
35+
int days; /* -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS */
36+
int seconds; /* 0 <= seconds < 24*3600 is invariant */
37+
int microseconds; /* 0 <= microseconds < 1000000 is invariant */
38+
} PyDateTime_Delta;
4139

4240
typedef struct
4341
{
44-
PyObject_HEAD
45-
long hashcode;
46-
unsigned char data[_PyDateTime_DATETIME_DATASIZE];
47-
} PyDateTime_DateTime;
42+
PyObject_HEAD /* a pure abstract base clase */
43+
} PyDateTime_TZInfo;
4844

4945
typedef struct
5046
{
5147
PyObject_HEAD
5248
long hashcode;
53-
unsigned char data[_PyDateTime_DATETIME_DATASIZE];
54-
PyObject *tzinfo;
55-
} PyDateTime_DateTimeTZ;
49+
unsigned char data[_PyDateTime_DATE_DATASIZE];
50+
} PyDateTime_Date;
5651

5752

53+
/* The datetime and time types have hashcodes, and an optional tzinfo member,
54+
* present if and only if hastzinfo is true.
55+
*/
56+
#define _PyTZINFO_HEAD \
57+
PyObject_HEAD \
58+
long hashcode; \
59+
char hastzinfo; /* boolean flag */
5860

61+
/* No _PyDateTime_BaseTZInfo is allocated; it's just to have something
62+
* convenient to cast to, when getting at the hastzinfo member of objects
63+
* starting with _PyTZINFO_HEAD.
64+
*/
65+
typedef struct
66+
{
67+
_PyTZINFO_HEAD
68+
} _PyDateTime_BaseTZInfo;
69+
70+
/* All time objects are of PyDateTime_TimeType, but that can be allocated
71+
* in two ways, with or without a tzinfo member. Without is the same as
72+
* tzinfo == None, but consumes less memory. _PyDateTime_BaseTime is an
73+
* internal struct used to allocate the right amount of space for the
74+
* "without" case.
75+
*/
5976
#define _PyDateTime_TIMEHEAD \
6077
_PyTZINFO_HEAD \
6178
unsigned char data[_PyDateTime_TIME_DATASIZE];
@@ -71,20 +88,23 @@ typedef struct
7188
PyObject *tzinfo;
7289
} PyDateTime_Time; /* hastzinfo true */
7390

91+
/* XXX The date type will be reworked similarly. */
7492

7593
typedef struct
7694
{
7795
PyObject_HEAD
78-
long hashcode; /* -1 when unknown */
79-
int days; /* -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS */
80-
int seconds; /* 0 <= seconds < 24*3600 is invariant */
81-
int microseconds; /* 0 <= microseconds < 1000000 is invariant */
82-
} PyDateTime_Delta;
96+
long hashcode;
97+
unsigned char data[_PyDateTime_DATETIME_DATASIZE];
98+
} PyDateTime_DateTime;
8399

84100
typedef struct
85101
{
86-
PyObject_HEAD /* a pure abstract base clase */
87-
} PyDateTime_TZInfo;
102+
PyObject_HEAD
103+
long hashcode;
104+
unsigned char data[_PyDateTime_DATETIME_DATASIZE];
105+
PyObject *tzinfo;
106+
} PyDateTime_DateTimeTZ;
107+
88108

89109
/* Apply for date, datetime, and datetimetz instances. */
90110
#define PyDateTime_GET_YEAR(o) ((((PyDateTime_Date*)o)->data[0] << 8) | \

Modules/datetimemodule.c

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@
7575
#define SET_TD_SECONDS(o, v) ((o)->seconds = (v))
7676
#define SET_TD_MICROSECONDS(o, v) ((o)->microseconds = (v))
7777

78+
/* p is a pointer to a time or a datetime object; HASTZINFO(p) returns
79+
* p->hastzinfo.
80+
*/
81+
#define HASTZINFO(p) (((_PyDateTime_BaseTZInfo *)(p))->hastzinfo)
82+
7883
/* Forward declarations. */
7984
static PyTypeObject PyDateTime_DateType;
8085
static PyTypeObject PyDateTime_DateTimeType;
@@ -606,7 +611,7 @@ get_tzinfo_member(PyObject *self)
606611

607612
if (PyDateTimeTZ_Check(self))
608613
tzinfo = ((PyDateTime_DateTimeTZ *)self)->tzinfo;
609-
else if (PyTime_Check(self) && ((PyDateTime_Time *)self)->hastzinfo)
614+
else if (PyTime_Check(self) && HASTZINFO(self))
610615
tzinfo = ((PyDateTime_Time *)self)->tzinfo;
611616

612617
return tzinfo;
@@ -2966,9 +2971,7 @@ datetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
29662971
TIME_GET_MINUTE(time),
29672972
TIME_GET_SECOND(time),
29682973
TIME_GET_MICROSECOND(time));
2969-
if (result &&
2970-
((PyDateTime_Time *)time)->hastzinfo &&
2971-
PyDateTimeTZ_Check(result)) {
2974+
if (result && HASTZINFO(time) && PyDateTimeTZ_Check(result)) {
29722975
/* Copy the tzinfo field. */
29732976
replace_tzinfo(result, ((PyDateTime_Time *)time)->tzinfo);
29742977
}
@@ -3618,7 +3621,7 @@ time_microsecond(PyDateTime_Time *self, void *unused)
36183621
static PyObject *
36193622
time_tzinfo(PyDateTime_Time *self, void *unused)
36203623
{
3621-
PyObject *result = self->hastzinfo ? self->tzinfo : Py_None;
3624+
PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None;
36223625
Py_INCREF(result);
36233626
return result;
36243627
}
@@ -3668,7 +3671,7 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
36683671
static void
36693672
time_dealloc(PyDateTime_Time *self)
36703673
{
3671-
if (self->hastzinfo) {
3674+
if (HASTZINFO(self)) {
36723675
Py_XDECREF(self->tzinfo);
36733676
}
36743677
self->ob_type->tp_free((PyObject *)self);
@@ -3681,19 +3684,19 @@ time_dealloc(PyDateTime_Time *self)
36813684
/* These are all METH_NOARGS, so don't need to check the arglist. */
36823685
static PyObject *
36833686
time_utcoffset(PyDateTime_Time *self, PyObject *unused) {
3684-
return offset_as_timedelta(self->hastzinfo ? self->tzinfo : Py_None,
3687+
return offset_as_timedelta(HASTZINFO(self) ? self->tzinfo : Py_None,
36853688
"utcoffset", Py_None);
36863689
}
36873690

36883691
static PyObject *
36893692
time_dst(PyDateTime_Time *self, PyObject *unused) {
3690-
return offset_as_timedelta(self->hastzinfo ? self->tzinfo : Py_None,
3693+
return offset_as_timedelta(HASTZINFO(self) ? self->tzinfo : Py_None,
36913694
"dst", Py_None);
36923695
}
36933696

36943697
static PyObject *
36953698
time_tzname(PyDateTime_Time *self, PyObject *unused) {
3696-
return call_tzname(self->hastzinfo ? self->tzinfo : Py_None,
3699+
return call_tzname(HASTZINFO(self) ? self->tzinfo : Py_None,
36973700
Py_None);
36983701
}
36993702

@@ -3722,7 +3725,7 @@ time_repr(PyDateTime_Time *self)
37223725
PyOS_snprintf(buffer, sizeof(buffer),
37233726
"%s(%d, %d)", typename, h, m);
37243727
result = PyString_FromString(buffer);
3725-
if (result != NULL && self->hastzinfo)
3728+
if (result != NULL && HASTZINFO(self))
37263729
result = append_keyword_tzinfo(result, self->tzinfo);
37273730
return result;
37283731
}
@@ -3749,7 +3752,7 @@ time_isoformat(PyDateTime_Time *self)
37493752

37503753
isoformat_time(pdatetime, buf, sizeof(buf));
37513754
result = PyString_FromString(buf);
3752-
if (result == NULL || ! self->hastzinfo || self->tzinfo == Py_None)
3755+
if (result == NULL || ! HASTZINFO(self) || self->tzinfo == Py_None)
37533756
return result;
37543757

37553758
/* We need to append the UTC offset. */
@@ -3876,7 +3879,7 @@ time_hash(PyDateTime_Time *self)
38763879
int minute;
38773880

38783881
assert(n == OFFSET_AWARE);
3879-
assert(self->hastzinfo);
3882+
assert(HASTZINFO(self));
38803883
hour = divmod(TIME_GET_HOUR(self) * 60 +
38813884
TIME_GET_MINUTE(self) - offset,
38823885
60,
@@ -3909,7 +3912,7 @@ time_replace(PyDateTime_Time *self, PyObject *args, PyObject *kw)
39093912
int mm = TIME_GET_MINUTE(self);
39103913
int ss = TIME_GET_SECOND(self);
39113914
int us = TIME_GET_MICROSECOND(self);
3912-
PyObject *tzinfo = self->hastzinfo ? self->tzinfo : Py_None;
3915+
PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None;
39133916

39143917
if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO:replace",
39153918
time_kws,
@@ -3936,7 +3939,7 @@ time_nonzero(PyDateTime_Time *self)
39363939
return 1;
39373940
}
39383941
offset = 0;
3939-
if (self->hastzinfo && self->tzinfo != Py_None) {
3942+
if (HASTZINFO(self) && self->tzinfo != Py_None) {
39403943
offset = call_utcoffset(self->tzinfo, Py_None, &none);
39413944
if (offset == -1 && PyErr_Occurred())
39423945
return -1;
@@ -3961,7 +3964,7 @@ time_getstate(PyDateTime_Time *self)
39613964
basestate = PyString_FromStringAndSize((char *)self->data,
39623965
_PyDateTime_TIME_DATASIZE);
39633966
if (basestate != NULL) {
3964-
if (! self->hastzinfo || self->tzinfo == Py_None)
3967+
if (! HASTZINFO(self) || self->tzinfo == Py_None)
39653968
result = Py_BuildValue("(O)", basestate);
39663969
else
39673970
result = Py_BuildValue("OO", basestate, self->tzinfo);
@@ -3986,7 +3989,7 @@ time_setstate(PyDateTime_Time *self, PyObject *state)
39863989
"bad argument to time.__setstate__");
39873990
return NULL;
39883991
}
3989-
if (tzinfo != Py_None && ! self->hastzinfo) {
3992+
if (tzinfo != Py_None && ! HASTZINFO(self)) {
39903993
PyErr_SetString(PyExc_ValueError, "time.__setstate__ can't "
39913994
"add a non-None tzinfo to a time object that "
39923995
"doesn't have one already");
@@ -3996,7 +3999,7 @@ time_setstate(PyDateTime_Time *self, PyObject *state)
39963999
PyString_AsString(basestate),
39974000
_PyDateTime_TIME_DATASIZE);
39984001
self->hashcode = -1;
3999-
if (self->hastzinfo) {
4002+
if (HASTZINFO(self)) {
40004003
Py_INCREF(tzinfo);
40014004
Py_XDECREF(self->tzinfo);
40024005
self->tzinfo = tzinfo;

0 commit comments

Comments
 (0)