1 #include "parts.h"
2 #include <stddef.h> // for offsetof()
3
4
5 // This defines two classes that contain all the simple member types, one
6 // using "new" Py_-prefixed API, and the other using "old" <structmember.h>.
7 // They should behave identically in Python.
8
9 typedef struct {
10 char bool_member;
11 char byte_member;
12 unsigned char ubyte_member;
13 short short_member;
14 unsigned short ushort_member;
15 int int_member;
16 unsigned int uint_member;
17 long long_member;
18 unsigned long ulong_member;
19 Py_ssize_t pyssizet_member;
20 float float_member;
21 double double_member;
22 char inplace_member[6];
23 long long longlong_member;
24 unsigned long long ulonglong_member;
25 } all_structmembers;
26
27 typedef struct {
28 PyObject_HEAD
29 all_structmembers structmembers;
30 } test_structmembers;
31
32
33 static struct PyMemberDef test_members_newapi[] = {
34 {"T_BOOL", Py_T_BOOL, offsetof(test_structmembers, structmembers.bool_member), 0, NULL},
35 {"T_BYTE", Py_T_BYTE, offsetof(test_structmembers, structmembers.byte_member), 0, NULL},
36 {"T_UBYTE", Py_T_UBYTE, offsetof(test_structmembers, structmembers.ubyte_member), 0, NULL},
37 {"T_SHORT", Py_T_SHORT, offsetof(test_structmembers, structmembers.short_member), 0, NULL},
38 {"T_USHORT", Py_T_USHORT, offsetof(test_structmembers, structmembers.ushort_member), 0, NULL},
39 {"T_INT", Py_T_INT, offsetof(test_structmembers, structmembers.int_member), 0, NULL},
40 {"T_UINT", Py_T_UINT, offsetof(test_structmembers, structmembers.uint_member), 0, NULL},
41 {"T_LONG", Py_T_LONG, offsetof(test_structmembers, structmembers.long_member), 0, NULL},
42 {"T_ULONG", Py_T_ULONG, offsetof(test_structmembers, structmembers.ulong_member), 0, NULL},
43 {"T_PYSSIZET", Py_T_PYSSIZET, offsetof(test_structmembers, structmembers.pyssizet_member), 0, NULL},
44 {"T_FLOAT", Py_T_FLOAT, offsetof(test_structmembers, structmembers.float_member), 0, NULL},
45 {"T_DOUBLE", Py_T_DOUBLE, offsetof(test_structmembers, structmembers.double_member), 0, NULL},
46 {"T_STRING_INPLACE", Py_T_STRING_INPLACE, offsetof(test_structmembers, structmembers.inplace_member), 0, NULL},
47 {"T_LONGLONG", Py_T_LONGLONG, offsetof(test_structmembers, structmembers.longlong_member), 0, NULL},
48 {"T_ULONGLONG", Py_T_ULONGLONG, offsetof(test_structmembers, structmembers.ulonglong_member), 0, NULL},
49 {NULL}
50 };
51
52 static PyObject *
test_structmembers_new(PyTypeObject * type,PyObject * args,PyObject * kwargs)53 test_structmembers_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
54 {
55 static char *keywords[] = {
56 "T_BOOL", "T_BYTE", "T_UBYTE", "T_SHORT", "T_USHORT",
57 "T_INT", "T_UINT", "T_LONG", "T_ULONG", "T_PYSSIZET",
58 "T_FLOAT", "T_DOUBLE", "T_STRING_INPLACE",
59 "T_LONGLONG", "T_ULONGLONG",
60 NULL};
61 static const char fmt[] = "|bbBhHiIlknfds#LK";
62 test_structmembers *ob;
63 const char *s = NULL;
64 Py_ssize_t string_len = 0;
65 ob = PyObject_New(test_structmembers, type);
66 if (ob == NULL) {
67 return NULL;
68 }
69 memset(&ob->structmembers, 0, sizeof(all_structmembers));
70 if (!PyArg_ParseTupleAndKeywords(args, kwargs, fmt, keywords,
71 &ob->structmembers.bool_member,
72 &ob->structmembers.byte_member,
73 &ob->structmembers.ubyte_member,
74 &ob->structmembers.short_member,
75 &ob->structmembers.ushort_member,
76 &ob->structmembers.int_member,
77 &ob->structmembers.uint_member,
78 &ob->structmembers.long_member,
79 &ob->structmembers.ulong_member,
80 &ob->structmembers.pyssizet_member,
81 &ob->structmembers.float_member,
82 &ob->structmembers.double_member,
83 &s, &string_len,
84 &ob->structmembers.longlong_member,
85 &ob->structmembers.ulonglong_member))
86 {
87 Py_DECREF(ob);
88 return NULL;
89 }
90 if (s != NULL) {
91 if (string_len > 5) {
92 Py_DECREF(ob);
93 PyErr_SetString(PyExc_ValueError, "string too long");
94 return NULL;
95 }
96 strcpy(ob->structmembers.inplace_member, s);
97 }
98 else {
99 strcpy(ob->structmembers.inplace_member, "");
100 }
101 return (PyObject *)ob;
102 }
103
104 static PyType_Slot test_structmembers_slots[] = {
105 {Py_tp_new, test_structmembers_new},
106 {Py_tp_members, test_members_newapi},
107 {0},
108 };
109
110 static PyType_Spec test_structmembers_spec = {
111 .name = "_testcapi._test_structmembersType_NewAPI",
112 .flags = Py_TPFLAGS_DEFAULT,
113 .basicsize = sizeof(test_structmembers),
114 .slots = test_structmembers_slots,
115 };
116
117 #include <structmember.h>
118
119 static struct PyMemberDef test_members[] = {
120 {"T_BOOL", T_BOOL, offsetof(test_structmembers, structmembers.bool_member), 0, NULL},
121 {"T_BYTE", T_BYTE, offsetof(test_structmembers, structmembers.byte_member), 0, NULL},
122 {"T_UBYTE", T_UBYTE, offsetof(test_structmembers, structmembers.ubyte_member), 0, NULL},
123 {"T_SHORT", T_SHORT, offsetof(test_structmembers, structmembers.short_member), 0, NULL},
124 {"T_USHORT", T_USHORT, offsetof(test_structmembers, structmembers.ushort_member), 0, NULL},
125 {"T_INT", T_INT, offsetof(test_structmembers, structmembers.int_member), 0, NULL},
126 {"T_UINT", T_UINT, offsetof(test_structmembers, structmembers.uint_member), 0, NULL},
127 {"T_LONG", T_LONG, offsetof(test_structmembers, structmembers.long_member), 0, NULL},
128 {"T_ULONG", T_ULONG, offsetof(test_structmembers, structmembers.ulong_member), 0, NULL},
129 {"T_PYSSIZET", T_PYSSIZET, offsetof(test_structmembers, structmembers.pyssizet_member), 0, NULL},
130 {"T_FLOAT", T_FLOAT, offsetof(test_structmembers, structmembers.float_member), 0, NULL},
131 {"T_DOUBLE", T_DOUBLE, offsetof(test_structmembers, structmembers.double_member), 0, NULL},
132 {"T_STRING_INPLACE", T_STRING_INPLACE, offsetof(test_structmembers, structmembers.inplace_member), 0, NULL},
133 {"T_LONGLONG", T_LONGLONG, offsetof(test_structmembers, structmembers.longlong_member), 0, NULL},
134 {"T_ULONGLONG", T_ULONGLONG, offsetof(test_structmembers, structmembers.ulonglong_member), 0, NULL},
135 {NULL}
136 };
137
138
139 static void
test_structmembers_free(PyObject * ob)140 test_structmembers_free(PyObject *ob)
141 {
142 PyObject_Free(ob);
143 }
144
145 /* Designated initializers would work too, but this does test the *old* API */
146 static PyTypeObject test_structmembersType_OldAPI= {
147 PyVarObject_HEAD_INIT(NULL, 0)
148 "test_structmembersType_OldAPI",
149 sizeof(test_structmembers), /* tp_basicsize */
150 0, /* tp_itemsize */
151 test_structmembers_free, /* destructor tp_dealloc */
152 0, /* tp_vectorcall_offset */
153 0, /* tp_getattr */
154 0, /* tp_setattr */
155 0, /* tp_as_async */
156 0, /* tp_repr */
157 0, /* tp_as_number */
158 0, /* tp_as_sequence */
159 0, /* tp_as_mapping */
160 0, /* tp_hash */
161 0, /* tp_call */
162 0, /* tp_str */
163 PyObject_GenericGetAttr, /* tp_getattro */
164 PyObject_GenericSetAttr, /* tp_setattro */
165 0, /* tp_as_buffer */
166 0, /* tp_flags */
167 "Type containing all structmember types",
168 0, /* traverseproc tp_traverse */
169 0, /* tp_clear */
170 0, /* tp_richcompare */
171 0, /* tp_weaklistoffset */
172 0, /* tp_iter */
173 0, /* tp_iternext */
174 0, /* tp_methods */
175 test_members, /* tp_members */
176 0,
177 0,
178 0,
179 0,
180 0,
181 0,
182 0,
183 0,
184 test_structmembers_new, /* tp_new */
185 };
186
187
188 int
_PyTestCapi_Init_Structmember(PyObject * m)189 _PyTestCapi_Init_Structmember(PyObject *m)
190 {
191 int res;
192 res = PyType_Ready(&test_structmembersType_OldAPI);
193 if (res < 0) {
194 return -1;
195 }
196 res = PyModule_AddObjectRef(
197 m,
198 "_test_structmembersType_OldAPI",
199 (PyObject *)&test_structmembersType_OldAPI);
200 if (res < 0) {
201 return -1;
202 }
203
204 PyObject *test_structmembersType_NewAPI = PyType_FromModuleAndSpec(
205 m, &test_structmembers_spec, NULL);
206 if (!test_structmembersType_NewAPI) {
207 return -1;
208 }
209 res = PyModule_AddType(m, (PyTypeObject*)test_structmembersType_NewAPI);
210 Py_DECREF(test_structmembersType_NewAPI);
211 if (res < 0) {
212 return -1;
213 }
214
215 return 0;
216 }
217