3636// -----------------------------------------------------------------------------
3737CCachedProperty::CCachedProperty (
3838 object fget=object(), object fset=object(), object fdel=object(), object doc=object(),
39- bool unbound=false, boost::python::tuple args=boost::python::tuple(), object kwargs=object())
39+ boost::python::tuple args=boost::python::tuple(), object kwargs=object())
4040{
4141 set_getter (fget);
4242 set_setter (fset);
4343 set_deleter (fdel);
4444
4545 m_doc = doc;
46- m_bUnbound = unbound;
4746
4847 m_args = args;
4948
@@ -65,52 +64,6 @@ object CCachedProperty::_callable_check(object function, const char *szName)
6564 return function;
6665}
6766
68- object CCachedProperty::_prepare_value (object value)
69- {
70- if (!PyGen_Check (value.ptr ()))
71- return value;
72-
73- if (getattr (value, " gi_frame" ).is_none ())
74- BOOST_RAISE_EXCEPTION (
75- PyExc_ValueError,
76- " The given generator is exhausted."
77- );
78-
79- list values;
80- while (true )
81- {
82- try
83- {
84- values.append (value.attr (" __next__" )());
85- }
86- catch (...)
87- {
88- if (!PyErr_ExceptionMatches (PyExc_StopIteration))
89- throw_error_already_set ();
90-
91- PyErr_Clear ();
92- break ;
93- }
94- }
95-
96- return values;
97- }
98-
99- void CCachedProperty::_invalidate_cache (PyObject *pRef)
100- {
101- try
102- {
103- m_cache[handle<>(pRef)].del ();
104- }
105- catch (...)
106- {
107- if (!PyErr_ExceptionMatches (PyExc_KeyError))
108- throw_error_already_set ();
109-
110- PyErr_Clear ();
111- }
112- }
113-
11467
11568object CCachedProperty::get_getter ()
11669{
@@ -155,81 +108,88 @@ str CCachedProperty::get_name()
155108
156109object CCachedProperty::get_owner ()
157110{
158- return m_owner () ;
111+ return m_owner;
159112}
160113
161114
162115object CCachedProperty::get_cached_value (object instance)
163116{
164- if (!m_name)
117+ if (!m_name || m_owner. is_none () )
165118 BOOST_RAISE_EXCEPTION (
166119 PyExc_AttributeError,
167120 " Unable to retrieve the value of an unbound property."
168121 );
169122
170- object value;
123+ PyObject *pValue = NULL ;
124+ PyObject **ppDict = _PyObject_GetDictPtr (instance.ptr ());
171125
172- if (m_bUnbound)
173- value = m_cache[
174- handle<>(
175- PyWeakref_NewRef (instance.ptr (), NULL )
176- )
177- ];
178- else
179- {
180- dict cache = extract<dict>(instance.attr (" __dict__" ));
181- value = cache[m_name];
126+
127+ if (ppDict && *ppDict) {
128+ pValue = PyDict_GetItem (*ppDict, m_name.ptr ());
182129 }
183130
184- return value;
131+ if (!pValue) {
132+ const char *szName = extract<const char *>(m_name);
133+ BOOST_RAISE_EXCEPTION (
134+ PyExc_KeyError,
135+ " No cached value found for '%s'." ,
136+ szName
137+ )
138+ }
139+
140+ return object (handle<>(borrowed (pValue)));
185141}
186142
187143void CCachedProperty::set_cached_value (object instance, object value)
188144{
189- if (!m_name)
145+ if (!m_name || m_owner. is_none () )
190146 BOOST_RAISE_EXCEPTION (
191147 PyExc_AttributeError,
192148 " Unable to assign the value of an unbound property."
193149 );
194150
195- if (m_bUnbound)
196- m_cache[handle<>(
197- PyWeakref_NewRef (
198- instance.ptr (),
199- make_function (
200- boost::bind (&CCachedProperty::_invalidate_cache, this , _1),
201- default_call_policies (),
202- boost::mpl::vector2<void , PyObject *>()
203- ).ptr ()
204- )
205- )] = _prepare_value (value);
206- else
207- {
208- dict cache = extract<dict>(instance.attr (" __dict__" ));
209- cache[m_name] = _prepare_value (value);
151+ if (!PyObject_IsInstance (instance.ptr (), m_owner.ptr ())) {
152+ const char *szOwner = extract<const char *>(m_owner.attr (" __qualname__" ));
153+ BOOST_RAISE_EXCEPTION (
154+ PyExc_TypeError,
155+ " Given instance is not of type '%s'." ,
156+ szOwner
157+ )
210158 }
159+
160+ if (PyGen_Check (value.ptr ())) {
161+ return ;
162+ }
163+
164+ PyObject *pDict = PyObject_GenericGetDict (instance.ptr (), NULL );
165+
166+ if (!pDict) {
167+ const char *szOwner = extract<const char *>(m_owner.attr (" __qualname__" ));
168+ BOOST_RAISE_EXCEPTION (
169+ PyExc_AttributeError,
170+ " '%s' object has no attribute '__dict__'" ,
171+ szOwner
172+ )
173+ }
174+
175+ PyDict_SetItem (pDict, m_name.ptr (), value.ptr ());
176+ Py_XDECREF (pDict);
211177}
212178
213179void CCachedProperty::delete_cached_value (object instance)
214180{
215- try
216- {
217- if (m_bUnbound)
218- m_cache[
219- handle<>(
220- PyWeakref_NewRef (instance.ptr (), NULL )
221- )
222- ].del ();
223- else
224- {
225- dict cache = extract<dict>(instance.attr (" __dict__" ));
226- cache[m_name].del ();
227- }
181+ PyObject **ppDict = _PyObject_GetDictPtr (instance.ptr ());
182+
183+ if (!ppDict && !*ppDict) {
184+ return ;
228185 }
229- catch (...)
230- {
231- if (!PyErr_ExceptionMatches (PyExc_KeyError))
186+
187+ PyDict_DelItem (*ppDict, m_name.ptr ());
188+
189+ if (PyErr_Occurred ()) {
190+ if (!PyErr_ExceptionMatches (PyExc_KeyError)) {
232191 throw_error_already_set ();
192+ }
233193
234194 PyErr_Clear ();
235195 }
@@ -239,6 +199,14 @@ void CCachedProperty::delete_cached_value(object instance)
239199object CCachedProperty::bind (object self, object owner, str name)
240200{
241201 CCachedProperty &pSelf = extract<CCachedProperty &>(self);
202+
203+ if (owner.is_none () && !name) {
204+ BOOST_RAISE_EXCEPTION (
205+ PyExc_ValueError,
206+ " Must provide a name and an owner."
207+ )
208+ }
209+
242210 owner.attr (name) = self;
243211 pSelf.__set_name__ (owner, name);
244212 return self;
@@ -247,9 +215,9 @@ object CCachedProperty::bind(object self, object owner, str name)
247215
248216void CCachedProperty::__set_name__ (object owner, str name)
249217{
250- if (m_name && !m_owner.is_none ())
218+ if (m_name || !m_owner.is_none ())
251219 {
252- const char *szName = extract<const char *>(str (" ." ).join (make_tuple (m_owner () .attr (" __qualname__" ), m_name)));
220+ const char *szName = extract<const char *>(str (" ." ).join (make_tuple (m_owner.attr (" __qualname__" ), m_name)));
253221 BOOST_RAISE_EXCEPTION (
254222 PyExc_RuntimeError,
255223 " This property was already bound as \" %s\" ." ,
@@ -258,7 +226,7 @@ void CCachedProperty::__set_name__(object owner, str name)
258226 }
259227
260228 m_name = name;
261- m_owner = object (handle<>( PyWeakref_NewRef ( owner. ptr (), NULL ))) ;
229+ m_owner = owner;
262230}
263231
264232object CCachedProperty::__get__ (object self, object instance, object owner=object())
@@ -349,11 +317,11 @@ void CCachedProperty::__setitem__(str item, object value)
349317
350318CCachedProperty *CCachedProperty::wrap_descriptor (
351319 object descriptor, object owner, str name,
352- bool unbound, boost::python::tuple args, object kwargs)
320+ boost::python::tuple args, object kwargs)
353321{
354322 CCachedProperty *pProperty = new CCachedProperty (
355323 descriptor.attr (" __get__" ), descriptor.attr (" __set__" ), descriptor.attr (" __delete__" ),
356- descriptor.attr (" __doc__" ), unbound, args, kwargs
324+ descriptor.attr (" __doc__" ), args, kwargs
357325 );
358326
359327 pProperty->__set_name__ (owner, name);
0 commit comments