• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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