Nuitka
The Python compiler
Loading...
Searching...
No Matches
HelpersOperationBinaryMultUtils.c
1// Copyright 2025, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
3/* These slots are still manually coded and are used by the generated code.
4 *
5 * The plan should be to generate these as well, so e.g. we can have a slot
6 * SLOT_nb_multiply_LONG_INT that is optimal too.
7 */
8
9// This file is included from another C file, help IDEs to still parse it on
10// its own.
11#ifdef __IDE_ONLY__
12#include "nuitka/prelude.h"
13#endif
14
15static Py_ssize_t CONVERT_LONG_TO_REPEAT_FACTOR(PyObject *value) {
16 /* Inline PyLong_AsSsize_t here for our special purpose. */
17 assert(PyLong_Check(value));
18
19 Py_ssize_t digits_count = Nuitka_LongGetDigitSize(value);
20
21 if (digits_count == 0) {
22 return 0;
23 }
24
25 bool is_negative = Nuitka_LongIsNegative(value);
26
27 PyLongObject *long_value = (PyLongObject *)value;
28
29 digit *digits = Nuitka_LongGetDigitPointer(long_value);
30
31 if ((digits_count == 1) && (is_negative == false)) {
32 return digits[0];
33 }
34
35 Py_ssize_t result = 0;
36
37 while (--digits_count >= 0) {
38 Py_ssize_t prev = result;
39 result = (result << PyLong_SHIFT) | digits[digits_count];
40
41 // Overflow detection.
42 if ((result >> PyLong_SHIFT) != prev) {
43 return (Py_ssize_t)-1;
44 }
45 }
46
47 if (is_negative) {
48 return 0;
49 }
50
51 return result;
52}
53
54static Py_ssize_t CONVERT_TO_REPEAT_FACTOR(PyObject *value) {
55#if PYTHON_VERSION < 0x300
56 assert(PyInt_Check(value) || PyLong_Check(value));
57
58 if (PyInt_Check(value)) {
59 Py_ssize_t result = PyInt_AS_LONG(value);
60
61 /* A -1 value could indicate error, so we avoid it. */
62 if (result < 0) {
63 return 0;
64 } else {
65 return result;
66 }
67 } else {
68 return CONVERT_LONG_TO_REPEAT_FACTOR(value);
69 }
70#else
71 /* For Python3 we know for a fact that it's a long, or else it's an
72 * exception.
73 */
74 assert(PyLong_Check(value));
75
76 return CONVERT_LONG_TO_REPEAT_FACTOR(value);
77#endif
78}
79
80static PyObject *SEQUENCE_REPEAT(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) {
81 if (unlikely(!Nuitka_Index_Check(n))) {
82 PyErr_Format(PyExc_TypeError, "can't multiply sequence by non-int of type '%s'", Py_TYPE(n)->tp_name);
83
84 return NULL;
85 }
86
87 PyObject *index_value = Nuitka_Number_Index(n);
88
89 if (unlikely(index_value == NULL)) {
90 return NULL;
91 }
92
93 Py_ssize_t count = CONVERT_TO_REPEAT_FACTOR(index_value);
94
95 Py_DECREF(index_value);
96
97 /* Above conversion indicates an error as -1 */
98 if (unlikely(count == -1)) {
99 PyErr_Format(PyExc_OverflowError, "cannot fit '%s' into an index-sized integer", Py_TYPE(n)->tp_name);
100 return NULL;
101 }
102
103 PyObject *result = (*repeatfunc)(seq, count);
104
105 if (unlikely(result == NULL)) {
106 return NULL;
107 }
108
109 return result;
110}
111
112// Part of "Nuitka", an optimizing Python compiler that is compatible and
113// integrates with CPython, but also works on its own.
114//
115// Licensed under the Apache License, Version 2.0 (the "License");
116// you may not use this file except in compliance with the License.
117// You may obtain a copy of the License at
118//
119// http://www.apache.org/licenses/LICENSE-2.0
120//
121// Unless required by applicable law or agreed to in writing, software
122// distributed under the License is distributed on an "AS IS" BASIS,
123// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124// See the License for the specific language governing permissions and
125// limitations under the License.