]>
Commit | Line | Data |
---|---|---|
7eb75bcc DM |
1 | \r |
2 | #include "Python.h"\r | |
3 | \r | |
4 | PyDoc_STRVAR(operator_doc,\r | |
5 | "Operator interface.\n\\r | |
6 | \n\\r | |
7 | This module exports a set of functions implemented in C corresponding\n\\r | |
8 | to the intrinsic operators of Python. For example, operator.add(x, y)\n\\r | |
9 | is equivalent to the expression x+y. The function names are those\n\\r | |
10 | used for special methods; variants without leading and trailing\n\\r | |
11 | '__' are also provided for convenience.");\r | |
12 | \r | |
13 | #define spam1(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a1) { \\r | |
14 | return AOP(a1); }\r | |
15 | \r | |
16 | #define spam2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \\r | |
17 | PyObject *a1, *a2; \\r | |
18 | if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \\r | |
19 | return AOP(a1,a2); }\r | |
20 | \r | |
21 | #define spamoi(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \\r | |
22 | PyObject *a1; int a2; \\r | |
23 | if(! PyArg_ParseTuple(a,"Oi:" #OP,&a1,&a2)) return NULL; \\r | |
24 | return AOP(a1,a2); }\r | |
25 | \r | |
26 | #define spam2n(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \\r | |
27 | PyObject *a1, *a2; \\r | |
28 | if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \\r | |
29 | if(-1 == AOP(a1,a2)) return NULL; \\r | |
30 | Py_INCREF(Py_None); \\r | |
31 | return Py_None; }\r | |
32 | \r | |
33 | #define spam3n(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \\r | |
34 | PyObject *a1, *a2, *a3; \\r | |
35 | if(! PyArg_UnpackTuple(a,#OP,3,3,&a1,&a2,&a3)) return NULL; \\r | |
36 | if(-1 == AOP(a1,a2,a3)) return NULL; \\r | |
37 | Py_INCREF(Py_None); \\r | |
38 | return Py_None; }\r | |
39 | \r | |
40 | #define spami(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a1) { \\r | |
41 | long r; \\r | |
42 | if(-1 == (r=AOP(a1))) return NULL; \\r | |
43 | return PyBool_FromLong(r); }\r | |
44 | \r | |
45 | #define spami2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \\r | |
46 | PyObject *a1, *a2; long r; \\r | |
47 | if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \\r | |
48 | if(-1 == (r=AOP(a1,a2))) return NULL; \\r | |
49 | return PyInt_FromLong(r); }\r | |
50 | \r | |
51 | #define spamn2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \\r | |
52 | PyObject *a1, *a2; Py_ssize_t r; \\r | |
53 | if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \\r | |
54 | if(-1 == (r=AOP(a1,a2))) return NULL; \\r | |
55 | return PyInt_FromSsize_t(r); }\r | |
56 | \r | |
57 | #define spami2b(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \\r | |
58 | PyObject *a1, *a2; long r; \\r | |
59 | if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \\r | |
60 | if(-1 == (r=AOP(a1,a2))) return NULL; \\r | |
61 | return PyBool_FromLong(r); }\r | |
62 | \r | |
63 | #define spamrc(OP,A) static PyObject *OP(PyObject *s, PyObject *a) { \\r | |
64 | PyObject *a1, *a2; \\r | |
65 | if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \\r | |
66 | return PyObject_RichCompare(a1,a2,A); }\r | |
67 | \r | |
68 | /* Deprecated operators that need warnings. */\r | |
69 | static int\r | |
70 | op_isCallable(PyObject *x)\r | |
71 | {\r | |
72 | if (PyErr_WarnPy3k("operator.isCallable() is not supported in 3.x. "\r | |
73 | "Use hasattr(obj, '__call__').", 1) < 0)\r | |
74 | return -1;\r | |
75 | return PyCallable_Check(x);\r | |
76 | }\r | |
77 | \r | |
78 | static int\r | |
79 | op_sequenceIncludes(PyObject *seq, PyObject* ob)\r | |
80 | {\r | |
81 | if (PyErr_WarnPy3k("operator.sequenceIncludes() is not supported "\r | |
82 | "in 3.x. Use operator.contains().", 1) < 0)\r | |
83 | return -1;\r | |
84 | return PySequence_Contains(seq, ob);\r | |
85 | }\r | |
86 | \r | |
87 | spami(isCallable , op_isCallable)\r | |
88 | spami(isNumberType , PyNumber_Check)\r | |
89 | spami(truth , PyObject_IsTrue)\r | |
90 | spam2(op_add , PyNumber_Add)\r | |
91 | spam2(op_sub , PyNumber_Subtract)\r | |
92 | spam2(op_mul , PyNumber_Multiply)\r | |
93 | spam2(op_div , PyNumber_Divide)\r | |
94 | spam2(op_floordiv , PyNumber_FloorDivide)\r | |
95 | spam2(op_truediv , PyNumber_TrueDivide)\r | |
96 | spam2(op_mod , PyNumber_Remainder)\r | |
97 | spam1(op_neg , PyNumber_Negative)\r | |
98 | spam1(op_pos , PyNumber_Positive)\r | |
99 | spam1(op_abs , PyNumber_Absolute)\r | |
100 | spam1(op_inv , PyNumber_Invert)\r | |
101 | spam1(op_invert , PyNumber_Invert)\r | |
102 | spam2(op_lshift , PyNumber_Lshift)\r | |
103 | spam2(op_rshift , PyNumber_Rshift)\r | |
104 | spami(op_not_ , PyObject_Not)\r | |
105 | spam2(op_and_ , PyNumber_And)\r | |
106 | spam2(op_xor , PyNumber_Xor)\r | |
107 | spam2(op_or_ , PyNumber_Or)\r | |
108 | spam2(op_iadd , PyNumber_InPlaceAdd)\r | |
109 | spam2(op_isub , PyNumber_InPlaceSubtract)\r | |
110 | spam2(op_imul , PyNumber_InPlaceMultiply)\r | |
111 | spam2(op_idiv , PyNumber_InPlaceDivide)\r | |
112 | spam2(op_ifloordiv , PyNumber_InPlaceFloorDivide)\r | |
113 | spam2(op_itruediv , PyNumber_InPlaceTrueDivide)\r | |
114 | spam2(op_imod , PyNumber_InPlaceRemainder)\r | |
115 | spam2(op_ilshift , PyNumber_InPlaceLshift)\r | |
116 | spam2(op_irshift , PyNumber_InPlaceRshift)\r | |
117 | spam2(op_iand , PyNumber_InPlaceAnd)\r | |
118 | spam2(op_ixor , PyNumber_InPlaceXor)\r | |
119 | spam2(op_ior , PyNumber_InPlaceOr)\r | |
120 | spami(isSequenceType , PySequence_Check)\r | |
121 | spam2(op_concat , PySequence_Concat)\r | |
122 | spamoi(op_repeat , PySequence_Repeat)\r | |
123 | spam2(op_iconcat , PySequence_InPlaceConcat)\r | |
124 | spamoi(op_irepeat , PySequence_InPlaceRepeat)\r | |
125 | spami2b(op_contains , PySequence_Contains)\r | |
126 | spami2b(sequenceIncludes, op_sequenceIncludes)\r | |
127 | spamn2(indexOf , PySequence_Index)\r | |
128 | spamn2(countOf , PySequence_Count)\r | |
129 | spami(isMappingType , PyMapping_Check)\r | |
130 | spam2(op_getitem , PyObject_GetItem)\r | |
131 | spam2n(op_delitem , PyObject_DelItem)\r | |
132 | spam3n(op_setitem , PyObject_SetItem)\r | |
133 | spamrc(op_lt , Py_LT)\r | |
134 | spamrc(op_le , Py_LE)\r | |
135 | spamrc(op_eq , Py_EQ)\r | |
136 | spamrc(op_ne , Py_NE)\r | |
137 | spamrc(op_gt , Py_GT)\r | |
138 | spamrc(op_ge , Py_GE)\r | |
139 | \r | |
140 | static PyObject*\r | |
141 | op_pow(PyObject *s, PyObject *a)\r | |
142 | {\r | |
143 | PyObject *a1, *a2;\r | |
144 | if (PyArg_UnpackTuple(a,"pow", 2, 2, &a1, &a2))\r | |
145 | return PyNumber_Power(a1, a2, Py_None);\r | |
146 | return NULL;\r | |
147 | }\r | |
148 | \r | |
149 | static PyObject*\r | |
150 | op_ipow(PyObject *s, PyObject *a)\r | |
151 | {\r | |
152 | PyObject *a1, *a2;\r | |
153 | if (PyArg_UnpackTuple(a,"ipow", 2, 2, &a1, &a2))\r | |
154 | return PyNumber_InPlacePower(a1, a2, Py_None);\r | |
155 | return NULL;\r | |
156 | }\r | |
157 | \r | |
158 | static PyObject *\r | |
159 | op_index(PyObject *s, PyObject *a)\r | |
160 | {\r | |
161 | return PyNumber_Index(a);\r | |
162 | }\r | |
163 | \r | |
164 | static PyObject*\r | |
165 | is_(PyObject *s, PyObject *a)\r | |
166 | {\r | |
167 | PyObject *a1, *a2, *result = NULL;\r | |
168 | if (PyArg_UnpackTuple(a,"is_", 2, 2, &a1, &a2)) {\r | |
169 | result = (a1 == a2) ? Py_True : Py_False;\r | |
170 | Py_INCREF(result);\r | |
171 | }\r | |
172 | return result;\r | |
173 | }\r | |
174 | \r | |
175 | static PyObject*\r | |
176 | is_not(PyObject *s, PyObject *a)\r | |
177 | {\r | |
178 | PyObject *a1, *a2, *result = NULL;\r | |
179 | if (PyArg_UnpackTuple(a,"is_not", 2, 2, &a1, &a2)) {\r | |
180 | result = (a1 != a2) ? Py_True : Py_False;\r | |
181 | Py_INCREF(result);\r | |
182 | }\r | |
183 | return result;\r | |
184 | }\r | |
185 | \r | |
186 | static PyObject*\r | |
187 | op_getslice(PyObject *s, PyObject *a)\r | |
188 | {\r | |
189 | PyObject *a1;\r | |
190 | Py_ssize_t a2, a3;\r | |
191 | \r | |
192 | if (!PyArg_ParseTuple(a, "Onn:getslice", &a1, &a2, &a3))\r | |
193 | return NULL;\r | |
194 | return PySequence_GetSlice(a1, a2, a3);\r | |
195 | }\r | |
196 | \r | |
197 | static PyObject*\r | |
198 | op_setslice(PyObject *s, PyObject *a)\r | |
199 | {\r | |
200 | PyObject *a1, *a4;\r | |
201 | Py_ssize_t a2, a3;\r | |
202 | \r | |
203 | if (!PyArg_ParseTuple(a, "OnnO:setslice", &a1, &a2, &a3, &a4))\r | |
204 | return NULL;\r | |
205 | \r | |
206 | if (-1 == PySequence_SetSlice(a1, a2, a3, a4))\r | |
207 | return NULL;\r | |
208 | \r | |
209 | Py_RETURN_NONE;\r | |
210 | }\r | |
211 | \r | |
212 | static PyObject*\r | |
213 | op_delslice(PyObject *s, PyObject *a)\r | |
214 | {\r | |
215 | PyObject *a1;\r | |
216 | Py_ssize_t a2, a3;\r | |
217 | \r | |
218 | if (!PyArg_ParseTuple(a, "Onn:delslice", &a1, &a2, &a3))\r | |
219 | return NULL;\r | |
220 | \r | |
221 | if (-1 == PySequence_DelSlice(a1, a2, a3))\r | |
222 | return NULL;\r | |
223 | \r | |
224 | Py_RETURN_NONE;\r | |
225 | }\r | |
226 | \r | |
227 | #undef spam1\r | |
228 | #undef spam2\r | |
229 | #undef spam1o\r | |
230 | #undef spam1o\r | |
231 | #define spam1(OP,DOC) {#OP, OP, METH_VARARGS, PyDoc_STR(DOC)},\r | |
232 | #define spam2(OP,ALTOP,DOC) {#OP, op_##OP, METH_VARARGS, PyDoc_STR(DOC)}, \\r | |
233 | {#ALTOP, op_##OP, METH_VARARGS, PyDoc_STR(DOC)},\r | |
234 | #define spam1o(OP,DOC) {#OP, OP, METH_O, PyDoc_STR(DOC)},\r | |
235 | #define spam2o(OP,ALTOP,DOC) {#OP, op_##OP, METH_O, PyDoc_STR(DOC)}, \\r | |
236 | {#ALTOP, op_##OP, METH_O, PyDoc_STR(DOC)},\r | |
237 | \r | |
238 | \r | |
239 | \r | |
240 | /* compare_digest **********************************************************/\r | |
241 | \r | |
242 | /*\r | |
243 | * timing safe compare\r | |
244 | *\r | |
245 | * Returns 1 of the strings are equal.\r | |
246 | * In case of len(a) != len(b) the function tries to keep the timing\r | |
247 | * dependent on the length of b. CPU cache locally may still alter timing\r | |
248 | * a bit.\r | |
249 | */\r | |
250 | static int\r | |
251 | _tscmp(const unsigned char *a, const unsigned char *b,\r | |
252 | Py_ssize_t len_a, Py_ssize_t len_b)\r | |
253 | {\r | |
254 | /* The volatile type declarations make sure that the compiler has no\r | |
255 | * chance to optimize and fold the code in any way that may change\r | |
256 | * the timing.\r | |
257 | */\r | |
258 | volatile Py_ssize_t length;\r | |
259 | volatile const unsigned char *left;\r | |
260 | volatile const unsigned char *right;\r | |
261 | Py_ssize_t i;\r | |
262 | unsigned char result;\r | |
263 | \r | |
264 | /* loop count depends on length of b */\r | |
265 | length = len_b;\r | |
266 | left = NULL;\r | |
267 | right = b;\r | |
268 | \r | |
269 | /* don't use else here to keep the amount of CPU instructions constant,\r | |
270 | * volatile forces re-evaluation\r | |
271 | * */\r | |
272 | if (len_a == length) {\r | |
273 | left = *((volatile const unsigned char**)&a);\r | |
274 | result = 0;\r | |
275 | }\r | |
276 | if (len_a != length) {\r | |
277 | left = b;\r | |
278 | result = 1;\r | |
279 | }\r | |
280 | \r | |
281 | for (i=0; i < length; i++) {\r | |
282 | result |= *left++ ^ *right++;\r | |
283 | }\r | |
284 | \r | |
285 | return (result == 0);\r | |
286 | }\r | |
287 | \r | |
288 | PyDoc_STRVAR(compare_digest__doc__,\r | |
289 | "compare_digest(a, b) -> bool\n"\r | |
290 | "\n"\r | |
291 | "Return 'a == b'. This function uses an approach designed to prevent\n"\r | |
292 | "timing analysis, making it appropriate for cryptography.\n"\r | |
293 | "a and b must both be of the same type: either str (ASCII only),\n"\r | |
294 | "or any type that supports the buffer protocol (e.g. bytes).\n"\r | |
295 | "\n"\r | |
296 | "Note: If a and b are of different lengths, or if an error occurs,\n"\r | |
297 | "a timing attack could theoretically reveal information about the\n"\r | |
298 | "types and lengths of a and b--but not their values.\n");\r | |
299 | \r | |
300 | static PyObject*\r | |
301 | compare_digest(PyObject *self, PyObject *args)\r | |
302 | {\r | |
303 | PyObject *a, *b;\r | |
304 | int rc;\r | |
305 | \r | |
306 | if (!PyArg_ParseTuple(args, "OO:compare_digest", &a, &b)) {\r | |
307 | return NULL;\r | |
308 | }\r | |
309 | \r | |
310 | /* Unicode string */\r | |
311 | if (PyUnicode_Check(a) && PyUnicode_Check(b)) {\r | |
312 | rc = _tscmp((const unsigned char *)PyUnicode_AS_DATA(a),\r | |
313 | (const unsigned char *)PyUnicode_AS_DATA(b),\r | |
314 | PyUnicode_GET_DATA_SIZE(a),\r | |
315 | PyUnicode_GET_DATA_SIZE(b));\r | |
316 | }\r | |
317 | /* fallback to buffer interface for bytes, bytesarray and other */\r | |
318 | else {\r | |
319 | Py_buffer view_a;\r | |
320 | Py_buffer view_b;\r | |
321 | \r | |
322 | if (PyObject_CheckBuffer(a) == 0 && PyObject_CheckBuffer(b) == 0) {\r | |
323 | PyErr_Format(PyExc_TypeError,\r | |
324 | "unsupported operand types(s) or combination of types: "\r | |
325 | "'%.100s' and '%.100s'",\r | |
326 | Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name);\r | |
327 | return NULL;\r | |
328 | }\r | |
329 | \r | |
330 | if (PyObject_GetBuffer(a, &view_a, PyBUF_SIMPLE) == -1) {\r | |
331 | return NULL;\r | |
332 | }\r | |
333 | if (view_a.ndim > 1) {\r | |
334 | PyErr_SetString(PyExc_BufferError,\r | |
335 | "Buffer must be single dimension");\r | |
336 | PyBuffer_Release(&view_a);\r | |
337 | return NULL;\r | |
338 | }\r | |
339 | \r | |
340 | if (PyObject_GetBuffer(b, &view_b, PyBUF_SIMPLE) == -1) {\r | |
341 | PyBuffer_Release(&view_a);\r | |
342 | return NULL;\r | |
343 | }\r | |
344 | if (view_b.ndim > 1) {\r | |
345 | PyErr_SetString(PyExc_BufferError,\r | |
346 | "Buffer must be single dimension");\r | |
347 | PyBuffer_Release(&view_a);\r | |
348 | PyBuffer_Release(&view_b);\r | |
349 | return NULL;\r | |
350 | }\r | |
351 | \r | |
352 | rc = _tscmp((const unsigned char*)view_a.buf,\r | |
353 | (const unsigned char*)view_b.buf,\r | |
354 | view_a.len,\r | |
355 | view_b.len);\r | |
356 | \r | |
357 | PyBuffer_Release(&view_a);\r | |
358 | PyBuffer_Release(&view_b);\r | |
359 | }\r | |
360 | \r | |
361 | return PyBool_FromLong(rc);\r | |
362 | }\r | |
363 | \r | |
364 | static struct PyMethodDef operator_methods[] = {\r | |
365 | \r | |
366 | spam1o(isCallable,\r | |
367 | "isCallable(a) -- Same as callable(a).")\r | |
368 | spam1o(isNumberType,\r | |
369 | "isNumberType(a) -- Return True if a has a numeric type, False otherwise.")\r | |
370 | spam1o(isSequenceType,\r | |
371 | "isSequenceType(a) -- Return True if a has a sequence type, False otherwise.")\r | |
372 | spam1o(truth,\r | |
373 | "truth(a) -- Return True if a is true, False otherwise.")\r | |
374 | spam2(contains,__contains__,\r | |
375 | "contains(a, b) -- Same as b in a (note reversed operands).")\r | |
376 | spam1(sequenceIncludes,\r | |
377 | "sequenceIncludes(a, b) -- Same as b in a (note reversed operands; deprecated).")\r | |
378 | spam1(indexOf,\r | |
379 | "indexOf(a, b) -- Return the first index of b in a.")\r | |
380 | spam1(countOf,\r | |
381 | "countOf(a, b) -- Return the number of times b occurs in a.")\r | |
382 | spam1o(isMappingType,\r | |
383 | "isMappingType(a) -- Return True if a has a mapping type, False otherwise.")\r | |
384 | \r | |
385 | spam1(is_, "is_(a, b) -- Same as a is b.")\r | |
386 | spam1(is_not, "is_not(a, b) -- Same as a is not b.")\r | |
387 | spam2o(index, __index__, "index(a) -- Same as a.__index__()")\r | |
388 | spam2(add,__add__, "add(a, b) -- Same as a + b.")\r | |
389 | spam2(sub,__sub__, "sub(a, b) -- Same as a - b.")\r | |
390 | spam2(mul,__mul__, "mul(a, b) -- Same as a * b.")\r | |
391 | spam2(div,__div__, "div(a, b) -- Same as a / b when __future__.division is not in effect.")\r | |
392 | spam2(floordiv,__floordiv__, "floordiv(a, b) -- Same as a // b.")\r | |
393 | spam2(truediv,__truediv__, "truediv(a, b) -- Same as a / b when __future__.division is in effect.")\r | |
394 | spam2(mod,__mod__, "mod(a, b) -- Same as a % b.")\r | |
395 | spam2o(neg,__neg__, "neg(a) -- Same as -a.")\r | |
396 | spam2o(pos,__pos__, "pos(a) -- Same as +a.")\r | |
397 | spam2o(abs,__abs__, "abs(a) -- Same as abs(a).")\r | |
398 | spam2o(inv,__inv__, "inv(a) -- Same as ~a.")\r | |
399 | spam2o(invert,__invert__, "invert(a) -- Same as ~a.")\r | |
400 | spam2(lshift,__lshift__, "lshift(a, b) -- Same as a << b.")\r | |
401 | spam2(rshift,__rshift__, "rshift(a, b) -- Same as a >> b.")\r | |
402 | spam2o(not_,__not__, "not_(a) -- Same as not a.")\r | |
403 | spam2(and_,__and__, "and_(a, b) -- Same as a & b.")\r | |
404 | spam2(xor,__xor__, "xor(a, b) -- Same as a ^ b.")\r | |
405 | spam2(or_,__or__, "or_(a, b) -- Same as a | b.")\r | |
406 | spam2(iadd,__iadd__, "a = iadd(a, b) -- Same as a += b.")\r | |
407 | spam2(isub,__isub__, "a = isub(a, b) -- Same as a -= b.")\r | |
408 | spam2(imul,__imul__, "a = imul(a, b) -- Same as a *= b.")\r | |
409 | spam2(idiv,__idiv__, "a = idiv(a, b) -- Same as a /= b when __future__.division is not in effect.")\r | |
410 | spam2(ifloordiv,__ifloordiv__, "a = ifloordiv(a, b) -- Same as a //= b.")\r | |
411 | spam2(itruediv,__itruediv__, "a = itruediv(a, b) -- Same as a /= b when __future__.division is in effect.")\r | |
412 | spam2(imod,__imod__, "a = imod(a, b) -- Same as a %= b.")\r | |
413 | spam2(ilshift,__ilshift__, "a = ilshift(a, b) -- Same as a <<= b.")\r | |
414 | spam2(irshift,__irshift__, "a = irshift(a, b) -- Same as a >>= b.")\r | |
415 | spam2(iand,__iand__, "a = iand(a, b) -- Same as a &= b.")\r | |
416 | spam2(ixor,__ixor__, "a = ixor(a, b) -- Same as a ^= b.")\r | |
417 | spam2(ior,__ior__, "a = ior(a, b) -- Same as a |= b.")\r | |
418 | spam2(concat,__concat__,\r | |
419 | "concat(a, b) -- Same as a + b, for a and b sequences.")\r | |
420 | spam2(repeat,__repeat__,\r | |
421 | "repeat(a, b) -- Return a * b, where a is a sequence, and b is an integer.")\r | |
422 | spam2(iconcat,__iconcat__,\r | |
423 | "a = iconcat(a, b) -- Same as a += b, for a and b sequences.")\r | |
424 | spam2(irepeat,__irepeat__,\r | |
425 | "a = irepeat(a, b) -- Same as a *= b, where a is a sequence, and b is an integer.")\r | |
426 | spam2(getitem,__getitem__,\r | |
427 | "getitem(a, b) -- Same as a[b].")\r | |
428 | spam2(setitem,__setitem__,\r | |
429 | "setitem(a, b, c) -- Same as a[b] = c.")\r | |
430 | spam2(delitem,__delitem__,\r | |
431 | "delitem(a, b) -- Same as del a[b].")\r | |
432 | spam2(pow,__pow__, "pow(a, b) -- Same as a ** b.")\r | |
433 | spam2(ipow,__ipow__, "a = ipow(a, b) -- Same as a **= b.")\r | |
434 | spam2(getslice,__getslice__,\r | |
435 | "getslice(a, b, c) -- Same as a[b:c].")\r | |
436 | spam2(setslice,__setslice__,\r | |
437 | "setslice(a, b, c, d) -- Same as a[b:c] = d.")\r | |
438 | spam2(delslice,__delslice__,\r | |
439 | "delslice(a, b, c) -- Same as del a[b:c].")\r | |
440 | spam2(lt,__lt__, "lt(a, b) -- Same as a<b.")\r | |
441 | spam2(le,__le__, "le(a, b) -- Same as a<=b.")\r | |
442 | spam2(eq,__eq__, "eq(a, b) -- Same as a==b.")\r | |
443 | spam2(ne,__ne__, "ne(a, b) -- Same as a!=b.")\r | |
444 | spam2(gt,__gt__, "gt(a, b) -- Same as a>b.")\r | |
445 | spam2(ge,__ge__, "ge(a, b) -- Same as a>=b.")\r | |
446 | \r | |
447 | {"_compare_digest", (PyCFunction)compare_digest, METH_VARARGS,\r | |
448 | compare_digest__doc__},\r | |
449 | {NULL, NULL} /* sentinel */\r | |
450 | \r | |
451 | };\r | |
452 | \r | |
453 | /* itemgetter object **********************************************************/\r | |
454 | \r | |
455 | typedef struct {\r | |
456 | PyObject_HEAD\r | |
457 | Py_ssize_t nitems;\r | |
458 | PyObject *item;\r | |
459 | } itemgetterobject;\r | |
460 | \r | |
461 | static PyTypeObject itemgetter_type;\r | |
462 | \r | |
463 | static PyObject *\r | |
464 | itemgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\r | |
465 | {\r | |
466 | itemgetterobject *ig;\r | |
467 | PyObject *item;\r | |
468 | Py_ssize_t nitems;\r | |
469 | \r | |
470 | if (!_PyArg_NoKeywords("itemgetter()", kwds))\r | |
471 | return NULL;\r | |
472 | \r | |
473 | nitems = PyTuple_GET_SIZE(args);\r | |
474 | if (nitems <= 1) {\r | |
475 | if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &item))\r | |
476 | return NULL;\r | |
477 | } else\r | |
478 | item = args;\r | |
479 | \r | |
480 | /* create itemgetterobject structure */\r | |
481 | ig = PyObject_GC_New(itemgetterobject, &itemgetter_type);\r | |
482 | if (ig == NULL)\r | |
483 | return NULL;\r | |
484 | \r | |
485 | Py_INCREF(item);\r | |
486 | ig->item = item;\r | |
487 | ig->nitems = nitems;\r | |
488 | \r | |
489 | PyObject_GC_Track(ig);\r | |
490 | return (PyObject *)ig;\r | |
491 | }\r | |
492 | \r | |
493 | static void\r | |
494 | itemgetter_dealloc(itemgetterobject *ig)\r | |
495 | {\r | |
496 | PyObject_GC_UnTrack(ig);\r | |
497 | Py_XDECREF(ig->item);\r | |
498 | PyObject_GC_Del(ig);\r | |
499 | }\r | |
500 | \r | |
501 | static int\r | |
502 | itemgetter_traverse(itemgetterobject *ig, visitproc visit, void *arg)\r | |
503 | {\r | |
504 | Py_VISIT(ig->item);\r | |
505 | return 0;\r | |
506 | }\r | |
507 | \r | |
508 | static PyObject *\r | |
509 | itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw)\r | |
510 | {\r | |
511 | PyObject *obj, *result;\r | |
512 | Py_ssize_t i, nitems=ig->nitems;\r | |
513 | \r | |
514 | if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &obj))\r | |
515 | return NULL;\r | |
516 | if (nitems == 1)\r | |
517 | return PyObject_GetItem(obj, ig->item);\r | |
518 | \r | |
519 | assert(PyTuple_Check(ig->item));\r | |
520 | assert(PyTuple_GET_SIZE(ig->item) == nitems);\r | |
521 | \r | |
522 | result = PyTuple_New(nitems);\r | |
523 | if (result == NULL)\r | |
524 | return NULL;\r | |
525 | \r | |
526 | for (i=0 ; i < nitems ; i++) {\r | |
527 | PyObject *item, *val;\r | |
528 | item = PyTuple_GET_ITEM(ig->item, i);\r | |
529 | val = PyObject_GetItem(obj, item);\r | |
530 | if (val == NULL) {\r | |
531 | Py_DECREF(result);\r | |
532 | return NULL;\r | |
533 | }\r | |
534 | PyTuple_SET_ITEM(result, i, val);\r | |
535 | }\r | |
536 | return result;\r | |
537 | }\r | |
538 | \r | |
539 | PyDoc_STRVAR(itemgetter_doc,\r | |
540 | "itemgetter(item, ...) --> itemgetter object\n\\r | |
541 | \n\\r | |
542 | Return a callable object that fetches the given item(s) from its operand.\n\\r | |
543 | After f = itemgetter(2), the call f(r) returns r[2].\n\\r | |
544 | After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])");\r | |
545 | \r | |
546 | static PyTypeObject itemgetter_type = {\r | |
547 | PyVarObject_HEAD_INIT(NULL, 0)\r | |
548 | "operator.itemgetter", /* tp_name */\r | |
549 | sizeof(itemgetterobject), /* tp_basicsize */\r | |
550 | 0, /* tp_itemsize */\r | |
551 | /* methods */\r | |
552 | (destructor)itemgetter_dealloc, /* tp_dealloc */\r | |
553 | 0, /* tp_print */\r | |
554 | 0, /* tp_getattr */\r | |
555 | 0, /* tp_setattr */\r | |
556 | 0, /* tp_compare */\r | |
557 | 0, /* tp_repr */\r | |
558 | 0, /* tp_as_number */\r | |
559 | 0, /* tp_as_sequence */\r | |
560 | 0, /* tp_as_mapping */\r | |
561 | 0, /* tp_hash */\r | |
562 | (ternaryfunc)itemgetter_call, /* tp_call */\r | |
563 | 0, /* tp_str */\r | |
564 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
565 | 0, /* tp_setattro */\r | |
566 | 0, /* tp_as_buffer */\r | |
567 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
568 | itemgetter_doc, /* tp_doc */\r | |
569 | (traverseproc)itemgetter_traverse, /* tp_traverse */\r | |
570 | 0, /* tp_clear */\r | |
571 | 0, /* tp_richcompare */\r | |
572 | 0, /* tp_weaklistoffset */\r | |
573 | 0, /* tp_iter */\r | |
574 | 0, /* tp_iternext */\r | |
575 | 0, /* tp_methods */\r | |
576 | 0, /* tp_members */\r | |
577 | 0, /* tp_getset */\r | |
578 | 0, /* tp_base */\r | |
579 | 0, /* tp_dict */\r | |
580 | 0, /* tp_descr_get */\r | |
581 | 0, /* tp_descr_set */\r | |
582 | 0, /* tp_dictoffset */\r | |
583 | 0, /* tp_init */\r | |
584 | 0, /* tp_alloc */\r | |
585 | itemgetter_new, /* tp_new */\r | |
586 | 0, /* tp_free */\r | |
587 | };\r | |
588 | \r | |
589 | \r | |
590 | /* attrgetter object **********************************************************/\r | |
591 | \r | |
592 | typedef struct {\r | |
593 | PyObject_HEAD\r | |
594 | Py_ssize_t nattrs;\r | |
595 | PyObject *attr;\r | |
596 | } attrgetterobject;\r | |
597 | \r | |
598 | static PyTypeObject attrgetter_type;\r | |
599 | \r | |
600 | static PyObject *\r | |
601 | attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\r | |
602 | {\r | |
603 | attrgetterobject *ag;\r | |
604 | PyObject *attr;\r | |
605 | Py_ssize_t nattrs;\r | |
606 | \r | |
607 | if (!_PyArg_NoKeywords("attrgetter()", kwds))\r | |
608 | return NULL;\r | |
609 | \r | |
610 | nattrs = PyTuple_GET_SIZE(args);\r | |
611 | if (nattrs <= 1) {\r | |
612 | if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &attr))\r | |
613 | return NULL;\r | |
614 | } else\r | |
615 | attr = args;\r | |
616 | \r | |
617 | /* create attrgetterobject structure */\r | |
618 | ag = PyObject_GC_New(attrgetterobject, &attrgetter_type);\r | |
619 | if (ag == NULL)\r | |
620 | return NULL;\r | |
621 | \r | |
622 | Py_INCREF(attr);\r | |
623 | ag->attr = attr;\r | |
624 | ag->nattrs = nattrs;\r | |
625 | \r | |
626 | PyObject_GC_Track(ag);\r | |
627 | return (PyObject *)ag;\r | |
628 | }\r | |
629 | \r | |
630 | static void\r | |
631 | attrgetter_dealloc(attrgetterobject *ag)\r | |
632 | {\r | |
633 | PyObject_GC_UnTrack(ag);\r | |
634 | Py_XDECREF(ag->attr);\r | |
635 | PyObject_GC_Del(ag);\r | |
636 | }\r | |
637 | \r | |
638 | static int\r | |
639 | attrgetter_traverse(attrgetterobject *ag, visitproc visit, void *arg)\r | |
640 | {\r | |
641 | Py_VISIT(ag->attr);\r | |
642 | return 0;\r | |
643 | }\r | |
644 | \r | |
645 | static PyObject *\r | |
646 | dotted_getattr(PyObject *obj, PyObject *attr)\r | |
647 | {\r | |
648 | char *s, *p;\r | |
649 | \r | |
650 | #ifdef Py_USING_UNICODE\r | |
651 | if (PyUnicode_Check(attr)) {\r | |
652 | attr = _PyUnicode_AsDefaultEncodedString(attr, NULL);\r | |
653 | if (attr == NULL)\r | |
654 | return NULL;\r | |
655 | }\r | |
656 | #endif\r | |
657 | \r | |
658 | if (!PyString_Check(attr)) {\r | |
659 | PyErr_SetString(PyExc_TypeError,\r | |
660 | "attribute name must be a string");\r | |
661 | return NULL;\r | |
662 | }\r | |
663 | \r | |
664 | s = PyString_AS_STRING(attr);\r | |
665 | Py_INCREF(obj);\r | |
666 | for (;;) {\r | |
667 | PyObject *newobj, *str;\r | |
668 | p = strchr(s, '.');\r | |
669 | str = p ? PyString_FromStringAndSize(s, (p-s)) :\r | |
670 | PyString_FromString(s);\r | |
671 | if (str == NULL) {\r | |
672 | Py_DECREF(obj);\r | |
673 | return NULL;\r | |
674 | }\r | |
675 | newobj = PyObject_GetAttr(obj, str);\r | |
676 | Py_DECREF(str);\r | |
677 | Py_DECREF(obj);\r | |
678 | if (newobj == NULL)\r | |
679 | return NULL;\r | |
680 | obj = newobj;\r | |
681 | if (p == NULL) break;\r | |
682 | s = p+1;\r | |
683 | }\r | |
684 | \r | |
685 | return obj;\r | |
686 | }\r | |
687 | \r | |
688 | static PyObject *\r | |
689 | attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw)\r | |
690 | {\r | |
691 | PyObject *obj, *result;\r | |
692 | Py_ssize_t i, nattrs=ag->nattrs;\r | |
693 | \r | |
694 | if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &obj))\r | |
695 | return NULL;\r | |
696 | if (ag->nattrs == 1)\r | |
697 | return dotted_getattr(obj, ag->attr);\r | |
698 | \r | |
699 | assert(PyTuple_Check(ag->attr));\r | |
700 | assert(PyTuple_GET_SIZE(ag->attr) == nattrs);\r | |
701 | \r | |
702 | result = PyTuple_New(nattrs);\r | |
703 | if (result == NULL)\r | |
704 | return NULL;\r | |
705 | \r | |
706 | for (i=0 ; i < nattrs ; i++) {\r | |
707 | PyObject *attr, *val;\r | |
708 | attr = PyTuple_GET_ITEM(ag->attr, i);\r | |
709 | val = dotted_getattr(obj, attr);\r | |
710 | if (val == NULL) {\r | |
711 | Py_DECREF(result);\r | |
712 | return NULL;\r | |
713 | }\r | |
714 | PyTuple_SET_ITEM(result, i, val);\r | |
715 | }\r | |
716 | return result;\r | |
717 | }\r | |
718 | \r | |
719 | PyDoc_STRVAR(attrgetter_doc,\r | |
720 | "attrgetter(attr, ...) --> attrgetter object\n\\r | |
721 | \n\\r | |
722 | Return a callable object that fetches the given attribute(s) from its operand.\n\\r | |
723 | After f = attrgetter('name'), the call f(r) returns r.name.\n\\r | |
724 | After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\\r | |
725 | After h = attrgetter('name.first', 'name.last'), the call h(r) returns\n\\r | |
726 | (r.name.first, r.name.last).");\r | |
727 | \r | |
728 | static PyTypeObject attrgetter_type = {\r | |
729 | PyVarObject_HEAD_INIT(NULL, 0)\r | |
730 | "operator.attrgetter", /* tp_name */\r | |
731 | sizeof(attrgetterobject), /* tp_basicsize */\r | |
732 | 0, /* tp_itemsize */\r | |
733 | /* methods */\r | |
734 | (destructor)attrgetter_dealloc, /* tp_dealloc */\r | |
735 | 0, /* tp_print */\r | |
736 | 0, /* tp_getattr */\r | |
737 | 0, /* tp_setattr */\r | |
738 | 0, /* tp_compare */\r | |
739 | 0, /* tp_repr */\r | |
740 | 0, /* tp_as_number */\r | |
741 | 0, /* tp_as_sequence */\r | |
742 | 0, /* tp_as_mapping */\r | |
743 | 0, /* tp_hash */\r | |
744 | (ternaryfunc)attrgetter_call, /* tp_call */\r | |
745 | 0, /* tp_str */\r | |
746 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
747 | 0, /* tp_setattro */\r | |
748 | 0, /* tp_as_buffer */\r | |
749 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
750 | attrgetter_doc, /* tp_doc */\r | |
751 | (traverseproc)attrgetter_traverse, /* tp_traverse */\r | |
752 | 0, /* tp_clear */\r | |
753 | 0, /* tp_richcompare */\r | |
754 | 0, /* tp_weaklistoffset */\r | |
755 | 0, /* tp_iter */\r | |
756 | 0, /* tp_iternext */\r | |
757 | 0, /* tp_methods */\r | |
758 | 0, /* tp_members */\r | |
759 | 0, /* tp_getset */\r | |
760 | 0, /* tp_base */\r | |
761 | 0, /* tp_dict */\r | |
762 | 0, /* tp_descr_get */\r | |
763 | 0, /* tp_descr_set */\r | |
764 | 0, /* tp_dictoffset */\r | |
765 | 0, /* tp_init */\r | |
766 | 0, /* tp_alloc */\r | |
767 | attrgetter_new, /* tp_new */\r | |
768 | 0, /* tp_free */\r | |
769 | };\r | |
770 | \r | |
771 | \r | |
772 | /* methodcaller object **********************************************************/\r | |
773 | \r | |
774 | typedef struct {\r | |
775 | PyObject_HEAD\r | |
776 | PyObject *name;\r | |
777 | PyObject *args;\r | |
778 | PyObject *kwds;\r | |
779 | } methodcallerobject;\r | |
780 | \r | |
781 | static PyTypeObject methodcaller_type;\r | |
782 | \r | |
783 | static PyObject *\r | |
784 | methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\r | |
785 | {\r | |
786 | methodcallerobject *mc;\r | |
787 | PyObject *name, *newargs;\r | |
788 | \r | |
789 | if (PyTuple_GET_SIZE(args) < 1) {\r | |
790 | PyErr_SetString(PyExc_TypeError, "methodcaller needs at least "\r | |
791 | "one argument, the method name");\r | |
792 | return NULL;\r | |
793 | }\r | |
794 | \r | |
795 | /* create methodcallerobject structure */\r | |
796 | mc = PyObject_GC_New(methodcallerobject, &methodcaller_type);\r | |
797 | if (mc == NULL)\r | |
798 | return NULL;\r | |
799 | \r | |
800 | newargs = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));\r | |
801 | if (newargs == NULL) {\r | |
802 | Py_DECREF(mc);\r | |
803 | return NULL;\r | |
804 | }\r | |
805 | mc->args = newargs;\r | |
806 | \r | |
807 | name = PyTuple_GET_ITEM(args, 0);\r | |
808 | Py_INCREF(name);\r | |
809 | mc->name = name;\r | |
810 | \r | |
811 | Py_XINCREF(kwds);\r | |
812 | mc->kwds = kwds;\r | |
813 | \r | |
814 | PyObject_GC_Track(mc);\r | |
815 | return (PyObject *)mc;\r | |
816 | }\r | |
817 | \r | |
818 | static void\r | |
819 | methodcaller_dealloc(methodcallerobject *mc)\r | |
820 | {\r | |
821 | PyObject_GC_UnTrack(mc);\r | |
822 | Py_XDECREF(mc->name);\r | |
823 | Py_XDECREF(mc->args);\r | |
824 | Py_XDECREF(mc->kwds);\r | |
825 | PyObject_GC_Del(mc);\r | |
826 | }\r | |
827 | \r | |
828 | static int\r | |
829 | methodcaller_traverse(methodcallerobject *mc, visitproc visit, void *arg)\r | |
830 | {\r | |
831 | Py_VISIT(mc->args);\r | |
832 | Py_VISIT(mc->kwds);\r | |
833 | return 0;\r | |
834 | }\r | |
835 | \r | |
836 | static PyObject *\r | |
837 | methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw)\r | |
838 | {\r | |
839 | PyObject *method, *obj, *result;\r | |
840 | \r | |
841 | if (!PyArg_UnpackTuple(args, "methodcaller", 1, 1, &obj))\r | |
842 | return NULL;\r | |
843 | method = PyObject_GetAttr(obj, mc->name);\r | |
844 | if (method == NULL)\r | |
845 | return NULL;\r | |
846 | result = PyObject_Call(method, mc->args, mc->kwds);\r | |
847 | Py_DECREF(method);\r | |
848 | return result;\r | |
849 | }\r | |
850 | \r | |
851 | PyDoc_STRVAR(methodcaller_doc,\r | |
852 | "methodcaller(name, ...) --> methodcaller object\n\\r | |
853 | \n\\r | |
854 | Return a callable object that calls the given method on its operand.\n\\r | |
855 | After f = methodcaller('name'), the call f(r) returns r.name().\n\\r | |
856 | After g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\\r | |
857 | r.name('date', foo=1).");\r | |
858 | \r | |
859 | static PyTypeObject methodcaller_type = {\r | |
860 | PyVarObject_HEAD_INIT(NULL, 0)\r | |
861 | "operator.methodcaller", /* tp_name */\r | |
862 | sizeof(methodcallerobject), /* tp_basicsize */\r | |
863 | 0, /* tp_itemsize */\r | |
864 | /* methods */\r | |
865 | (destructor)methodcaller_dealloc, /* tp_dealloc */\r | |
866 | 0, /* tp_print */\r | |
867 | 0, /* tp_getattr */\r | |
868 | 0, /* tp_setattr */\r | |
869 | 0, /* tp_compare */\r | |
870 | 0, /* tp_repr */\r | |
871 | 0, /* tp_as_number */\r | |
872 | 0, /* tp_as_sequence */\r | |
873 | 0, /* tp_as_mapping */\r | |
874 | 0, /* tp_hash */\r | |
875 | (ternaryfunc)methodcaller_call, /* tp_call */\r | |
876 | 0, /* tp_str */\r | |
877 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
878 | 0, /* tp_setattro */\r | |
879 | 0, /* tp_as_buffer */\r | |
880 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */\r | |
881 | methodcaller_doc, /* tp_doc */\r | |
882 | (traverseproc)methodcaller_traverse, /* tp_traverse */\r | |
883 | 0, /* tp_clear */\r | |
884 | 0, /* tp_richcompare */\r | |
885 | 0, /* tp_weaklistoffset */\r | |
886 | 0, /* tp_iter */\r | |
887 | 0, /* tp_iternext */\r | |
888 | 0, /* tp_methods */\r | |
889 | 0, /* tp_members */\r | |
890 | 0, /* tp_getset */\r | |
891 | 0, /* tp_base */\r | |
892 | 0, /* tp_dict */\r | |
893 | 0, /* tp_descr_get */\r | |
894 | 0, /* tp_descr_set */\r | |
895 | 0, /* tp_dictoffset */\r | |
896 | 0, /* tp_init */\r | |
897 | 0, /* tp_alloc */\r | |
898 | methodcaller_new, /* tp_new */\r | |
899 | 0, /* tp_free */\r | |
900 | };\r | |
901 | \r | |
902 | \r | |
903 | /* Initialization function for the module (*must* be called initoperator) */\r | |
904 | \r | |
905 | PyMODINIT_FUNC\r | |
906 | initoperator(void)\r | |
907 | {\r | |
908 | PyObject *m;\r | |
909 | \r | |
910 | /* Create the module and add the functions */\r | |
911 | m = Py_InitModule4("operator", operator_methods, operator_doc,\r | |
912 | (PyObject*)NULL, PYTHON_API_VERSION);\r | |
913 | if (m == NULL)\r | |
914 | return;\r | |
915 | \r | |
916 | if (PyType_Ready(&itemgetter_type) < 0)\r | |
917 | return;\r | |
918 | Py_INCREF(&itemgetter_type);\r | |
919 | PyModule_AddObject(m, "itemgetter", (PyObject *)&itemgetter_type);\r | |
920 | \r | |
921 | if (PyType_Ready(&attrgetter_type) < 0)\r | |
922 | return;\r | |
923 | Py_INCREF(&attrgetter_type);\r | |
924 | PyModule_AddObject(m, "attrgetter", (PyObject *)&attrgetter_type);\r | |
925 | \r | |
926 | if (PyType_Ready(&methodcaller_type) < 0)\r | |
927 | return;\r | |
928 | Py_INCREF(&methodcaller_type);\r | |
929 | PyModule_AddObject(m, "methodcaller", (PyObject *)&methodcaller_type);\r | |
930 | }\r |