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