1 // Copyright David Abrahams 2004. Distributed under the Boost
2 // Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4 #include <boost/python/dict.hpp>
5 #include <boost/python/extract.hpp>
6
7 namespace boost { namespace python { namespace detail {
8 namespace
9 {
10 // When returning list objects from methods, it may turn out that the
11 // derived class is returning something else, perhaps something not
12 // even derived from list. Since it is generally harmless for a
13 // Boost.Python wrapper object to hold an object of a different
14 // type, and because calling list() with an object may in fact
15 // perform a conversion, the least-bad alternative is to assume that
16 // we have a Python list object and stuff it into the list result.
assume_list(object const & o)17 list assume_list(object const& o)
18 {
19 return list(detail::borrowed_reference(o.ptr()));
20 }
21
22 // No PyDict_CheckExact; roll our own.
check_exact(dict_base const * p)23 inline bool check_exact(dict_base const* p)
24 {
25 return p->ptr()->ob_type == &PyDict_Type;
26 }
27 }
28
call(object const & arg_)29 detail::new_reference dict_base::call(object const& arg_)
30 {
31 return (detail::new_reference)PyObject_CallFunction(
32 (PyObject*)&PyDict_Type, const_cast<char*>("(O)"),
33 arg_.ptr());
34 }
35
dict_base()36 dict_base::dict_base()
37 : object(detail::new_reference(PyDict_New()))
38 {}
39
dict_base(object_cref data)40 dict_base::dict_base(object_cref data)
41 : object(call(data))
42 {}
43
clear()44 void dict_base::clear()
45 {
46 if (check_exact(this))
47 PyDict_Clear(this->ptr());
48 else
49 this->attr("clear")();
50 }
51
copy()52 dict dict_base::copy()
53 {
54 if (check_exact(this))
55 {
56 return dict(detail::new_reference(
57 PyDict_Copy(this->ptr())));
58 }
59 else
60 {
61 return dict(detail::borrowed_reference(
62 this->attr("copy")().ptr()
63 ));
64 }
65 }
66
get(object_cref k) const67 object dict_base::get(object_cref k) const
68 {
69 if (check_exact(this))
70 {
71 PyObject* result = PyDict_GetItem(this->ptr(),k.ptr());
72 return object(detail::borrowed_reference(result ? result : Py_None));
73 }
74 else
75 {
76 return this->attr("get")(k);
77 }
78 }
79
get(object_cref k,object_cref d) const80 object dict_base::get(object_cref k, object_cref d) const
81 {
82 return this->attr("get")(k,d);
83 }
84
has_key(object_cref k) const85 bool dict_base::has_key(object_cref k) const
86 {
87 return extract<bool>(this->contains(k));
88 }
89
items() const90 list dict_base::items() const
91 {
92 if (check_exact(this))
93 {
94 return list(detail::new_reference(
95 PyDict_Items(this->ptr())));
96 }
97 else
98 {
99 return assume_list(this->attr("items")());
100 }
101 }
102
iteritems() const103 object dict_base::iteritems() const
104 {
105 return this->attr("iteritems")();
106 }
107
iterkeys() const108 object dict_base::iterkeys() const
109 {
110 return this->attr("iterkeys")();
111 }
112
itervalues() const113 object dict_base::itervalues() const
114 {
115 return this->attr("itervalues")();
116 }
117
keys() const118 list dict_base::keys() const
119 {
120 if (check_exact(this))
121 {
122 return list(detail::new_reference(
123 PyDict_Keys(this->ptr())));
124 }
125 else
126 {
127 return assume_list(this->attr("keys")());
128 }
129 }
130
popitem()131 tuple dict_base::popitem()
132 {
133 return tuple(detail::borrowed_reference(
134 this->attr("popitem")().ptr()
135 ));
136 }
137
setdefault(object_cref k)138 object dict_base::setdefault(object_cref k)
139 {
140 return this->attr("setdefault")(k);
141 }
142
setdefault(object_cref k,object_cref d)143 object dict_base::setdefault(object_cref k, object_cref d)
144 {
145 return this->attr("setdefault")(k,d);
146 }
147
update(object_cref other)148 void dict_base::update(object_cref other)
149 {
150 if (check_exact(this))
151 {
152 if (PyDict_Update(this->ptr(),other.ptr()) == -1)
153 throw_error_already_set();
154 }
155 else
156 {
157 this->attr("update")(other);
158 }
159 }
160
values() const161 list dict_base::values() const
162 {
163 if (check_exact(this))
164 {
165 return list(detail::new_reference(
166 PyDict_Values(this->ptr())));
167 }
168 else
169 {
170 return assume_list(this->attr("values")());
171 }
172 }
173
174 static struct register_dict_pytype_ptr
175 {
register_dict_pytype_ptrboost::python::detail::register_dict_pytype_ptr176 register_dict_pytype_ptr()
177 {
178 const_cast<converter::registration &>(
179 converter::registry::lookup(boost::python::type_id<boost::python::dict>())
180 ).m_class_object = &PyDict_Type;
181 }
182 }register_dict_pytype_ptr_;
183
184 }}} // namespace boost::python
185