this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2// tupleobject.c implementation
3
4#include <cstdarg>
5
6#include "api-handle.h"
7#include "objects.h"
8#include "runtime.h"
9#include "tuple-builtins.h"
10
11namespace py {
12
13PY_EXPORT PyTypeObject* PyTupleIter_Type_Ptr() {
14 Runtime* runtime = Thread::current()->runtime();
15 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference(
16 runtime, runtime->typeAt(LayoutId::kTupleIterator)));
17}
18
19PY_EXPORT PyObject* PyTuple_New(Py_ssize_t length) {
20 Runtime* runtime = Thread::current()->runtime();
21 if (length == 0) {
22 return ApiHandle::newReferenceWithManaged(runtime, runtime->emptyTuple());
23 }
24 RawMutableTuple tuple = MutableTuple::cast(runtime->newMutableTuple(length));
25 tuple.fill(NoneType::object());
26 return ApiHandle::newReferenceWithManaged(runtime, tuple.becomeImmutable());
27}
28
29PY_EXPORT int PyTuple_CheckExact_Func(PyObject* obj) {
30 return ApiHandle::asObject(ApiHandle::fromPyObject(obj)).isTuple();
31}
32
33PY_EXPORT int PyTuple_Check_Func(PyObject* obj) {
34 return Thread::current()->runtime()->isInstanceOfTuple(
35 ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
36}
37
38PY_EXPORT PyObject* PyTuple_GET_ITEM_Func(PyObject* pytuple, Py_ssize_t pos) {
39 Runtime* runtime = Thread::current()->runtime();
40 RawObject obj = ApiHandle::asObjectNoImmediate(ApiHandle::fromPyObject(pytuple));
41 DCHECK(runtime->isInstanceOfTuple(obj),
42 "non-tuple argument to PyTuple_GET_ITEM");
43 RawTuple tuple = tupleUnderlying(obj);
44 DCHECK_INDEX(pos, tuple.length());
45 return ApiHandle::borrowedReference(runtime, tuple.at(pos));
46}
47
48PY_EXPORT Py_ssize_t PyTuple_GET_SIZE_Func(PyObject* pytuple) {
49 RawObject obj = ApiHandle::asObjectNoImmediate(ApiHandle::fromPyObject(pytuple));
50 DCHECK(Thread::current()->runtime()->isInstanceOfTuple(obj),
51 "non-tuple argument to PyTuple_GET_SIZE");
52 return tupleUnderlying(obj).length();
53}
54
55PY_EXPORT PyObject* PyTuple_GetItem(PyObject* pytuple, Py_ssize_t pos) {
56 Thread* thread = Thread::current();
57 Runtime* runtime = thread->runtime();
58 RawObject obj = ApiHandle::asObject(ApiHandle::fromPyObject(pytuple));
59 if (!runtime->isInstanceOfTuple(obj)) {
60 thread->raiseBadInternalCall();
61 return nullptr;
62 }
63
64 RawTuple tuple = tupleUnderlying(obj);
65 if (pos < 0 || pos >= tuple.length()) {
66 thread->raiseWithFmt(LayoutId::kIndexError, "tuple index out of range");
67 return nullptr;
68 }
69
70 return ApiHandle::borrowedReference(runtime, tuple.at(pos));
71}
72
73PY_EXPORT PyObject* PyTuple_SET_ITEM_Func(PyObject* pytuple, Py_ssize_t pos,
74 PyObject* pyitem) {
75 RawObject obj = ApiHandle::asObjectNoImmediate(ApiHandle::fromPyObject(pytuple));
76 RawObject item = pyitem == nullptr ? NoneType::object()
77 : ApiHandle::stealReference(pyitem);
78 DCHECK(Thread::current()->runtime()->isInstanceOfTuple(obj),
79 "non-tuple argument to PyTuple_SET_ITEM");
80 RawTuple tuple = tupleUnderlying(obj);
81 DCHECK_INDEX(pos, tuple.length());
82 tuple.atPut(pos, item);
83 return pyitem;
84}
85
86PY_EXPORT int PyTuple_SetItem(PyObject* pytuple, Py_ssize_t pos,
87 PyObject* pyitem) {
88 Thread* thread = Thread::current();
89 Runtime* runtime = thread->runtime();
90 RawObject obj = ApiHandle::asObject(ApiHandle::fromPyObject(pytuple));
91 RawObject item = pyitem == nullptr ? NoneType::object()
92 : ApiHandle::stealReference(pyitem);
93 if (!runtime->isInstanceOfTuple(obj)) {
94 thread->raiseBadInternalCall();
95 return -1;
96 }
97
98 RawTuple tuple = tupleUnderlying(obj);
99 if (pos < 0 || pos >= tuple.length()) {
100 thread->raiseWithFmt(LayoutId::kIndexError,
101 "tuple assignment index out of range");
102 return -1;
103 }
104
105 tuple.atPut(pos, item);
106 return 0;
107}
108
109PY_EXPORT Py_ssize_t PyTuple_Size(PyObject* pytuple) {
110 Thread* thread = Thread::current();
111 Runtime* runtime = thread->runtime();
112 RawObject obj = ApiHandle::asObject(ApiHandle::fromPyObject(pytuple));
113 if (!runtime->isInstanceOfTuple(obj)) {
114 thread->raiseBadInternalCall();
115 return -1;
116 }
117 return tupleUnderlying(obj).length();
118}
119
120PY_EXPORT PyTypeObject* PyTuple_Type_Ptr() {
121 Runtime* runtime = Thread::current()->runtime();
122 return reinterpret_cast<PyTypeObject*>(
123 ApiHandle::borrowedReference(runtime, runtime->typeAt(LayoutId::kTuple)));
124}
125
126PY_EXPORT PyObject* PyTuple_Pack(Py_ssize_t n, ...) {
127 Thread* thread = Thread::current();
128 Runtime* runtime = thread->runtime();
129 if (n == 0) {
130 return ApiHandle::newReferenceWithManaged(runtime, runtime->emptyTuple());
131 }
132
133 HandleScope scope(thread);
134 va_list vargs;
135 va_start(vargs, n);
136 MutableTuple tuple(&scope, runtime->newMutableTuple(n));
137 for (Py_ssize_t i = 0; i < n; i++) {
138 PyObject* item = va_arg(vargs, PyObject*);
139 tuple.atPut(i, ApiHandle::asObject(ApiHandle::fromPyObject(item)));
140 }
141 va_end(vargs);
142 return ApiHandle::newReferenceWithManaged(runtime, tuple.becomeImmutable());
143}
144
145PY_EXPORT PyObject* PyTuple_GetSlice(PyObject* pytuple, Py_ssize_t low,
146 Py_ssize_t high) {
147 Thread* thread = Thread::current();
148 if (pytuple == nullptr) {
149 thread->raiseBadInternalCall();
150 return nullptr;
151 }
152 Runtime* runtime = thread->runtime();
153 HandleScope scope(thread);
154 Object tuple_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pytuple)));
155 if (!runtime->isInstanceOfTuple(*tuple_obj)) {
156 thread->raiseBadInternalCall();
157 return nullptr;
158 }
159 Tuple tuple(&scope, tupleUnderlying(*tuple_obj));
160 word len = tuple.length();
161 if (low < 0) {
162 low = 0;
163 } else if (low > len) {
164 low = len;
165 }
166 if (high < low) {
167 high = low;
168 } else if (high > len) {
169 high = len;
170 }
171 if (low == 0 && high == len && tuple_obj.isTuple()) {
172 return ApiHandle::newReferenceWithManaged(runtime, *tuple);
173 }
174 return ApiHandle::newReferenceWithManaged(
175 runtime, runtime->tupleSubseq(thread, tuple, low, high - low));
176}
177
178} // namespace py