Changeset 43

Show
Ignore:
Timestamp:
10/27/06 01:05:57 (2 years ago)
Author:
KirkMcDonald
Message:

More operator overload wrapping, and docs

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/html_doc/class_wrapping.html

    r42 r43  
    5353<dd>This allows the user to specify a different overload of opApply than the default. (The default is always the one that is lexically first.) The <span class="t_arg">iter_t</span> argument should be the type of the delegate that forms the argument to opApply. This might be e.g. <code>int delegate(inout int)</code>. Don't forget the <code>inout</code> modifiers!</dd> 
    5454 
    55 <dt><code>static void alt_iter(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), iter_t = <i>implementationDetail</i>) ();</code></dt> 
     55<dt><code>static void alt_iter(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">iter_t</span> = <i>implementationDetail</i>) ();</code></dt> 
    5656<dd>This wraps alternate iterator methods as Python methods that return iterator objects. The wrapped methods should have a signature like that of opApply. (In other words, they should be methods intended to be used with D's ability to iterate over delgates.) The <span class="t_arg">iter_t</span> argument should be the type of the delegate argument to the method. This will usually be derived automatically. 
    5757</dd> 
     
    8181<p>At the moment, only the following operator overloads are supported:</p> 
    8282 
    83 <p><code>opAdd, opSub, opMul, opDiv, opMod, opAnd, opOr, opXor, opShl, opShr, opCat, opAddAssign, opSubAssign, opMulAssign, opDivAssign, opModAssign, opAndAssign, opOrAssign, opXorAssign, opShlAssign, opShrAssign, opCatAssign, opIn_r, opCmp, opCall, opApply</code></p> 
     83<p><code>opAdd, opSub, opMul, opDiv, opMod, opAnd, opOr, opXor, opShl, opShr, opCat, opAddAssign, opSubAssign, opMulAssign, opDivAssign, opModAssign, opAndAssign, opOrAssign, opXorAssign, opShlAssign, opShrAssign, opCatAssign, opIn_r, opCmp, opCall, opApply, opIndex, opIndexAssign, opSlice, opSliceAssign</code></p> 
    8484 
    85 <p>Most notably missing from this list are <code>opIndex, opIndexAssign, opSlice</code>, and <code>opSliceAssign</code>. Support for these operators is forthcoming. Also missing from the list are <code>opUShr</code> and <code>opUShrAssign</code>. Python does not have an unsigned right-shift operator, so these operator overloads are not supported. (You may still wrap them with a normal method using <code>wrapped_class.def</code>, of course.) Also missing from the list is <code>opApplyReverse</code>. This must be wrapped explicitly with <code>alt_iter</code>.</p> 
     85<p>Missing from this list are <code>opUShr</code> and <code>opUShrAssign</code>. Python does not have an unsigned right-shift operator, so these operator overloads are not supported. (You may still wrap them with a normal method using <code>wrapped_class.def</code>, of course.) Also missing from the list is <code>opApplyReverse</code>. This must be wrapped explicitly with <code>wrapped_class.alt_iter</code>.</p> 
    8686 
    8787<!-- This is not yet implemented. 
    88 <p>Additionally, if a class provides a <code>length</code> property, Pyd will automatically make it available via Python's built-in function <code>len</code>. You may still wrap it with <code>prop</code> if you wish it to be available as a normal property.</p> 
     88<p>Additionally, if a class provides a <code>length</code> property, Pyd will automatically make it available via Python's built-in function <code>len</code>. You may still wrap it with <code>prop</code> or <code>def</code> if you wish it to be available as a normal property or method.</p> 
    8989--> 
    9090 
    91 <p>Notably <em>included</em> in the list is <code>opApply</code>. Pyd wraps D's iteration protocol with the help of Mikola Lysenko's StackThreads package.</p> 
     91<p><b>Notes on wrapped operators</b></p> 
     92 
     93<dl> 
     94<dt><code>opApply</code></dt> <dd>Pyd wraps D's iteration protocol with the help of Mikola Lysenko's StackThreads package.</dd> 
     95<dt><code>opIndex, opIndexAssign</code></dt> <dd>Pyd only supports these overloads if they have precisely one index argument. This is a limitation of the Python/C API.</dd> 
     96<dt><code>opSlice, opSliceAssign</code></dt> <dd>Pyd only supports these overloads if both of their two indexes are implicitly convertable to type <code>int</code>. This is a limitation of the Python/C API.</dd> 
     97<dt><code>opCat, opCatAssign</code></dt> <dd>Python does not have a dedicated array concatenation operator. The plus sign (<code>+</code>) is reused for this purpose. Therefore, odd behavior may result with classes that define both <code>opAdd/opAddAssign</code> and one or both of these operators. (Consider yourself warned.) However, the Python/C API considers addition and concatenation distinct operations, and so both of these sets of operator overloads are supported.</dd> 
     98<dt><code>opIn_r</code></dt> <dd>Python expects the <code>in</code> operator to return a boolean value (it is a containment test). D convention is for <code>in</code> to search for the value in the container, and to return a pointer to the found item, or <code>null</code> if the item is not found. That said, D does not enforce any particular signature on the <code>in</code> overload, while the Python/C API does. Pyd will check the boolean result of a call to <code>opIn_r</code>, and return that value to Python.</dd> 
     99</dl> 
    92100 
    93101<h3><a class="anchor" name="examples">Examples</a></h3> 
  • trunk/infrastructure/pyd/op_wrap.d

    r41 r43  
    2525 
    2626private import pyd.class_wrap; 
     27private import pyd.dg_convert; 
    2728private import pyd.func_wrap; 
    2829private import pyd.exception; 
     
    7677template wrapped_class_as_sequence(T) { 
    7778    static PySequenceMethods wrapped_class_as_sequence = { 
    78         null,                 /*sq_length*/ 
    79         opCat_wrap!(T),       /*sq_concat*/ 
    80         null,                 /*sq_repeat*/ 
    81         null,                 /*sq_item*/ 
    82         null,                 /*sq_slice*/ 
    83         null,                /*sq_ass_item*/ 
    84         null,                 /*sq_ass_slice*/ 
    85         null,                 /*sq_contains*/ 
    86         opCatAssign_wrap!(T), /*sq_inplace_concat*/ 
    87         null,                 /*sq_inplace_repeat*/ 
     79        null,                            /*sq_length*/ 
     80        opCat_wrap!(T),                  /*sq_concat*/ 
     81        null,                            /*sq_repeat*/ 
     82        opIndex_sequence_wrap!(T),       /*sq_item*/ 
     83        opSlice_wrap!(T),                /*sq_slice*/ 
     84        opIndexAssign_sequence_wrap!(T), /*sq_ass_item*/ 
     85        opSliceAssign_wrap!(T),          /*sq_ass_slice*/ 
     86        null,                            /*sq_contains*/ 
     87        opCatAssign_wrap!(T),            /*sq_inplace_concat*/ 
     88        null,                            /*sq_inplace_repeat*/ 
    8889    }; 
    8990} 
     
    9192template wrapped_class_as_mapping(T) { 
    9293    static PyMappingMethods wrapped_class_as_mapping = { 
    93         null,                 /*mp_length*/ 
    94         null,                 /*mp_subscript*/ 
    95         null,                /*mp_ass_subscript*/ 
     94        null,                           /*mp_length*/ 
     95        opIndex_mapping_wrap!(T),       /*mp_subscript*/ 
     96        opIndexAssign_mapping_wrap!(T), /*mp_ass_subscript*/ 
    9697    }; 
    9798} 
     
    99100template opfunc_binary_wrap(T, alias opfn) { 
    100101    alias wrapped_class_object!(T) wrap_object; 
     102    alias funcDelegInfoT!(typeof(&opfn)) Info; 
    101103    extern(C) 
    102104    PyObject* func(PyObject* self, PyObject* o) { 
    103         PyObject* temp_tuple = PyTuple_New(1); 
    104         if (temp_tuple is null) return null; 
    105         Py_INCREF(o); 
    106         PyTuple_SetItem(temp_tuple, 0, o); 
    107         PyObject* res = func_wrap!(opfn, 1, T).func(self, temp_tuple); 
    108         Py_DECREF(temp_tuple); 
    109         return res; 
     105        return exception_catcher(delegate PyObject*() { 
     106            auto dg = dg_wrapper((cast(wrap_object*)self).d_obj, &opfn); 
     107            return _py(dg(d_type!(Info.Meta.ArgType!(0))(o))); 
     108        }); 
    110109    } 
    111110} 
    112111 
    113112template opfunc_unary_wrap(T, alias opfn) { 
    114     alias wrapped_class_object!(T) wrap_object; 
    115113    extern(C) 
    116114    PyObject* func(PyObject* self) { 
     115        // func_wrap takes care of exception handling 
    117116        return func_wrap!(opfn, 0, T).func(self, null); 
    118117    } 
     
    132131template opindexassign_sequence_pyfunc(T) { 
    133132    alias wrapped_class_object!(T) wrap_object; 
     133    alias funcDelegInfoT!(typeof(&T.opIndexAssign)) Info; 
     134    alias Info.Meta.ArgType!(0) AssignT; 
    134135 
    135136    extern(C) 
    136137    int func(PyObject* self, int i, PyObject* o) { 
    137          
     138        return exception_catcher(delegate int() { 
     139            (cast(wrap_object*)self).d_obj.opIndexAssign(d_type!(AssignT)(o), i); 
     140            return 0; 
     141        }); 
     142    } 
     143
     144 
     145template opindexassign_mapping_pyfunc(T) { 
     146    alias wrapped_class_object!(T) wrap_object; 
     147    alias funcDelegInfoT!(typeof(&T.opIndexAssign)) Info; 
     148    alias Info.Meta.ArgType!(0) ValT; 
     149    alias Info.Meta.ArgType!(1) KeyT; 
     150 
     151    extern(C) 
     152    int func(PyObject* self, PyObject* key, PyObject* val) { 
     153        return exception_catcher(delegate int() { 
     154            (cast(wrap_object*)self).d_obj.opIndexAssign(d_type!(ValT)(val), d_type!(KeyT)(key)); 
     155            return 0; 
     156        }); 
     157    } 
     158
     159 
     160template opslice_pyfunc(T) { 
     161    alias wrapped_class_object!(T) wrap_object; 
     162 
     163    extern(C) 
     164    PyObject* func(PyObject* self, int i1, int i2) { 
     165        return exception_catcher(delegate PyObject*() { 
     166            return _py((cast(wrap_object*)self).d_obj.opSlice(i1, i2)); 
     167        }); 
     168    } 
     169
     170 
     171template opsliceassign_pyfunc(T) { 
     172    alias wrapped_class_object!(T) wrap_object; 
     173    alias funcDelegInfoT!(typeof(&T.opSliceAssign)) Info; 
     174    alias Info.Meta.ArgType!(0) AssignT; 
     175 
     176    extern(C) 
     177    int func(PyObject* self, int i1, int i2, PyObject* o) { 
     178        return exception_catcher(delegate int() { 
     179            (cast(wrap_object*)self).d_obj.opSliceAssign(d_type!(AssignT)(o), i1, i2); 
     180            return 0; 
     181        }); 
     182    } 
     183
     184 
     185template opin_wrap(T) { 
     186    alias wrapped_class_object!(T) wrap_object; 
     187    alias funcDelegInfoT!(typeof(&T.opIn_r)) Info; 
     188    alias Info.Meta.ArgType!(0) OtherT; 
     189     
     190    extern(C) 
     191    int func(PyObject* self, PyObject* val) { 
     192        return exception_catcher(delegate int() { 
     193            if ((cast(wrap_object*)self).d_obj.opIn_r(d_type!(OtherT)(val))) 
     194                return 1; 
     195            else 
     196                return 0; 
     197        }); 
    138198    } 
    139199} 
     
    159219// The rest of the file is composed of these short stubs 
    160220template opIndex_sequence_wrap(T) { 
    161     static if (is(typeof(&T.opIndex)) && 
    162                funcDelegInfoT!(typeof(&T.opIndex)).numArgs == 1 && 
    163                is(funcDelegInfoT!(typeof(&T.opIndex)).Meta.ArgType!(0) : int) 
     221    static if ( 
     222        is(typeof(&T.opIndex)) && 
     223        funcDelegInfoT!(typeof(&T.opIndex)).numArgs == 1 && 
     224        is(funcDelegInfoT!(typeof(&T.opIndex)).Meta.ArgType!(0) : int) 
    164225    ) { 
    165226        const intargfunc opIndex_sequence_wrap = &opindex_sequence_pyfunc!(T).func; 
     
    170231 
    171232template opIndexAssign_sequence_wrap(T) { 
    172     static if (true) { 
     233    static if ( 
     234        is(typeof(&T.opIndexAssign)) && 
     235        funcDelegInfoT!(typeof(&T.opIndexAssign)).numArgs == 2 && 
     236        is(funcDelegInfoT!(typeof(&T.opIndexAssign)).Meta.ArgType!(1) : int) 
     237    ) { 
     238        const intobjargproc opIndexAssign_sequence_wrap = &opindexassign_sequence_pyfunc!(T).func; 
     239    } else { 
    173240        const intobjargproc opIndexAssign_sequence_wrap = null; 
    174     } else { 
    175         const intobjargproc opIndexAssign_sequence_wrap = null; 
    176241    } 
    177242} 
    178243 
    179244template opIndex_mapping_wrap(T) { 
    180  
     245    static if ( 
     246        is(typeof(&T.opIndex)) && 
     247        funcDelegInfoT!(typeof(&T.opIndex)).numArgs == 1 && 
     248        !is(funcDelegInfoT!(typeof(&T.opIndex)).Meta.ArgType!(0) : int) 
     249    ) { 
     250        const binaryfunc opIndex_mapping_wrap = &opfunc_binary_wrap!(T, T.opIndex).func; 
     251    } else { 
     252        const binaryfunc opIndex_mapping_wrap = null; 
     253    } 
    181254} 
    182255 
    183256template opIndexAssign_mapping_wrap(T) { 
    184  
     257    static if ( 
     258        is(typeof(&T.opIndexAssign)) && 
     259        funcDelegInfoT!(typeof(&T.opIndexAssign)).numArgs == 2 && 
     260        !is(funcDelegInfoT!(typeof(&T.opIndexAssign)).Meta.ArgType!(1) : int) 
     261    ) { 
     262        const objobjargproc opIndexAssign_mapping_wrap = &opindexassign_mapping_pyfunc!(T).func; 
     263    } else { 
     264        const objobjargproc opIndexAssign_mapping_wrap = null; 
     265    } 
    185266} 
    186267 
    187268template opSlice_wrap(T) { 
    188  
     269    static if ( 
     270        is(typeof(&T.opSlice)) && 
     271        funcDelegInfoT!(typeof(&T.opSlice)).numArgs == 2 && 
     272        is(funcDelegInfoT!(typeof(&T.opSlice)).Meta.ArgType!(0) : int) && 
     273        is(funcDelegInfoT!(typeof(&T.opSlice)).Meta.ArgType!(1) : int) 
     274    ) { 
     275        const intintargfunc opSlice_wrap = opslice_pyfunc!(T).func; 
     276    } else { 
     277        const intintargfunc opSlice_wrap = null; 
     278    } 
    189279} 
    190280 
    191281template opSliceAssign_wrap(T) { 
    192  
     282    static if ( 
     283        is(typeof(&T.opSlice)) && 
     284        funcDelegInfoT!(typeof(&T.opSlice)).numArgs == 3 && 
     285        is(funcDelegInfoT!(typeof(&T.opSlice)).Meta.ArgType!(1) : int) && 
     286        is(funcDelegInfoT!(typeof(&T.opSlice)).Meta.ArgType!(2) : int) 
     287    ) { 
     288        const intintobjargproc opSliceAssign_wrap = opsliceassign_pyfunc!(T).func; 
     289    } else { 
     290        const intintobjargproc opSliceAssign_wrap = null; 
     291    } 
    193292} 
    194293 
     
    410509template opIn_wrap(T) { 
    411510    static if (is(typeof(&T.opIn_r))) { 
    412         const binaryfunc opIn_wrap = &opfunc_binary_wrap!(T, T.opIn_r).func; 
     511        const binaryfunc opIn_wrap = &opin_wrap.func; 
    413512    } else { 
    414513        const binaryfunc opIn_wrap = null;