Library of Assembled Shared Sources
 
Loading...
Searching...
No Matches
pymap.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-2026 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_PYMAP_H
44#define LASS_GUARDIAN_OF_INCLUSION_UTIL_PYMAP_H
45
46#include "python_common.h"
47#include "pyshadow_object.h"
48#include "pyiteratorrange.h"
49#include "container.h"
50#include "pyobject_util.h"
51#include "argument_traits.h"
52#include <map>
54#include "../meta/type_traits.h"
55
56namespace lass
57{
58namespace python
59{
60namespace impl
61{
62 class LASS_PYTHON_DLL PyMapImplBase: public ContainerImplBase
63 {
64 public:
65 typedef std::unique_ptr<PyMapImplBase> TPimpl;
66 using ContainerImplBase::ContainerImplBase;
67 virtual TPimpl copy() const = 0;
68 virtual PyObject* subscript(PyObject* key) const = 0;
69 virtual int assSubscript(PyObject* key, PyObject* value) = 0;
70 virtual PyObject* keys() const = 0;
71 virtual PyObject* values() const = 0;
72 };
73
74 template<typename Container>
75 class PyMapImpl: public ContainerImpl<Container, PyMapImplBase>
76 {
77 public:
78 typedef ContainerImpl<Container, PyMapImplBase> TBase;
79 typedef typename TBase::TContainerPtr TContainerPtr;
80 typedef typename TBase::TConstContainerPtr TConstContainerPtr;
81 typedef typename TBase::TContainerTraits TContainerTraits;
82 typedef PyMapImplBase::TPimpl TPimpl;
83 typedef ArgumentTraits<typename Container::key_type> TKeyArgTraits;
84 typedef ArgumentTraits<typename Container::mapped_type> TMappedArgTraits;
85
86 PyMapImpl(const TContainerPtr& container, bool readOnly = false):
87 TBase(container, readOnly)
88 {
89 }
90 TPimpl copy() const override
91 {
92 TContainerPtr copy = TContainerTraits::copy(this->container());
93 return TPimpl(new PyMapImpl(copy));
94 }
95 PyObject* subscript(PyObject* key) const override
96 {
97 LockGIL lock;
98 typename TKeyArgTraits::TStorage k;
99 if (pyGetSimpleObject(key, k) != 0)
100 {
101 PyErr_SetObject(PyExc_KeyError, key);
102 return 0;
103 }
104 auto it = this->container().find(TKeyArgTraits::arg(k));
105 if (it == this->container().end())
106 {
107 PyErr_SetObject(PyExc_KeyError, key);
108 return 0;
109 }
110 return pyBuildSimpleObject(it->second);
111 }
112 int assSubscript(PyObject* key, PyObject* value) override
113 {
114 LockGIL lock;
115 if (!this->checkWritable())
116 {
117 return -1;
118 }
119 if (value)
120 {
121 typename TKeyArgTraits::TStorage k;
122 if (pyGetSimpleObject(key, k) != 0)
123 {
125 return -1;
126 }
127 typename TMappedArgTraits::TStorage v;
128 if (pyGetSimpleObject(value, v) != 0)
129 {
130 impl::addMessageHeader("value");
131 return -1;
132 }
133 this->container().insert_or_assign(TKeyArgTraits::arg(k), TMappedArgTraits::arg(v));
134 }
135 else
136 {
137 typename TKeyArgTraits::TStorage k;
138 if (pyGetSimpleObject(key, k) != 0)
139 {
140 PyErr_SetObject(PyExc_KeyError, key);
141 return -1;
142 }
143 auto it = this->container().find(TKeyArgTraits::arg(k));
144 if (it == this->container().end())
145 {
146 PyErr_SetObject(PyExc_KeyError, key);
147 return -1;
148 }
149 this->container().erase(it);
150 }
151 return 0;
152 }
153 PyObject* keys() const override
154 {
155 return new PyIteratorRange(
156 stde::first_iterator(this->container().begin()), stde::first_iterator(this->container().end()));
157 }
158 PyObject* values() const override
159 {
160 return new PyIteratorRange(
161 stde::second_iterator(this->container().begin()), stde::second_iterator(this->container().end()));
162 }
163 const TPyObjPtr asNative() const override
164 {
165 return pyBuildMap(this->container().begin(), this->container().end());
166 }
167 };
168
169 class Map;
170 typedef PyObjectPtr<Map>::Type TMapPtr;
171
172 /** Map. Object for interfacing maps with Python
173 */
174 class LASS_PYTHON_DLL Map : public PyObjectPlus, util::NonCopyable
175 {
176 PY_HEADER(PyObjectPlus)
177 public:
178 template <typename Container> Map( const util::SharedPtr<Container>& container )
179 {
180 TPimpl pimpl(new PyMapImpl<Container>(
181 LASS_ENFORCE_POINTER(container)));
182 init(std::move(pimpl));
183 }
184 template<typename Container> Map( const util::SharedPtr<const Container>& container )
185 {
186 TPimpl pimpl(new PyMapImpl<Container>(
187 (LASS_ENFORCE_POINTER(container)).template constCast<Container>(), true));
188 init(std::move(pimpl));
189 }
190 template<typename Container> Map( const Container& container )
191 {
192 util::SharedPtr<Container> p(new Container(container));
193 TPimpl pimpl(new PyMapImpl<Container>(p, true));
194 init(std::move(pimpl));
195 }
196 ~Map();
197
198 std::string repr() const;
199 const TPyObjPtr keys() const;
200 const TPyObjPtr values() const;
201 const TPyObjPtr items() const;
202 const TPyObjPtr iter() const;
203 const TPyObjPtr get(const TPyObjPtr& key, const TPyObjPtr& defaultValue) const;
204 const TPyObjPtr getOrNone(const TPyObjPtr& key) const;
205 void clear();
206 const TMapPtr copy() const;
207 const TPyObjPtr asDict() const;
208
209 const std::type_info& type() const;
210 void* raw(bool writable) const;
211
212 static Py_ssize_t length(PyObject* self);
213 static PyObject* subscript(PyObject* self, PyObject* key);
214 static int assSubscript(PyObject* self, PyObject* key, PyObject* value);
215
216 private:
217 typedef PyMapImplBase::TPimpl TPimpl;
218
219 Map(TPimpl&& pimpl);
220 void init(TPimpl&& pimpl);
221
222 TPimpl pimpl_;
223 };
224
225 template <>
226 struct ShadowTraits<Map>: public ShadowTraitsContainer< Map, ShadowTraits<Map> >
227 {
228 template <typename Container> static int getObjectImpl(PyObject* obj, util::SharedPtr<Container>& value, bool writable)
229 {
230 if (!PyMapping_Check(obj))
231 {
232 PyErr_SetString(PyExc_TypeError, "not a map");
233 return 1;
234 }
235
236 // check if we have our own Sequence object, then take a shortcut
237 if (obj->ob_type == Map::_lassPyClassDef.type())
238 {
239 const Map* const map = static_cast<Map*>(obj);
240 void* const raw = map->raw(writable);
241 if (raw && typeid(value) == map->type())
242 {
243 value = *static_cast< util::SharedPtr<Container>* >(raw);
244 return 0;
245 }
246 }
247
248 const util::SharedPtr<Container> result(new Container);
249 const Py_ssize_t size = PyMapping_Length(obj);
250 TPyObjPtr items(PyMapping_Items(obj));
251 if (!items)
252 {
253 PyErr_SetString(PyExc_TypeError, "Not a mapping");
254 return 1;
255 }
256 TPyObjPtr fast = impl::checkedFastSequence(items.get(), size);
257 if (!fast)
258 {
259 return 1;
260 }
261 PyObject** pairs = PySequence_Fast_ITEMS(fast.get());
262 typedef ArgumentTraits<typename Container::key_type> TKeyArgTraits;
263 typedef ArgumentTraits<typename Container::mapped_type> TMappedArgTraits;
264 for (Py_ssize_t i = 0; i < size; ++i)
265 {
266 typename TKeyArgTraits::TStorage key;
267 typename TMappedArgTraits::TStorage mapped;
268 if (decodeTuple(pairs[i], key, mapped) != 0)
269 {
271 return 1;
272 }
273 [[maybe_unused]] auto r = result->emplace(TKeyArgTraits::arg(key), TMappedArgTraits::arg(mapped));
274 LASS_ASSERT(r.second); // should always insert!
275 }
276 value = std::move(result);
277 return 0;
278 }
279 };
280}
281
282template <typename ContainerType>
283struct ShadoweeTraitsMap: meta::True
284{
285 typedef impl::Map TShadow;
286 typedef impl::ShadowTraits<impl::Map> TShadowTraits;
287 typedef SharedPointerTraits<ContainerType> TPointerTraits;
288};
289
290/** @ingroup Python
291 * @internal
292 */
293template< typename K, typename T, typename C, typename A>
294struct ShadoweeTraits< std::map<K, T, C, A> >:
295 public ShadoweeTraitsMap< std::map<K, T, C, A> >
296{
297};
298
299}
300
301}
302
303#endif
304
305#ifdef LASS_GUARDIAN_OF_INCLUSION_STDE_VECTOR_MAP_H
306
307namespace lass
308{
309namespace python
310{
311/** @ingroup Python
312 * @internal
313 */
314template< typename K, typename T, typename C, typename A>
315struct ShadoweeTraits< stde::vector_map<K, T, C, A> >:
316 public ShadoweeTraitsMap< stde::vector_map<K, T, C, A> >
317{
318};
319}
320}
321
322#endif
323
324// EOF
use as base class if derived should not be copyable
void addMessageHeader(const char *header)
Prepend a message to the current Python exception value.
PyObjectPtr< PyObject >::Type TPyObjPtr
PyObjectPtr to a PyObject.
#define PY_HEADER(t_parentClass)
Place as first line of your Pythonized class.
Comprehensive C++ to Python binding library.
Library for Assembled Shared Sources.
Definition config.h:53