this repo has no description
at trunk 154 lines 5.5 kB view raw
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