this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "cpython-func.h"
3
4#include "api-handle.h"
5#include "runtime.h"
6#include "slice-builtins.h"
7
8namespace py {
9
10PY_EXPORT int PySlice_Check_Func(PyObject* pyobj) {
11 return ApiHandle::asObject(ApiHandle::fromPyObject(pyobj)).isSlice();
12}
13
14PY_EXPORT PyObject* PySlice_New(PyObject* start, PyObject* stop,
15 PyObject* step) {
16 Thread* thread = Thread::current();
17 HandleScope scope(thread);
18 Object start_obj(&scope, NoneType::object());
19 Object stop_obj(&scope, NoneType::object());
20 Object step_obj(&scope, NoneType::object());
21 if (start != nullptr) {
22 start_obj = ApiHandle::asObject(ApiHandle::fromPyObject(start));
23 }
24 if (stop != nullptr) {
25 stop_obj = ApiHandle::asObject(ApiHandle::fromPyObject(stop));
26 }
27 if (step != nullptr) {
28 step_obj = ApiHandle::asObject(ApiHandle::fromPyObject(step));
29 }
30 Runtime* runtime = thread->runtime();
31 return ApiHandle::newReferenceWithManaged(
32 runtime, runtime->newSlice(start_obj, stop_obj, step_obj));
33}
34
35PY_EXPORT PyTypeObject* PySlice_Type_Ptr() {
36 Runtime* runtime = Thread::current()->runtime();
37 return reinterpret_cast<PyTypeObject*>(
38 ApiHandle::borrowedReference(runtime, runtime->typeAt(LayoutId::kSlice)));
39}
40
41PY_EXPORT Py_ssize_t PySlice_AdjustIndices(Py_ssize_t length,
42 Py_ssize_t* start_ptr,
43 Py_ssize_t* stop_ptr,
44 Py_ssize_t step) {
45 DCHECK(step != 0, "step cannot be 0");
46 DCHECK(step >= -SmallInt::kMaxValue, "step must allow for safe reversal");
47 DCHECK(length >= 0, "length cannot be negative");
48 word start = static_cast<word>(*start_ptr);
49 word stop = static_cast<word>(*stop_ptr);
50 word slice_length = RawSlice::adjustIndices(static_cast<word>(length), &start,
51 &stop, static_cast<word>(step));
52 *start_ptr = static_cast<Py_ssize_t>(start);
53 *stop_ptr = static_cast<Py_ssize_t>(stop);
54 return static_cast<Py_ssize_t>(slice_length);
55}
56
57PY_EXPORT int PySlice_GetIndices(PyObject*, Py_ssize_t, Py_ssize_t*,
58 Py_ssize_t*, Py_ssize_t*) {
59 UNIMPLEMENTED("PySlice_GetIndices is not supported");
60}
61
62PY_EXPORT int PySlice_GetIndicesEx(PyObject* slice, Py_ssize_t length,
63 Py_ssize_t* start, Py_ssize_t* stop,
64 Py_ssize_t* step, Py_ssize_t* slicelength) {
65 if (PySlice_Unpack(slice, start, stop, step) < 0) {
66 return -1;
67 }
68 *slicelength = PySlice_AdjustIndices(length, start, stop, *step);
69 return 0;
70}
71
72PY_EXPORT int PySlice_Unpack(PyObject* pyobj, Py_ssize_t* start_ptr,
73 Py_ssize_t* stop_ptr, Py_ssize_t* step_ptr) {
74 DCHECK(SmallInt::kMinValue + 1 == -SmallInt::kMaxValue,
75 "expected two's complement SmallInt (got min %ld, max %ld)",
76 SmallInt::kMinValue, SmallInt::kMaxValue);
77 Thread* thread = Thread::current();
78 HandleScope scope(thread);
79 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyobj)));
80 if (!obj.isSlice()) {
81 thread->raiseBadInternalCall();
82 return -1;
83 }
84
85 Slice slice(&scope, *obj);
86 Runtime* runtime = thread->runtime();
87
88 word step = 1;
89 Object step_obj(&scope, slice.step());
90 if (!step_obj.isNoneType()) {
91 if (!runtime->isInstanceOfInt(*step_obj)) {
92 step_obj =
93 thread->invokeFunction1(ID(builtins), ID(_slice_index), step_obj);
94 if (step_obj.isError()) return -1;
95 }
96 step = intUnderlying(*step_obj).asWordSaturated();
97 if (step == 0) {
98 thread->raiseWithFmt(LayoutId::kValueError, "slice step cannot be zero");
99 return -1;
100 }
101 if (step <= SmallInt::kMinValue) {
102 // Here *step might be -SmallInt::kMaxValue - 1. In that case, we replace
103 // it with -SmallInt::kMaxValue. This doesn't affect the semantics, and it
104 // guards against later undefined behaviour resulting from code that does
105 // "step = -step" as part of a slice reversal.
106 step = -SmallInt::kMaxValue;
107 } else if (step > SmallInt::kMaxValue) {
108 step = SmallInt::kMaxValue;
109 }
110 }
111
112 word start;
113 Object start_obj(&scope, slice.start());
114 if (start_obj.isNoneType()) {
115 start = step < 0 ? SmallInt::kMaxValue : 0;
116 } else {
117 if (!runtime->isInstanceOfInt(*start_obj)) {
118 start_obj =
119 thread->invokeFunction1(ID(builtins), ID(_slice_index), start_obj);
120 if (start_obj.isError()) return -1;
121 }
122 start = intUnderlying(*start_obj).asWordSaturated();
123 if (start < SmallInt::kMinValue) {
124 start = SmallInt::kMinValue;
125 } else if (start > SmallInt::kMaxValue) {
126 start = SmallInt::kMaxValue;
127 }
128 }
129
130 word stop;
131 Object stop_obj(&scope, slice.stop());
132 if (stop_obj.isNoneType()) {
133 stop = step < 0 ? SmallInt::kMinValue : SmallInt::kMaxValue;
134 } else {
135 if (!runtime->isInstanceOfInt(*stop_obj)) {
136 stop_obj =
137 thread->invokeFunction1(ID(builtins), ID(_slice_index), stop_obj);
138 if (stop_obj.isError()) return -1;
139 }
140 stop = intUnderlying(*stop_obj).asWordSaturated();
141 if (stop < SmallInt::kMinValue) {
142 stop = SmallInt::kMinValue;
143 } else if (stop > SmallInt::kMaxValue) {
144 stop = SmallInt::kMaxValue;
145 }
146 }
147
148 *start_ptr = static_cast<Py_ssize_t>(start);
149 *stop_ptr = static_cast<Py_ssize_t>(stop);
150 *step_ptr = static_cast<Py_ssize_t>(step);
151 return 0;
152}
153
154} // namespace py