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