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