Package pyplusplus :: Package code_repository :: Module convenience

# Source Code for Module pyplusplus.code_repository.convenience

      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 needed to export one dimensional static arrays.
      8  """
      9
     10
     11  namespace = "pyplusplus::convenience"
     12
     13  file_name = "__convenience.pypp.hpp"
     14
     15  code = \
     16  """// Copyright 2004-2008 Roman Yakovenko.
     17  // Distributed under the Boost Software License, Version 1.0. (See
     18  // accompanying file LICENSE_1_0.txt or copy at
     19  // http://www.boost.org/LICENSE_1_0.txt)
     20
     21  #ifndef __convenience_pyplusplus_hpp__
     22  #define __convenience_pyplusplus_hpp__
     23
     24  #include "boost/python.hpp"
     25
     26  namespace pyplusplus{ namespace convenience{
     27
     28  //TODO: Replace index_type with Boost.Python defined ssize_t type.
     29  //      This should be done by checking Python and Boost.Python version.
     30  typedef int index_type;
     31
     32  inline void
     33  raise_error( PyObject *exception, const char *message ){
     34     PyErr_SetString(exception, message);
     35     boost::python::throw_error_already_set();
     36  }
     37
     38  inline index_type sequence_len(boost::python::object const& obj){
     39      if( !PySequence_Check( obj.ptr() ) ){
     40          raise_error( PyExc_TypeError, "Sequence expected" );
     41      }
     42
     43      index_type result = PyObject_Length( obj.ptr() );
     44      if( PyErr_Occurred() ){
     45          boost::python::throw_error_already_set();
     46      }
     47      return result;
     48  }
     49
     50  inline void
     51  ensure_sequence( boost::python::object seq, index_type expected_length=-1 ){
     52      index_type length = sequence_len( seq );
     53      if( expected_length != -1 && length != expected_length ){
     54          std::stringstream err;
     55          err << "Expected sequence length is " << expected_length << ". "
     56              << "Actual sequence length is " << length << ".";
     57          raise_error( PyExc_ValueError, err.str().c_str() );
     58      }
     59  }
     60
     61  template< class ExpectedType >
     62  void ensure_uniform_sequence( boost::python::object seq, index_type expected_length=-1 ){
     63      ensure_sequence( seq, expected_length );
     64
     65      index_type length = sequence_len( seq );
     66      for( index_type index = 0; index < length; ++index ){
     67          boost::python::object item = seq[index];
     68
     69          boost::python::extract<ExpectedType> type_checker( item );
     70          if( !type_checker.check() ){
     71              std::string expected_type_name( boost::python::type_id<ExpectedType>().name() );
     72
     73              std::string item_type_name("different");
     74              PyObject* item_impl = item.ptr();
     75              if( item_impl && item_impl->ob_type && item_impl->ob_type->tp_name ){
     76                  item_type_name = std::string( item_impl->ob_type->tp_name );
     77              }
     78
     79              std::stringstream err;
     80              err << "Sequence should contain only items with type \\"" << expected_type_name << "\\". "
     81                  << "Item at position " << index << " has \\"" << item_type_name << "\\" type.";
     82              raise_error( PyExc_ValueError, err.str().c_str() );
     83          }
     84      }
     85  }
     86
     87  template< class Iterator, class Inserter >
     88  void copy_container( Iterator begin, Iterator end, Inserter inserter ){
     89      for( Iterator index = begin; index != end; ++index )
     90          inserter( *index );
     91  }
     92
     93  template< class Inserter >
     94  void copy_sequence( boost::python::object const& seq, Inserter inserter ){
     95      index_type length = sequence_len( seq );
     96      for( index_type index = 0; index < length; ++index ){
     97          inserter = seq[index];
     98      }
     99  }
    100
    101  template< class Inserter, class TItemType >
    102  void copy_sequence( boost::python::object const& seq, Inserter inserter, boost::type< TItemType > ){
    103      index_type length = sequence_len( seq );
    104      for( index_type index = 0; index < length; ++index ){
    105          boost::python::object item = seq[index];
    106          inserter = boost::python::extract< TItemType >( item );
    107      }
    108  }
    109
    110  struct list_inserter{
    111      list_inserter( boost::python::list& py_list )
    112      : m_py_list( py_list )
    113      {}
    114
    115      template< class T >
    116      void operator()( T const & value ){
    117          m_py_list.append( value );
    118      }
    119  private:
    120      boost::python::list& m_py_list;
    121  };
    122
    123  template < class T >
    124  struct array_inserter_t{
    125      array_inserter_t( T* array, index_type size )
    126      : m_array( array )
    127        , m_curr_pos( 0 )
    128        , m_size( size )
    129      {}
    130
    131      void insert( const T& item ){
    132          if( m_size <= m_curr_pos ){
    133              std::stringstream err;
    134              err << "Index out of range. Array size is" << m_size << ", "
    135                  << "current position is" << m_curr_pos << ".";
    136              raise_error( PyExc_ValueError, err.str().c_str() );
    137          }
    138          m_array[ m_curr_pos ] = item;
    139          m_curr_pos += 1;
    140      }
    141
    142      array_inserter_t<T>&
    143      operator=( boost::python::object const & item ){
    144          insert( boost::python::extract< T >( item ) );
    145          return *this;
    146      }
    147
    148  private:
    149      T* m_array;
    150      index_type m_curr_pos;
    151      const index_type m_size;
    152  };
    153
    154  template< class T>
    155  array_inserter_t<T> array_inserter( T* array, index_type size ){
    156      return array_inserter_t<T>( array, size );
    157  }
    158
    159  inline boost::python::object
    160  get_out_argument( boost::python::object result, const char* arg_name ){
    161      if( !PySequence_Check( result.ptr() ) ){
    162          return result;
    163      }
    164      boost::python::object cls = boost::python::getattr( result, "__class__" );
    165      boost::python::object cls_name = boost::python::getattr( cls, "__name__" );
    166      std::string name = boost::python::extract< std::string >( cls_name );
    167      if( "named_tuple" == name ){
    168          return boost::python::getattr( result, arg_name );
    169      }
    170      else{
    171          return result;
    172      }
    173
    174  }
    175
    176  inline boost::python::object
    177  get_out_argument( boost::python::object result, index_type index ){
    178      if( !PySequence_Check( result.ptr() ) ){
    179          return result;
    180      }
    181      boost::python::object cls = boost::python::getattr( result, "__class__" );
    182      boost::python::object cls_name = boost::python::getattr( cls, "__name__" );
    183      std::string name = boost::python::extract< std::string >( cls_name );
    184      if( "named_tuple" == name ){
    185          return result[ index ];
    186      }
    187      else{
    188          return result;
    189      }
    190  }
    191
    192  } /*pyplusplus*/ } /*convenience*/
    193
    194  namespace pyplus_conv = pyplusplus::convenience;
    195
    196  #endif//__convenience_pyplusplus_hpp__
    197
    198  """
    199