blob: 0994d8fda0e51fa40257d945e540b82f20743cfd [file] [log] [blame]
Antoine Pitrou1d80a562018-04-07 18:14:03 +02001#include <Python.h>
2#include "structmember.h"
3
4typedef struct {
5 PyObject_HEAD
6 PyObject *first; /* first name */
7 PyObject *last; /* last name */
8 int number;
9} CustomObject;
10
11static int
12Custom_traverse(CustomObject *self, visitproc visit, void *arg)
13{
14 Py_VISIT(self->first);
15 Py_VISIT(self->last);
16 return 0;
17}
18
19static int
20Custom_clear(CustomObject *self)
21{
22 Py_CLEAR(self->first);
23 Py_CLEAR(self->last);
24 return 0;
25}
26
27static void
28Custom_dealloc(CustomObject *self)
29{
30 PyObject_GC_UnTrack(self);
31 Custom_clear(self);
32 Py_TYPE(self)->tp_free((PyObject *) self);
33}
34
35static PyObject *
36Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
37{
38 CustomObject *self;
39 self = (CustomObject *) type->tp_alloc(type, 0);
40 if (self != NULL) {
41 self->first = PyUnicode_FromString("");
42 if (self->first == NULL) {
43 Py_DECREF(self);
44 return NULL;
45 }
46 self->last = PyUnicode_FromString("");
47 if (self->last == NULL) {
48 Py_DECREF(self);
49 return NULL;
50 }
51 self->number = 0;
52 }
53 return (PyObject *) self;
54}
55
56static int
57Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
58{
59 static char *kwlist[] = {"first", "last", "number", NULL};
60 PyObject *first = NULL, *last = NULL, *tmp;
61
62 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
63 &first, &last,
64 &self->number))
65 return -1;
66
67 if (first) {
68 tmp = self->first;
69 Py_INCREF(first);
70 self->first = first;
71 Py_DECREF(tmp);
72 }
73 if (last) {
74 tmp = self->last;
75 Py_INCREF(last);
76 self->last = last;
77 Py_DECREF(tmp);
78 }
79 return 0;
80}
81
82static PyMemberDef Custom_members[] = {
83 {"number", T_INT, offsetof(CustomObject, number), 0,
84 "custom number"},
85 {NULL} /* Sentinel */
86};
87
88static PyObject *
89Custom_getfirst(CustomObject *self, void *closure)
90{
91 Py_INCREF(self->first);
92 return self->first;
93}
94
95static int
96Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
97{
98 if (value == NULL) {
99 PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
100 return -1;
101 }
102 if (!PyUnicode_Check(value)) {
103 PyErr_SetString(PyExc_TypeError,
104 "The first attribute value must be a string");
105 return -1;
106 }
107 Py_INCREF(value);
108 Py_CLEAR(self->first);
109 self->first = value;
110 return 0;
111}
112
113static PyObject *
114Custom_getlast(CustomObject *self, void *closure)
115{
116 Py_INCREF(self->last);
117 return self->last;
118}
119
120static int
121Custom_setlast(CustomObject *self, PyObject *value, void *closure)
122{
123 if (value == NULL) {
124 PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
125 return -1;
126 }
127 if (!PyUnicode_Check(value)) {
128 PyErr_SetString(PyExc_TypeError,
129 "The last attribute value must be a string");
130 return -1;
131 }
132 Py_INCREF(value);
133 Py_CLEAR(self->last);
134 self->last = value;
135 return 0;
136}
137
138static PyGetSetDef Custom_getsetters[] = {
139 {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
140 "first name", NULL},
141 {"last", (getter) Custom_getlast, (setter) Custom_setlast,
142 "last name", NULL},
143 {NULL} /* Sentinel */
144};
145
146static PyObject *
147Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
148{
149 return PyUnicode_FromFormat("%S %S", self->first, self->last);
150}
151
152static PyMethodDef Custom_methods[] = {
153 {"name", (PyCFunction) Custom_name, METH_NOARGS,
154 "Return the name, combining the first and last name"
155 },
156 {NULL} /* Sentinel */
157};
158
159static PyTypeObject CustomType = {
160 PyVarObject_HEAD_INIT(NULL, 0)
161 .tp_name = "custom4.Custom",
162 .tp_doc = "Custom objects",
163 .tp_basicsize = sizeof(CustomObject),
164 .tp_itemsize = 0,
165 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
166 .tp_new = Custom_new,
167 .tp_init = (initproc) Custom_init,
168 .tp_dealloc = (destructor) Custom_dealloc,
169 .tp_traverse = (traverseproc) Custom_traverse,
170 .tp_clear = (inquiry) Custom_clear,
171 .tp_members = Custom_members,
172 .tp_methods = Custom_methods,
173 .tp_getset = Custom_getsetters,
174};
175
176static PyModuleDef custommodule = {
177 PyModuleDef_HEAD_INIT,
178 .m_name = "custom4",
179 .m_doc = "Example module that creates an extension type.",
180 .m_size = -1,
181};
182
183PyMODINIT_FUNC
184PyInit_custom4(void)
185{
186 PyObject *m;
187 if (PyType_Ready(&CustomType) < 0)
188 return NULL;
189
190 m = PyModule_Create(&custommodule);
191 if (m == NULL)
192 return NULL;
193
194 Py_INCREF(&CustomType);
195 PyModule_AddObject(m, "Custom", (PyObject *) &CustomType);
196 return m;
197}