Package pyplusplus :: Package code_repository :: Module return_range

# Source Code for Module pyplusplus.code_repository.return_range

      1  # Copyright 2004-2008 Roman Yakovenko.
      2  # Distributed under the Boost Software License, Version 1.0. (See
      3  # accompanying file LICENSE_1_0.txt or copy at
      4  # http://www.boost.org/LICENSE_1_0.txt)
      5
      6  """
      7  This file contains C++ code - "return_range" call policies
      8  """
      9
     10  from pyplusplus.decl_wrappers import call_policies
     11
     12  namespace = "pyplusplus::call_policies"
     13
     14  file_name = call_policies.return_range_t.HEADER_FILE
     15
     16  code = \
     17  """// Copyright 2004-2008 Roman Yakovenko.
     18  // Distributed under the Boost Software License, Version 1.0. (See
     19  // accompanying file LICENSE_1_0.txt or copy at
     20  // http://www.boost.org/LICENSE_1_0.txt)
     21
     22  #ifndef return_range_pyplusplus_hpp__
     23  #define return_range_pyplusplus_hpp__
     24
     25  #include "boost/python.hpp"
     26  #include "boost/mpl/int.hpp"
     27  #include "boost/function.hpp"
     28  #include "boost/python/suite/indexing/iterator_range.hpp"
     29  #include "boost/python/object/class_detail.hpp"
     30  #include "boost/type_traits/is_same.hpp"
     31  namespace pyplusplus{ namespace call_policies{
     32
     33  namespace bpl = boost::python;
     34
     35  namespace detail{
     36
     37  struct return_raw_data_ref{
     38
     39      template <class T>
     40      struct apply{
     41
     42          BOOST_STATIC_ASSERT( boost::is_pointer<T>::value );
     43
     44          struct type{
     45              static bool convertible()
     46              { return true; }
     47
     48              PyObject*
     49              operator()( T return_value) const{
     50                  if( !return_value ){
     51                      return bpl::detail::none();
     52                  }
     53                  else{
     54                      typedef typename boost::remove_pointer< T >::type value_type;
     55                      typedef typename boost::remove_const< value_type >::type non_const_value_type;
     56                      non_const_value_type* data = const_cast<non_const_value_type*>( return_value );
     57                      return PyCObject_FromVoidPtr( data, NULL );
     58                  }
     59              }
     60          };
     61
     62      };
     63
     64  };
     65
     66  } //detail
     67
     68  template < typename TGetSize, typename TValueType, typename TValuePolicies=bpl::default_call_policies >
     69  struct return_range : bpl::default_call_policies{
     70
     71      typedef return_range< TGetSize, TValueType, TValuePolicies > this_type;
     72
     73  public:
     74
     75      typedef typename detail::return_raw_data_ref result_converter;
     76
     77      typedef TValueType value_type;
     78      typedef TGetSize get_size_type;
     79      typedef TValuePolicies value_policies_type;
     80
     81      typedef bpl::indexing::iterator_range<value_type*> range_type;
     82
     83      template <class ArgumentPackage>
     84      static PyObject* postcall(ArgumentPackage const& args, PyObject* result){
     85          if( result == bpl::detail::none() ){
     86              return result;
     87          }
     88          if( !PyCObject_Check( result ) ){
     89              throw std::runtime_error( "Internal error: expected to get PyCObject" );
     90          }
     91          value_type* raw_data = reinterpret_cast<value_type*>( PyCObject_AsVoidPtr( result ) );
     92          Py_DECREF(result);//we don't need result anymore
     93
     94          bpl::tuple args_w( bpl::handle<>( bpl::borrowed( args ) ) );
     95
     96          register_range_class_on_demand();
     97
     98          get_size_type get_size;
     99          range_type the_range( raw_data, raw_data + get_size( args_w ) );
    100
    101          bpl::object range_obj( the_range );
    102
    103          return bpl::incref( range_obj.ptr() );
    104      }
    105  private:
    106
    107      static void register_range_class( boost::mpl::true_ ){
    108          //register range class with default call policies
    109          bpl::class_<range_type>( "_impl_details_range_iterator_",  bpl::init<value_type*, value_type*>() )
    110              .def(bpl::indexing::container_suite<range_type>() );
    111      }
    112
    113      static void register_range_class( boost::mpl::false_ ){
    114          //register range class with non default call policies
    115          unsigned long const methods_mask
    116              = bpl::indexing::all_methods
    117                & ~( bpl::indexing::reorder_methods |  bpl::indexing::search_methods ) ;
    118
    119          typedef bpl::indexing::iterator_range_suite< range_type, methods_mask > suite_type;
    120          bpl::class_<range_type>( "_impl_details_range_iterator_",  bpl::init<value_type*, value_type*>() )
    121              .def( suite_type::with_policies( value_policies_type() ) );
    122      }
    123
    124      static void register_range_class_on_demand(){
    125          //Check the registry. If the class doesn't exist, register it.
    126          bpl::handle<> class_obj(
    127              bpl::objects::registered_class_object(bpl::type_id<range_type>()));
    128
    129          if( class_obj.get() == 0 ){
    130              register_range_class( boost::is_same< bpl::default_call_policies, value_policies_type>() );
    131          }
    132      }
    133
    134  };
    135
    136  } /*pyplusplus*/ } /*call_policies*/
    137
    138
    139  #endif//return_range_pyplusplus_hpp__
    140
    141  """
    142