diff --git a/include/boost/python/suite/indexing/element_proxy.hpp b/include/boost/python/suite/indexing/element_proxy.hpp new file mode 100755 index 00000000..705abef8 --- /dev/null +++ b/include/boost/python/suite/indexing/element_proxy.hpp @@ -0,0 +1,195 @@ +// -*- mode:c++ -*- +// +// Header file element_proxy.hpp +// +// Proxy objects for invidivual elements in a container wrapped by +// container_proxy +// +// Copyright (c) 2003 Raoul M. Gough +// +// This material is provided "as is", with absolutely no warranty expressed +// or implied. Any use is at your own risk. +// +// Permission to use or copy this material for any purpose is hereby +// granted without fee, provided the above notices are retained on all +// copies. Permission to modify the material and to distribute modified +// versions is granted, provided the above notices are retained, and a +// notice that the material was modified is included with the above +// copyright notice. +// +// History +// ======= +// 2003/ 9/15 rmg File creation from container_proxy.hpp +// +// $Id$ +// + +#ifndef element_proxy_rmg_20030915_included +#define element_proxy_rmg_20030915_included + +#include "shared_proxy_impl.hpp" +#include + +#include "value_traits.hpp" +#include +#include +#include + +template +class element_proxy +{ + template friend struct const_element_proxy; + + typedef ContainerProxy container_proxy; + typedef typename container_proxy::shared_proxy proxy_type; + typedef boost::shared_ptr proxy_pointer; + typedef typename container_proxy::raw_value_type raw_value_type; + typedef typename container_proxy::size_type size_type; + + proxy_pointer mPtr; + +public: + typedef typename proxy_type::value_type value_type; + typedef typename proxy_type::reference reference; + typedef typename proxy_type::pointer pointer; + typedef typename proxy_type::iterator_category iterator_category; + typedef typename proxy_type::difference_type difference_type; + + typedef value_type element_type; // Alias for register_ptr_to_python + + element_proxy () : mPtr () { } + explicit element_proxy (proxy_type *ptr) : mPtr (ptr) { } + element_proxy (proxy_pointer const &ptr) : mPtr (ptr) { } + + explicit element_proxy (raw_value_type const &val) + : mPtr (new proxy_type(val)) + { + // Create new standalone value (i.e. detached) + } + + reference operator* () const { return mPtr->operator*(); } + pointer operator-> () const { return (*mPtr).operator->(); } + pointer get () const { return operator->(); } // Alias for pointer_holder + + // Implicit conversion to raw_value_type + operator reference () const { return operator*(); } + + // These are necessary (at least) while the indexing suite insists + // on converting the real container's value_type to the proxy + // container's value_type when going from Python to C++. If the + // suite would just pass the real container's value_type through, + // our implicit conversion to value_type might suffice. + bool operator== (value_type const &other) { return (**this) == other; } + bool operator!= (value_type const &other) { return (**this) != other; } + bool operator< (value_type const &other) { return (**this) < other; } + bool operator> (value_type const &other) { return (**this) > other; } + + element_proxy &operator= (value_type const ©) + { + proxy_type &proxy (*mPtr); + container_proxy *container = proxy.owner(); + size_type index = proxy.index(); + + if (container) + { + container->replace (index, copy); + // Proxy was attached before, but is now detached. Make sure + // we now refer to the new element, instead of the detached + // copy of the old element + mPtr = container->at (index).mPtr; + + // Note: in the special case that this we and the container + // proxy itself have the only references to the + // shared_proxy_impl, it is not necessary to first detach + // the proxy. Maybe best to implement when changing to + // intrusive_ptr instead of shared_ptr. + } + + else + { + *proxy = copy; + } + + return *this; + } + + element_proxy &operator= (element_proxy const ©) + { + // This is the most dubious bit of the fudge. The indexing_suite's + // implementation of __setitem__ tries to pass us our value_type, + // which is actually of type element_proxy + return (*this) = *copy; + } + + size_t use_count() const { return mPtr.use_count(); } // For debugging +}; + +template +struct const_element_proxy +{ + typedef ContainerProxy container_proxy; + typedef typename container_proxy::shared_proxy proxy_type; + typedef boost::shared_ptr proxy_pointer; + typedef typename container_proxy::raw_value_type raw_value_type; + + proxy_pointer mPtr; + +public: + typedef typename proxy_type::value_type const value_type; + typedef value_type &reference; + typedef value_type *pointer; + typedef typename proxy_type::iterator_category iterator_category; + typedef typename proxy_type::difference_type difference_type; + + const_element_proxy () : mPtr () { } + explicit const_element_proxy (proxy_type *ptr) : mPtr (ptr) { } + const_element_proxy (proxy_pointer const &ptr) : mPtr (ptr) { } + + const_element_proxy (element_proxy const ©) + : mPtr (copy.mPtr) + { + } + + explicit const_element_proxy (raw_value_type const &val) + : mPtr (new proxy_type(val)) + { + // Create new standalone value (i.e. detached) + } + + reference operator* () const { return mPtr->operator*(); } + pointer operator-> () const { return mPtr->operator->(); } + + // Implicit conversion to raw_value_type + operator reference () const { return operator*(); } + + size_t use_count() const { return mPtr.use_count(); } // For debugging +}; + +namespace boost +{ + template + typename ContainerProxy::raw_value_type * + get_pointer (element_proxy const &proxy) + { + return &(*proxy); + } +} + +namespace indexing { + template + struct value_traits > + : public value_traits + { + template + static void visitor_helper (PythonClass &, Policy const &) + { + typedef element_proxy element_proxy_; + typedef typename ContainerProxy::raw_value_type raw_value_type; + + boost::python::register_ptr_to_python(); + boost::python::implicitly_convertible(); + } + }; +} + +#endif // element_proxy_rmg_20030915_included