Library of Assembled Shared Sources
py_tuple.h
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2025 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_PY_TUPLE_H
44#define LASS_GUARDIAN_OF_INCLUSION_UTIL_PY_TUPLE_H
45
46#include "python_common.h"
47#include "pyobject_plus.h"
48#include <utility>
49#include <tuple>
50
51#if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
52# pragma warning(push)
53# pragma warning(disable: 4267) // conversion from 'size_t' to 'unsigned int', possible loss of data
54#endif
55
56namespace lass
57{
58namespace python
59{
60namespace impl
61{
62 /** @ingroup Python
63 * @internal
64 */
65 template <typename P>
66 inline bool tupleSetItems(PyObject* tuple, Py_ssize_t index, const P& p)
67 {
68 return PyTuple_SetItem(tuple, index, pyBuildSimpleObject(p)) == 0;
69 }
70
71 /** @ingroup Python
72 * @internal
73 */
74 template <typename P, typename... Ptail>
75 inline bool tupleSetItems(PyObject* tuple, Py_ssize_t index, const P& p, Ptail&... tail)
76 {
77 return PyTuple_SetItem(tuple, index, pyBuildSimpleObject(p)) == 0
78 && tupleSetItems(tuple, index + 1, tail...);
79 }
80
81 /** @ingroup Python
82 * @internal
83 */
84 template <typename P>
85 inline bool decodeObject(PyObject* in, Py_ssize_t index, P& out)
86 {
87 if (lass::python::pyGetSimpleObject(in, out) != 0)
88 {
89 std::ostringstream buffer;
90 buffer << "Bad Argument on " << (index + 1) << "th position";
91 impl::addMessageHeader(buffer.str().c_str());
92 return false;
93 }
94 return true;
95 }
96
97 /** @ingroup Python
98 * @internal
99 */
100 template <typename P>
101 inline bool decodeObjects(PyObject** objects, Py_ssize_t index, P& p)
102 {
103 return impl::decodeObject(objects[index], index, p);
104 }
105
106 /** @ingroup Python
107 * @internal
108 */
109 template <typename P, typename... Ptail>
110 inline bool decodeObjects(PyObject** objects, Py_ssize_t index, P& p, Ptail&... tail)
111 {
112 return impl::decodeObject(objects[index], index, p)
113 && decodeObjects(objects, index + 1, tail...);
114 }
115
116 /** @ingroup Python
117 * @internal
118 */
119 template <typename P>
120 inline bool decodeObjectsMinimum(PyObject** objects, Py_ssize_t index, Py_ssize_t size, P& p)
121 {
122 return index >= size
123 || impl::decodeObject(objects[index], index, p);
124 }
125
126 /** @ingroup Python
127 * @internal
128 */
129 template <typename P, typename... Ptail>
130 inline bool decodeObjectsMinimum(PyObject** objects, Py_ssize_t index, Py_ssize_t size, P& p, Ptail&... tail)
131 {
132 return index >= size
133 || (impl::decodeObject(objects[index], index, p)
134 && decodeObjectsMinimum(objects, index + 1, size, tail...));
135 }
136}
137
138
139
140/** @ingroup Python
141 */
142inline const TPyObjPtr makeTuple()
143{
144 return TPyObjPtr(PyTuple_New(0));
145}
146
147/** @ingroup Python
148 */
149template <typename... P>
150const TPyObjPtr makeTuple(const P&... p)
151{
152 LockGIL LASS_UNUSED(lock);
153 TPyObjPtr tuple(PyTuple_New(sizeof...(P)));
154 return impl::tupleSetItems(tuple.get(), 0, p...)
155 ? tuple
156 : TPyObjPtr();
157}
158
159
160
161/** @ingroup Python
162 */
163inline int decodeTuple(PyObject* obj)
164{
165 LASS_ASSERT(obj);
166 return impl::checkSequenceSize(obj, 0) ? 0 : 1;
167}
168
169/** @ingroup Python
170 */
171template <typename... P>
172int decodeTuple(PyObject* obj, P&... p)
173{
174 LockGIL LASS_UNUSED(lock);
175 const TPyObjPtr tuple = impl::checkedFastSequence(obj, sizeof...(P));
176 if (!tuple)
177 {
178 return 1;
179 }
180 PyObject** objects = PySequence_Fast_ITEMS(tuple.get());
181 return impl::decodeObjects(objects, 0, p...)
182 ? 0
183 : 1;
184}
185
186
187
188/** @ingroup Python
189 */
190inline int decodeTuple(const TPyObjPtr& obj)
191{
192 return decodeTuple(obj.get());
193}
194
195/** @ingroup Python
196 */
197template <typename... P>
198inline int decodeTuple(const TPyObjPtr& obj, P&... p)
199{
200 return decodeTuple(obj.get(), p...);
201}
202
203
204
205/** @ingroup Python
206 */
207template <typename... P>
208int decodeTupleMinimum(PyObject* obj, Py_ssize_t minumumLength, P&... p)
209{
210 LockGIL LASS_UNUSED(lock);
211 const TPyObjPtr tuple = impl::checkedFastSequence(obj, minumumLength, sizeof...(P));
212 if (!tuple)
213 {
214 return 1;
215 }
216 const Py_ssize_t size = PySequence_Fast_GET_SIZE(tuple.get());
217 PyObject** objects = PySequence_Fast_ITEMS(tuple.get());
218 return impl::decodeObjectsMinimum(objects, 0, size, p...)
219 ? 0
220 : 1;
221}
222
223
224
225/** @ingroup Python
226 */
227template <typename... P>
228int decodeTupleMinimum(const TPyObjPtr& obj, Py_ssize_t minumumLength, P&... p)
229{
230 return decodeTupleMinimum(obj.get(), minumumLength, p...);
231}
232
233
234
235// --- pairs ---------------------------------------------------------------------------------------
236
237/** std::pair translates to a tuple by copy.
238 * @ingroup PyExportTraits
239 */
240template <typename T1, typename T2>
241struct PyExportTraits< std::pair<T1, T2> >
242{
243 constexpr static const char* py_typing = "tuple[T1, T2]";
244
245 static PyObject* build(const std::pair<T1, T2>& v)
246 {
247 return fromSharedPtrToNakedCast(makeTuple(v.first, v.second));
248
249 }
250 static int get(PyObject* obj, std::pair<T1, T2>& v)
251 {
252 if (decodeTuple(obj, v.first, v.second) != 0)
253 {
255 return 1;
256 }
257 return 0;
258 }
259};
260
261
262/** std::tuple translates to a tuple by copy.
263 * @ingroup PyExportTraits
264 */
265template <typename... T>
266struct PyExportTraits< std::tuple<T...> >
267{
268 constexpr static const char* py_typing = "tuple[T...]";
269
270 static PyObject* build(const std::tuple<T...>& v)
271 {
272 return doBuild(v, std::index_sequence_for<T...>());
273 }
274 static int get(PyObject* obj, std::tuple<T...>& v)
275 {
276 return doGet(obj, v, std::index_sequence_for<T...>());
277 }
278
279private:
280 template <std::size_t... I>
281 static PyObject* doBuild(const std::tuple<T...>& v, std::index_sequence<I...>)
282 {
283 return fromSharedPtrToNakedCast(makeTuple(std::get<I>(v)...));
284 }
285 template <std::size_t... I>
286 static int doGet(PyObject* obj, std::tuple<T...>& v, std::index_sequence<I...>)
287 {
288 if (decodeTuple(obj, std::get<I>(v)...) != 0)
289 {
290 impl::addMessageHeader("tuple");
291 return 1;
292 }
293 return 0;
294 }
295};
296
297}
298
299}
300
301#if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
302# pragma warning(pop)
303#endif
304
305#endif
306
307// EOF
acquire the GIL for the current scope.
Definition gil.h:56
void addMessageHeader(const char *header)
Prepend a message to the current Python exception value.
PyObjectPtr< PyObject >::Type TPyObjPtr
PyObjectPtr to a PyObject.
PyObject * fromSharedPtrToNakedCast(const util::SharedPtr< T, PyObjectStorage, PyObjectCounter > &object)
fromSharedPtrToNakedCast.
Comprehensive C++ to Python binding library.
Library for Assembled Shared Sources.
Definition config.h:53
by copy, general case assumes shadow type or PyObjectPlus based type.