Pycxx Operators

Tidying up the operator code at the bottom of /pycxx-6.2.5/Python3/cxx_extensions.cxx

This code is currently 324 lines:

//------------------------------------------------------------
// compare operators
bool operator!=( const Long &a, const Long &b )
{
    return a.as_long() != b.as_long();
}

bool operator!=( const Long &a, int b )
{
    return a.as_long() != b;
}

:

bool operator<=( const Float &a, double b )
{
    return a.as_double() <= b;
}

Firstly, get each function on one line, so we can see clearly what we're dealing with.

    bool operator!=( const Long &a, const Long &b ) { return a.as_long() != b.as_long(); }
    bool operator!=( const Long &a, int b )         { return a.as_long() != b;    }
    bool operator!=( const Long &a, long b )        { return a.as_long() != b;    }
    bool operator!=( int a,         const Long &b ) { return a != b.as_long();    }
    bool operator!=( long a,        const Long &b )  { return a != b.as_long();    }
    //------------------------------
    bool operator==( const Long &a, const Long &b ) { return a.as_long() == b.as_long();    }
    bool operator==( const Long &a, int b )         { return a.as_long() == b;    }
    bool operator==( const Long &a, long b )        { return a.as_long() == b;    }
    bool operator==( int a,         const Long &b ) { return a == b.as_long();    }
    bool operator==( long a,        const Long &b ) { return a == b.as_long();    }

    //------------------------------
    bool operator>( const Long &a, const Long &b )  { return a.as_long() > b.as_long();    }
    bool operator>( const Long &a, int b )          { return a.as_long() > b;    }
    bool operator>( const Long &a, long b )         { return a.as_long() > b;    }
    bool operator>( int a,         const Long &b )  { return a > b.as_long();    }
    bool operator>( long a,        const Long &b )  { return a > b.as_long();    }

    //------------------------------
    bool operator>=( const Long &a, const Long &b ) { return a.as_long() >= b.as_long();    }
    bool operator>=( const Long &a, int b )         { return a.as_long() >= b;    }
    bool operator>=( const Long &a, long b )        { return a.as_long() >= b;    }
    bool operator>=( int a,         const Long &b ) { return a >= b.as_long();    }
    bool operator>=( long a,        const Long &b ) { return a >= b.as_long();    }

    //------------------------------
    bool operator<( const Long &a,  const Long &b ) { return a.as_long() < b.as_long();    }
    bool operator<( const Long &a,  int b )         { return a.as_long() < b;    }
    bool operator<( const Long &a,  long b )        { return a.as_long() < b;    }
    bool operator<( int a,          const Long &b ) { return a < b.as_long();    }
    bool operator<( long a,         const Long &b ) { return a < b.as_long();    }

    //------------------------------
    bool operator<=( const Long &a, const Long &b ) { return a.as_long() <= b.as_long();    }
    bool operator<=( int a, const Long &b )         { return a <= b.as_long();    }
    bool operator<=( long a, const Long &b )        { return a <= b.as_long();    }
    bool operator<=( const Long &a, int b )         { return a.as_long() <= b;    }
    bool operator<=( const Long &a, long b )        { return a.as_long() <= b;    }

#ifdef HAVE_LONG_LONG
    //------------------------------

    OPS( const Long &a, PY_LONG_LONG b,   a.as_long_long() != b                )
    OPS( PY_LONG_LONG a, const Long &b,   a                != b.as_long_long() )

    bool operator!=( const Long &a, PY_LONG_LONG b )    { return a.as_long_long() != b;    }
    bool operator!=( PY_LONG_LONG a, const Long &b )    { return a != b.as_long_long();    }

    //------------------------------
    bool operator==( const Long &a, PY_LONG_LONG b )    { return a.as_long_long() == b;    }
    bool operator==( PY_LONG_LONG a, const Long &b )    { return a == b.as_long_long();    }

    //------------------------------
    bool operator>( const Long &a, PY_LONG_LONG b )    { return a.as_long_long() > b;    }
    bool operator>( PY_LONG_LONG a, const Long &b )    { return a > b.as_long_long();    }

    //------------------------------
    bool operator>=( const Long &a, PY_LONG_LONG b )    { return a.as_long_long() >= b;    }
    bool operator>=( PY_LONG_LONG a, const Long &b )    { return a >= b.as_long_long();    }

    //------------------------------
    bool operator<( const Long &a, PY_LONG_LONG b )    { return a.as_long_long() < b;    }
    bool operator<( PY_LONG_LONG a, const Long &b )    { return a < b.as_long_long();    }

    //------------------------------
    bool operator<=( const Long &a, PY_LONG_LONG b )    { return a.as_long_long() <= b;    }
    bool operator<=( PY_LONG_LONG a, const Long &b )    { return a <= b.as_long_long();    }
#endif
#endif

    //------------------------------------------------------------
    // compare operators
    OPS( const Float &a, const Float &b,   a.as_double() != b.as_double() )
    OPS( const Float &a, double       b,   a.as_double() != b             )
    OPS( double a,       const Float &b,   a             != b.as_double() )

    bool operator!=( const Float &a, const Float &b )  { return a.as_double() != b.as_double();    }
    bool operator!=( const Float &a, double b )        { return a.as_double() != b;    }
    bool operator!=( double a,       const Float &b )  { return a != b.as_double();    }

    //------------------------------
    bool operator==( const Float &a, const Float &b )  { return a.as_double() == b.as_double();    }
    bool operator==( const Float &a, double b )        { return a.as_double() == b;    }
    bool operator==( double a,       const Float &b )  { return a == b.as_double();    }

    //------------------------------
    bool operator>( const Float &a, const Float &b )   { return a.as_double() > b.as_double();    }
    bool operator>( const Float &a, double b )         { return a.as_double() > b;    }
    bool operator>( double a,       const Float &b )   { return a > b.as_double();    }

    //------------------------------
    bool operator>=( const Float &a, const Float &b )  { return a.as_double() >= b.as_double(); }
    bool operator>=( const Float &a, double b )        { return a.as_double() >= b;    }
    bool operator>=( double a,       const Float &b )  { return a >= b.as_double();    }
    //------------------------------
    bool operator<( const Float &a, const Float &b )   { return a.as_double() < b.as_double();    }
    bool operator<( const Float &a, double b )         { return a.as_double() < b;    }
    bool operator<( double a,       const Float &b )   { return a < b.as_double();    }
    //------------------------------
    bool operator<=( const Float &a, const Float &b )  { return a.as_double() <= b.as_double();    }
    bool operator<=( double a,       const Float &b )  { return a <= b.as_double();    }
    bool operator<=( const Float &a, double b )        { return a.as_double() <= b;    }

Now notice code is identical for each of the six operators, there is a 6x duplication going on, which can be fixed with a handful of macros:

#define OP( op, l, r, cmpL, cmpR ) \
    bool operator op( l, r ) \
    { \
        return cmpL op cmpR; \
    }

#define OPS( l, r, cmpL, cmpR ) \
    OP( !=, l, r, cmpL, cmpR ) \
    OP( ==, l, r, cmpL, cmpR ) \
    OP( > , l, r, cmpL, cmpR ) \
    OP( >=, l, r, cmpL, cmpR ) \
    OP( < , l, r, cmpL, cmpR ) \
    OP( <=, l, r, cmpL, cmpR )

    OPS( const Long &a, const Long &b,   a.as_long() , b.as_long() )
    OPS( const Long &a,       int   b,   a.as_long() , b           )
    OPS( const Long &a,       long  b,   a.as_long() , b           )
    OPS( int         a, const Long &b,   a           , b.as_long() )
    OPS( long        a, const Long &b,   a           , b.as_long() )

#ifdef HAVE_LONG_LONG
    OPS( const Long &a, PY_LONG_LONG b,   a.as_long_long() , b                )
    OPS( PY_LONG_LONG a, const Long &b,   a                , b.as_long_long() )
#endif

    OPS( const Float &a, const Float &b,   a.as_double() , b.as_double() )
    OPS( const Float &a, double       b,   a.as_double() , b             )
    OPS( double a,       const Float &b,   a             , b.as_double() )

We can eliminate duplicating the parameter list as well:

#define OPS( ... ) \
    OP( !=, ##__VA_ARGS__ ) \
    OP( ==, ##__VA_ARGS__ ) \
    OP( > , ##__VA_ARGS__ ) \
    OP( >=, ##__VA_ARGS__ ) \
    OP( < , ##__VA_ARGS__ ) \
    OP( <=, ##__VA_ARGS__ )

Also, note one further symmetry:

    OPS( const Long &a,       int   b,   a.as_long() , b           )
    OPS( int         a, const Long &b,   a           , b.as_long() )

i.e. We need to define X op X, X op Y and Y op X, and those last two could be merged:

#define BI_( a, b, convA, convB ) \
    OPS(a, b, convA, convB ) \
    OPS(b, a, convB, convA )

So the entire code becomes:

#define OP( op, l, r, cmpL, cmpR ) \
    bool operator op( l, r ) { return cmpL op cmpR; }

#define OPS( ... ) \
    OP( != , ##__VA_ARGS__ ) \
    OP( == , ##__VA_ARGS__ ) \
    OP( >  , ##__VA_ARGS__ ) \
    OP( >= , ##__VA_ARGS__ ) \
    OP( <  , ##__VA_ARGS__ ) \
    OP( <= , ##__VA_ARGS__ )

#define BI_( a, b, convA, convB ) \
    OPS( a, b, convA, convB ) \
    OPS( b, a, convB, convA )

    OPS( const Long  &a, const Long  &b  ,  a.as_long()      , b.as_long()    )
    BI_( const Long  &a, int          b  ,  a.as_long()      , b              )
    BI_( const Long  &a, long         b  ,  a.as_long()      , b              )

#ifdef HAVE_LONG_LONG
    BI_( const Long  &a, PY_LONG_LONG b  ,  a.as_long_long() , b              )
#endif

    OPS( const Float &a, const Float &b  ,  a.as_double()    , b.as_double()  )
    BI_( const Float &a, double       b  ,  a.as_double()    , b              )

#undef BI_
#undef OPS
#undef OP

Now it should be possible to remove the line marked *, as int would get promoted to long.

A final idea would be just making int/long implicitly convertible to Long (by adding a constructor to Long that takes int/long), and then having the operators only defined for two Longs. And then do the same for Float.


Also /src/Python3/cxxsupport.cxx can be tidied similarly:

bool operator==( const Object &o1, const Object &o2 )
{
    int k = PyObject_RichCompareBool( *o1, *o2, Py_EQ );
    if( PyErr_Occurred() )
        throw Exception();
    return k != 0;
}

bool operator!=( const Object &o1, const Object &o2 )
{
    int k = PyObject_RichCompareBool( *o1, *o2, Py_NE );
    if( PyErr_Occurred() )
        throw Exception();
    return k != 0;

}

bool operator>=( const Object &o1, const Object &o2 )
{
    int k = PyObject_RichCompareBool( *o1, *o2, Py_GE );
    if( PyErr_Occurred() )
        throw Exception();
    return k != 0;
}

bool operator<=( const Object &o1, const Object &o2 )
{
    int k = PyObject_RichCompareBool( *o1, *o2, Py_LE );
    if( PyErr_Occurred() )
        throw Exception();
    return k != 0;
}

bool operator<( const Object &o1, const Object &o2 )
{
    int k = PyObject_RichCompareBool( *o1, *o2, Py_LT );
    if( PyErr_Occurred() )
        throw Exception();
    return k != 0;
}

bool operator>( const Object &o1, const Object &o2 )
{
    int k = PyObject_RichCompareBool( *o1, *o2, Py_GT );
    if( PyErr_Occurred() )
        throw Exception();
    return k != 0;
}

…can be replaced with:

#define OP( _op_ , _expr_ ) \
    bool operator _op_ ( const Object &p, const Object &q ) \
    { \
        int k = PyObject_RichCompareBool( *p, *q, _expr_ ); \
        if( PyErr_Occurred() ) \
            throw Exception(); \
        return k != 0; \
    }

OP( == , Py_EQ )
OP( != , Py_NE )
OP( >= , Py_GE )
OP( <= , Py_LE )
OP( <  , Py_LT )
OP( >  , Py_GT )

#undef OP

and…

bool operator==( const Sequence::iterator &left, const Sequence::iterator &right )
{
    return left.eql( right );
}

bool operator!=( const Sequence::iterator &left, const Sequence::iterator &right )
{
    return left.neq( right );
}

bool operator<( const Sequence::iterator &left, const Sequence::iterator &right )
{
    return left.lss( right );
}

bool operator>( const Sequence::iterator &left, const Sequence::iterator &right )
{
    return left.gtr( right );
}

bool operator<=( const Sequence::iterator &left, const Sequence::iterator &right )
{
    return left.leq( right );
}

bool operator>=( const Sequence::iterator &left, const Sequence::iterator &right )
{
    return left.geq( right );
}

 const_iterator compares
bool operator==( const Sequence::const_iterator &left, const Sequence::const_iterator &right )
{
    return left.eql( right );
}

bool operator!=( const Sequence::const_iterator &left, const Sequence::const_iterator &right )
{
    return left.neq( right );
}

bool operator<( const Sequence::const_iterator &left, const Sequence::const_iterator &right )
{
    return left.lss( right );
}

bool operator>( const Sequence::const_iterator &left, const Sequence::const_iterator &right )
{
    return left.gtr( right );
}

bool operator<=( const Sequence::const_iterator &left, const Sequence::const_iterator &right )
{
    return left.leq( right );
}

bool operator>=( const Sequence::const_iterator &left, const Sequence::const_iterator &right )
{
    return left.geq( right );
}

 For mappings:
bool operator==( const Mapping::iterator &left, const Mapping::iterator &right )
{
    return left.eql( right );
}

bool operator!=( const Mapping::iterator &left, const Mapping::iterator &right )
{
    return left.neq( right );
}

// now for const_iterator
bool operator==( const Mapping::const_iterator &left, const Mapping::const_iterator &right )
{
    return left.eql( right );
}

bool operator!=( const Mapping::const_iterator &left, const Mapping::const_iterator &right )
{
    return left.neq( right );
}

…with…

#define OP( _type_, _op_, _func_ ) \
    bool operator _op_( const _type_ &left, const _type_ &right ) \
    { \
        return left._func_( right ); \
    }

#define OPS( _type_ ) \
    OP( _type_, == , eql ) \
    OP( _type_, != , neq ) \
    OP( _type_,  < , lss ) \
    OP( _type_,  > , gtr ) \
    OP( _type_, <= , leq ) \
    OP( _type_, >= , geq )

OPS( Sequence::iterator )
OPS( Sequence::const_iterator )

OP( Mapping::iterator, == , eql )
OP( Mapping::iterator, != , neq )

OP( Mapping::const_iterator, == , eql )
OP( Mapping::const_iterator, != , neq )

#undef OPS
#undef OP

Of course a further reduction could be achieved by noticing that everything is repeated firstly for iterator and then for const_iterator.

#define ITER( _it_ ) \
    OPS( Sequence::_it_ ) \
    OP( Mapping::_it_, == , eql ) \
    OP( Mapping::_it_, != , neq ) \

    ITER( iterator )
    ITER( const_iterator )
#undef ITER

However, I think it may get in the way of clarity.


We can also tidy up the corresponding declarations in CXX/Python3/Objects.hxx

#ifdef PYCXX_PYTHON_2TO3
    // PyCXX for Python2 had an Int and LongLong classes
    typedef Long Int;
#ifdef HAVE_LONG_LONG
    typedef Long LongLong;
#endif
#endif

#define OPS( A, B ) \
    bool operator == ( A, B ); \
    bool operator != ( A, B ); \
    bool operator >  ( A, B ); \
    bool operator <  ( A, B ); \
    bool operator >= ( A, B ); \
    bool operator <= ( A, B );

#define BI_( A, B ) \
    OPS( A, B ) \
    OPS( B, A )

    OPS( const Long &a, const Long &b )
    BI_( const Long &a, int b )
    BI_( const Long &a, long b )

    //------------------------------------------------------------
    // compare operators
//    bool operator!=( const Long &a, const Long &b );
//    bool operator!=( const Long &a, int b );
//    bool operator!=( const Long &a, long b );
//    bool operator!=( int a, const Long &b );
//    bool operator!=( long a, const Long &b );
//    //------------------------------
//    bool operator==( const Long &a, const Long &b );
//    bool operator==( const Long &a, int b );
//    bool operator==( const Long &a, long b );
//    bool operator==( int a, const Long &b );
//    bool operator==( long a, const Long &b );
//    //------------------------------
//    bool operator>( const Long &a, const Long &b );
//    bool operator>( const Long &a, int b );
//    bool operator>( const Long &a, long b );
//    bool operator>( int a, const Long &b );
//    bool operator>( long a, const Long &b );
//    //------------------------------
//    bool operator>=( const Long &a, const Long &b );
//    bool operator>=( const Long &a, int b );
//    bool operator>=( const Long &a, long b );
//    bool operator>=( int a, const Long &b );
//    bool operator>=( long a, const Long &b );
//    //------------------------------
//    bool operator<( const Long &a, const Long &b );
//    bool operator<( const Long &a, int b );
//    bool operator<( const Long &a, long b );
//    bool operator<( int a, const Long &b );
//    bool operator<( long a, const Long &b );
//    //------------------------------
//    bool operator<=( const Long &a, const Long &b );
//    bool operator<=( int a, const Long &b );
//    bool operator<=( long a, const Long &b );
//    bool operator<=( const Long &a, int b );
//    bool operator<=( const Long &a, long b );

#ifdef HAVE_LONG_LONG
    BI_( const Long &a, PY_LONG_LONG b )

    //------------------------------
//    bool operator!=( const Long &a, PY_LONG_LONG b );
//    bool operator!=( PY_LONG_LONG a, const Long &b );
//    //------------------------------
//    bool operator==( const Long &a, PY_LONG_LONG b );
//    bool operator==( PY_LONG_LONG a, const Long &b );
//    //------------------------------
//    bool operator>( const Long &a, PY_LONG_LONG b );
//    bool operator>( PY_LONG_LONG a, const Long &b );
//    //------------------------------
//    bool operator>=( const Long &a, PY_LONG_LONG b );
//    bool operator>=( PY_LONG_LONG a, const Long &b );
//    //------------------------------
//    bool operator<( const Long &a, PY_LONG_LONG b );
//    bool operator<( PY_LONG_LONG a, const Long &b );
//    //------------------------------
//    bool operator<=( const Long &a, PY_LONG_LONG b );
//    bool operator<=( PY_LONG_LONG a, const Long &b );
#endif

#undef BI_
#undef OPS
#undef OP

Objects.hxx again:

#define OP( _it_ , _op_ ) \
    template <TEMPLATE_TYPENAME T> bool operator _op_( \
                                                      const EXPLICIT_TYPENAME MapBase<T>::_it_ &left, \
                                                      const EXPLICIT_TYPENAME MapBase<T>::_it_ &right ); \
    extern bool operator _op_( \
                              const Mapping::_it_ &left, \
                              const Mapping::_it_ &right );

    OP( iterator        , == )
    OP( iterator        , != )
    OP( const_iterator  , == )
    OP( const_iterator  , != )

#undef OP

//    template <TEMPLATE_TYPENAME T> bool operator==( const EXPLICIT_TYPENAME MapBase<T>::iterator        &left, const EXPLICIT_TYPENAME MapBase<T>::iterator         &right );
//    template <TEMPLATE_TYPENAME T> bool operator!=( const EXPLICIT_TYPENAME MapBase<T>::iterator        &left, const EXPLICIT_TYPENAME MapBase<T>::iterator         &right );
//    template <TEMPLATE_TYPENAME T> bool operator==( const EXPLICIT_TYPENAME MapBase<T>::const_iterator  &left, const EXPLICIT_TYPENAME MapBase<T>::const_iterator   &right );
//    template <TEMPLATE_TYPENAME T> bool operator!=( const EXPLICIT_TYPENAME MapBase<T>::const_iterator  &left, const EXPLICIT_TYPENAME MapBase<T>::const_iterator   &right );
//
//    extern bool operator==( const Mapping::iterator       &left, const Mapping::iterator       &right );
//    extern bool operator!=( const Mapping::iterator       &left, const Mapping::iterator       &right );
//    extern bool operator==( const Mapping::const_iterator &left, const Mapping::const_iterator &right );
//    extern bool operator!=( const Mapping::const_iterator &left, const Mapping::const_iterator &right );

And again:

#define OP( op, func, param_a, param_b, expr_A, expr_B ) \
    inline Object operator op( param_a, param_b ) { return asObject( func(expr_A,expr_B) ); }

#define OPS( ... ) \
    OP( +, PyNumber_Add         , __VA_ARGS__ ) \
    OP( -, PyNumber_Subtract    , __VA_ARGS__ ) \
    OP( *, PyNumber_Multiply    , __VA_ARGS__ ) \
    OP( /, PyNumber_TrueDivide  , __VA_ARGS__ ) \
    OP( %, PyNumber_Remainder   , __VA_ARGS__ )

#define BI_( param_a, param_b, expr_A, expr_B ) \
    OPS( param_a, param_b, expr_A, expr_B ) \
    OPS( param_b, param_a, expr_B, expr_A )

    //------------------------------------------------------------
    // operator +
    OP( +, PyNumber_Add, long j         , const Object &b, *Long(j), *b       )
    OP( +, PyNumber_Add, const Object &b, long j         , *b      , *Long(j) )

    OPS( const Object &a, const Object &b   , *a, *b        )
    BI_( const Object &a, int b             , *a, *Long(b)  )
    BI_( const Object &a, double b          , *a, *Float(b) )

#undef BI_
#undef UNI
#undef OPS
#undef OP

//    inline Object operator+( long j, const Object &b )          {return asObject( PyNumber_Add( *Long( j ), *b ) );}
//    inline Object operator+( const Object &a, long j )          {return asObject( PyNumber_Add( *a, *Long( j ) ) );}

//    inline Object operator+( const Object &a, const Object &b ) {return asObject( PyNumber_Add( *a, *b ) );}
//    inline Object operator+( const Object &a, int j )           {return asObject( PyNumber_Add( *a, *Long( j ) ) );}
//    inline Object operator+( const Object &a, double v )        {return asObject( PyNumber_Add( *a, *Float( v ) ) );}
//    inline Object operator+( int j, const Object &b )           {return asObject( PyNumber_Add( *Long( j ), *b ) );}
//    inline Object operator+( double v, const Object &b )        {return asObject( PyNumber_Add( *Float( v ), *b ) );}
//
//    //------------------------------------------------------------
//    // operator -
//    inline Object operator-( const Object &a, const Object &b ) {return asObject( PyNumber_Subtract( *a, *b ) );}
//    inline Object operator-( const Object &a, int j )           {return asObject( PyNumber_Subtract( *a, *Long( j ) ) );}
//    inline Object operator-( const Object &a, double v )        {return asObject( PyNumber_Subtract( *a, *Float( v ) ) );}
//    inline Object operator-( int j, const Object &b )           {return asObject( PyNumber_Subtract( *Long( j ), *b ) );}
//    inline Object operator-( double v, const Object &b )        {return asObject( PyNumber_Subtract( *Float( v ), *b ) );}
//
//    //------------------------------------------------------------
//    // operator *
//    inline Object operator*( const Object &a, const Object &b ) {return asObject( PyNumber_Multiply( *a, *b ) );}
//    inline Object operator*( const Object &a, int j )           {return asObject( PyNumber_Multiply( *a, *Long( j ) ) );}
//    inline Object operator*( const Object &a, double v )        {return asObject( PyNumber_Multiply( *a, *Float( v ) ) );}
//    inline Object operator*( int j, const Object &b )           {return asObject( PyNumber_Multiply( *Long( j ), *b ) );}
//    inline Object operator*( double v, const Object &b )        {return asObject( PyNumber_Multiply( *Float( v ), *b ) );}
//
//    //------------------------------------------------------------
//    // operator /
//    inline Object operator/( const Object &a, const Object &b ) {return asObject( PyNumber_TrueDivide( *a, *b ) );}
//    inline Object operator/( const Object &a, int j )           {return asObject( PyNumber_TrueDivide( *a, *Long( j ) ) );}
//    inline Object operator/( const Object &a, double v )        {return asObject( PyNumber_TrueDivide( *a, *Float( v ) ) );}
//    inline Object operator/( int j, const Object &b )           {return asObject( PyNumber_TrueDivide( *Long( j ), *b ) );}
//    inline Object operator/( double v, const Object &b )        {return asObject( PyNumber_TrueDivide( *Float( v ), *b ) );}
//
//    //------------------------------------------------------------
//    // operator %
//    inline Object operator%( const Object &a, const Object &b ) {return asObject( PyNumber_Remainder( *a, *b ) );}
//    inline Object operator%( const Object &a, int j )           {return asObject( PyNumber_Remainder( *a, *Long( j ) ) );}
//    inline Object operator%( const Object &a, double v )        {return asObject( PyNumber_Remainder( *a, *Float( v ) ) );}
//    inline Object operator%( int j, const Object &b )           {return asObject( PyNumber_Remainder( *Long( j ), *b ) );}
//    inline Object operator%( double v, const Object &b )        {return asObject( PyNumber_Remainder( *Float( v ), *b ) );}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License