stas        2004/07/14 23:23:21

  Modified:    src/modules/perl modperl_common_util.c modperl_common_util.h
               t/lib/TestAPRlib table.pm
               xs/APR/Table APR__Table.h
               xs/maps  apr_functions.map
               xs/tables/current/ModPerl FunctionTable.pm
               .        Changes
  Log:
  fix an old outstanding bug in the APR::Table's TIE interface with
  each()/values() over tables with multi-values keys. Now the produced
  order is correct and consistent with keys(). Though, values() works
  correctly only with perl 5.8.x and higher.
  Submitted by: Joe Schaefer
  
  Revision  Changes    Path
  1.3       +64 -6     modperl-2.0/src/modules/perl/modperl_common_util.c
  
  Index: modperl_common_util.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_common_util.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -u -r1.2 -r1.3
  --- modperl_common_util.c     22 Jun 2004 22:34:10 -0000      1.2
  +++ modperl_common_util.c     15 Jul 2004 06:23:20 -0000      1.3
  @@ -22,6 +22,41 @@
   
   #include "modperl_common_util.h"
   
  +
  +/* Prefetch magic requires perl 5.8 */
  +#if ((PERL_REVISION == 5) && (PERL_VERSION >= 8))
  +
  +/* A custom MGVTBL with mg_copy slot filled in allows us to FETCH a
  + * table entry immediately during iteration.  For multivalued keys
  + * this is essential in order to get the value corresponding to the
  + * current key, otherwise values() will always report the first value
  + * repeatedly.  With this MGVTBL the keys() list always matches up
  + * with the values() list, even in the multivalued case.  We only
  + * prefetch the value during iteration, because the prefetch adds
  + * overhead (an unnecessary FETCH call) to EXISTS and STORE
  + * operations.  This way they are only "penalized" when the perl
  + * program is iterating via each(), which seems to be a reasonable
  + * tradeoff.
  + */
  +
  +MP_INLINE static
  +int modperl_table_magic_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, 
  +                             const char *name, int namelen)
  +{
  +    /* prefetch the value whenever we're iterating over the keys */
  +    MAGIC *tie_magic = mg_find(nsv, PERL_MAGIC_tiedelem);
  +    SV *obj = SvRV(tie_magic->mg_obj);
  +    if (SvCUR(obj)) {
  +        SvGETMAGIC(nsv);
  +    }
  +    return 0;
  +}
  +
  +
  +static const MGVTBL modperl_table_magic_prefetch = {0, 0, 0, 0, 0, 
  +                                                    modperl_table_magic_copy};
  +#endif /* End of prefetch magic */
  +
   MP_INLINE SV *modperl_hash_tie(pTHX_ 
                                  const char *classname,
                                  SV *tsv, void *p)
  @@ -30,15 +65,25 @@
       SV *rsv = sv_newmortal();
   
       sv_setref_pv(rsv, classname, p);
  +
  +    /* Prefetch magic requires perl 5.8 */
  +#if ((PERL_REVISION == 5) && (PERL_VERSION >= 8))
  +    
  +    sv_magic(hv, NULL, PERL_MAGIC_ext, Nullch, -1);
  +    SvMAGIC(hv)->mg_virtual = (MGVTBL *)&modperl_table_magic_prefetch;
  +    SvMAGIC(hv)->mg_flags |= MGf_COPY;
  +
  +#endif /* End of prefetch magic */
  +
       sv_magic(hv, rsv, PERL_MAGIC_tied, Nullch, 0);
   
       return SvREFCNT_inc(sv_bless(sv_2mortal(newRV_noinc(hv)),
                                    gv_stashpv(classname, TRUE)));
   }
   
  -MP_INLINE void *modperl_hash_tied_object(pTHX_ 
  -                                         const char *classname,
  -                                         SV *tsv)
  +MP_INLINE SV *modperl_hash_tied_object_rv(pTHX_ 
  +                                          const char *classname,
  +                                          SV *tsv)
   {
       if (sv_derived_from(tsv, classname)) {
           if (SVt_PVHV == SvTYPE(SvRV(tsv))) {
  @@ -47,7 +92,7 @@
   
               if (SvMAGICAL(hv)) {
                   if ((mg = mg_find(hv, PERL_MAGIC_tied))) {
  -                    return (void *)MgObjIV(mg);
  +                    return mg->mg_obj;
                   }
                   else {
                       Perl_warn(aTHX_ "Not a tied hash: (magic=%c)", mg);
  @@ -58,7 +103,7 @@
               }
           }
           else {
  -            return (void *)SvObjIV(tsv);
  +            return tsv;
           }
       }
       else {
  @@ -67,7 +112,20 @@
                      "(expecting an %s derived object)", classname);
       }
   
  -    return NULL;
  +    return &PL_sv_undef;
  +}
  +
  +MP_INLINE void *modperl_hash_tied_object(pTHX_ 
  +                                         const char *classname,
  +                                         SV *tsv)
  +{
  +    SV *rv = modperl_hash_tied_object_rv(aTHX_ classname, tsv);
  +    if (SvROK(rv)) {
  +        return (void *)SvIVX(SvRV(rv));
  +    }
  +    else {
  +        return NULL;
  +    }
   }
   
   /* same as Symbol::gensym() */
  
  
  
  1.3       +4 -0      modperl-2.0/src/modules/perl/modperl_common_util.h
  
  Index: modperl_common_util.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_common_util.h,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -u -r1.2 -r1.3
  --- modperl_common_util.h     22 Jun 2004 22:34:10 -0000      1.2
  +++ modperl_common_util.h     15 Jul 2004 06:23:20 -0000      1.3
  @@ -75,6 +75,10 @@
                                  SV *tsv, void *p);
   
   /* tied %hash */
  +MP_INLINE SV *modperl_hash_tied_object_rv(pTHX_ 
  +                                          const char *classname,
  +                                          SV *tsv);
  +/* tied %hash */
   MP_INLINE void *modperl_hash_tied_object(pTHX_ const char *classname,
                                            SV *tsv);
   
  
  
  
  1.5       +39 -2     modperl-2.0/t/lib/TestAPRlib/table.pm
  
  Index: table.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/t/lib/TestAPRlib/table.pm,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -u -r1.4 -r1.5
  --- table.pm  15 Jul 2004 05:42:04 -0000      1.4
  +++ table.pm  15 Jul 2004 06:23:21 -0000      1.5
  @@ -11,13 +11,19 @@
   use APR::Table ();
   use APR::Pool ();
   
  -use APR::Const    -compile => ':table';
  +use APR::Const -compile => ':table';
   
   use constant TABLE_SIZE => 20;
   our $filter_count;
   
   sub num_of_tests {
  -    return 38;
  +    my $tests = 50;
  +
  +    # tied hash values() for a table w/ multiple values for the same
  +    # key
  +    $tests += 2 if $] >= 5.008;
  +
  +    return $tests;
   }
   
   sub test {
  @@ -173,6 +179,37 @@
               my_filter($key, $table->{$key});
           }
           ok $filter_count == TABLE_SIZE;
  +    }
  +
  +
  +    # each, values
  +    {
  +        my $table = APR::Table::make($pool, 2);
  +
  +        $table->add("first"  => 1);
  +        $table->add("second" => 2);
  +        $table->add("first"  => 3);
  +
  +        my $i = 0;
  +        while (my($a,$b) = each %$table) {
  +            my $key = ("first", "second")[$i % 2];
  +            my $val = ++$i;
  +
  +            ok t_cmp $a,           $key, "table each: key test";
  +            ok t_cmp $b,           $val, "table each: value test";
  +            ok t_cmp $table->{$a}, $val, "table each: get test";
  +
  +            ok t_cmp tied(%$table)->FETCH($a), $val,
  +                "table each: tied get test";
  +        }
  +
  +        # this doesn't work with Perl < 5.8
  +        if ($] >= 5.008) {
  +            ok t_cmp "1,2,3", join(",", values %$table),
  +                "table values";
  +            ok t_cmp "first,1,second,2,first,3", join(",", %$table),
  +                "table entries";
  +        }
       }
   
       # overlap and compress routines
  
  
  
  1.12      +38 -12    modperl-2.0/xs/APR/Table/APR__Table.h
  
  Index: APR__Table.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/APR/Table/APR__Table.h,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -u -r1.11 -r1.12
  --- APR__Table.h      4 Mar 2004 06:01:10 -0000       1.11
  +++ APR__Table.h      15 Jul 2004 06:23:21 -0000      1.12
  @@ -13,7 +13,6 @@
    * limitations under the License.
    */
   
  -#define mpxs_APR__Table_FETCH   apr_table_get
   #define mpxs_APR__Table_STORE   apr_table_set
   #define mpxs_APR__Table_DELETE  apr_table_unset
   #define mpxs_APR__Table_CLEAR   apr_table_clear
  @@ -122,26 +121,53 @@
   
   static MP_INLINE const char *mpxs_APR__Table_NEXTKEY(pTHX_ SV *tsv, SV *key)
   {
  -    apr_table_t *t = mp_xs_sv2_APR__Table(tsv); 
  +    apr_table_t *t;
  +    SV *rv = modperl_hash_tied_object_rv(aTHX_ "APR::Table", tsv);
  +    if (!SvROK(rv)) {
  +        Perl_croak(aTHX_ "Usage: $table->NEXTKEY($key): "
  +                   "first argument not an APR::Table object");
  +    }
  +
  +    t = (apr_table_t *)SvIVX(SvRV(rv)); 
   
       if (apr_is_empty_table(t)) {
           return NULL;
       }
   
  -    if (mpxs_apr_table_iterix(tsv) < apr_table_elts(t)->nelts) {
  -        return mpxs_apr_table_nextkey(t, tsv);
  +    if (key == NULL) {
  +        mpxs_apr_table_iterix(rv) = 0; /* reset iterator index */
  +    }
  +    
  +    if (mpxs_apr_table_iterix(rv) < apr_table_elts(t)->nelts) {
  +        return mpxs_apr_table_nextkey(t, rv);
       }
   
  +    mpxs_apr_table_iterix(rv) = 0;
  +    
       return NULL;
   }
   
  -static MP_INLINE const char *mpxs_APR__Table_FIRSTKEY(pTHX_ SV *tsv)
  -{
  -    mpxs_apr_table_iterix(tsv) = 0; /* reset iterator index */
  +/* Try to shortcut apr_table_get by fetching the key using the current
  + * iterator (unless it's inactive or points at different key).
  + */
  +static MP_INLINE const char *mpxs_APR__Table_FETCH(pTHX_ SV *tsv,
  +                                                   const char *key)
  +{
  +    SV* rv = modperl_hash_tied_object_rv(aTHX_ "APR::Table", tsv);
  +    const int i = mpxs_apr_table_iterix(rv);
  +    apr_table_t *t = (apr_table_t *)SvIVX(SvRV(rv));
  +    const apr_array_header_t *arr = apr_table_elts(t);
  +    apr_table_entry_t *elts = (apr_table_entry_t *)arr->elts;
   
  -    return mpxs_APR__Table_NEXTKEY(aTHX_ tsv, Nullsv);
  +    if (i > 0 && i <= arr->nelts && !strcasecmp(key, elts[i-1].key)) {
  +        return elts[i-1].val;
  +    }
  +    else {
  +        return apr_table_get(t, key);
  +    }
   }
   
  +
   static XS(MPXS_apr_table_get)
   {
       dXSARGS;
  @@ -153,11 +179,11 @@
       mpxs_PPCODE({
           APR__Table t = modperl_hash_tied_object(aTHX_ "APR::Table", ST(0));
           const char *key = (const char *)SvPV_nolen(ST(1));
  -    
  +
           if (!t) {
               XSRETURN_UNDEF;
           }
  -        
  +
           if (GIMME_V == G_SCALAR) {
               const char *val = apr_table_get(t, key);
   
  @@ -167,9 +193,9 @@
           }
           else {
               const apr_array_header_t *arr = apr_table_elts(t);
  -            apr_table_entry_t *elts  = (apr_table_entry_t *)arr->elts;
  +            apr_table_entry_t *elts = (apr_table_entry_t *)arr->elts;
               int i;
  -            
  +
               for (i = 0; i < arr->nelts; i++) {
                   if (!elts[i].key || strcasecmp(elts[i].key, key)) {
                       continue;
  
  
  
  1.83      +3 -3      modperl-2.0/xs/maps/apr_functions.map
  
  Index: apr_functions.map
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/maps/apr_functions.map,v
  retrieving revision 1.82
  retrieving revision 1.83
  diff -u -u -r1.82 -r1.83
  --- apr_functions.map 9 Jun 2004 14:46:22 -0000       1.82
  +++ apr_functions.map 15 Jul 2004 06:23:21 -0000      1.83
  @@ -253,12 +253,12 @@
   -apr_table_setn
    apr_table_unset
   -apr_table_vdo
  - const char *:DEFINE_FETCH | | apr_table_t *:t, const char *:key
    void:DEFINE_STORE | | apr_table_t *:t, const char *:key, const char *:value
    void:DEFINE_DELETE | | apr_table_t *:t, const char *:key
    void:DEFINE_CLEAR | | apr_table_t *:t
  - mpxs_APR__Table_FIRSTKEY
  - mpxs_APR__Table_NEXTKEY
  + const char *:DEFINE_FIRSTKEY | mpxs_APR__Table_NEXTKEY | SV *:tsv, SV *:key=Nullsv
  + mpxs_APR__Table_NEXTKEY | | SV *:tsv, SV *:key=&PL_sv_undef
  + mpxs_APR__Table_FETCH
    mpxs_APR__Table_EXISTS
   
   !MODULE=APR::File
  
  
  
  1.172     +27 -2     modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm
  
  Index: FunctionTable.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v
  retrieving revision 1.171
  retrieving revision 1.172
  diff -u -u -r1.171 -r1.172
  --- FunctionTable.pm  12 Jul 2004 08:19:40 -0000      1.171
  +++ FunctionTable.pm  15 Jul 2004 06:23:21 -0000      1.172
  @@ -2,7 +2,7 @@
   
   # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   # ! WARNING: generated by ModPerl::ParseSource/0.01
  -# !          Mon Jul 12 00:41:18 2004
  +# !          Wed Jul 14 22:25:32 2004
   # !          do NOT edit, any changes will be lost !
   # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   
  @@ -2619,6 +2619,27 @@
       ]
     },
     {
  +    'return_type' => 'SV *',
  +    'name' => 'modperl_hash_tied_object_rv',
  +    'attr' => [
  +      '__inline__'
  +    ],
  +    'args' => [
  +      {
  +        'type' => 'PerlInterpreter *',
  +        'name' => 'my_perl'
  +      },
  +      {
  +        'type' => 'const char *',
  +        'name' => 'classname'
  +      },
  +      {
  +        'type' => 'SV *',
  +        'name' => 'tsv'
  +      }
  +    ]
  +  },
  +  {
       'return_type' => 'int',
       'name' => 'modperl_header_parser_handler',
       'args' => [
  @@ -5598,7 +5619,7 @@
     },
     {
       'return_type' => 'const char *',
  -    'name' => 'mpxs_APR__Table_FIRSTKEY',
  +    'name' => 'mpxs_APR__Table_FETCH',
       'attr' => [
         'static',
         '__inline__'
  @@ -5611,6 +5632,10 @@
         {
           'type' => 'SV *',
           'name' => 'tsv'
  +      },
  +      {
  +        'type' => 'const char *',
  +        'name' => 'key'
         }
       ]
     },
  
  
  
  1.413     +5 -0      modperl-2.0/Changes
  
  Index: Changes
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/Changes,v
  retrieving revision 1.412
  retrieving revision 1.413
  diff -u -u -r1.412 -r1.413
  --- Changes   15 Jul 2004 05:40:14 -0000      1.412
  +++ Changes   15 Jul 2004 06:23:21 -0000      1.413
  @@ -12,6 +12,11 @@
   
   =item 1.99_15-dev
   
  +fix an old outstanding bug in the APR::Table's TIE interface with
  +each()/values() over tables with multi-values keys. Now the produced
  +order is correct and consistent with keys(). Though, values() works
  +correctly only with perl 5.8.x and higher. [Joe Schaefer]
  +
   require Perl 5.6.1, 5.6.0 isn't supported for a long time, but we
   weren't aborting at the Makefile.PL stage [Stas]
   
  
  
  

Reply via email to