Router-R3

 view release on metacpan or  search on metacpan

R3.xs  view on Meta::CPAN

                        --k; \
                        break; \
                } \
                ++j; \
            } \
        } \
    capture_n[i] = this_capture_n; \
    if( i < branch_n - 1 ) \
        first_capture_key_head[i+1] = this_capture_key_head_cursor; \
    char *errstr; \
    if( !r3_tree_insert_pathl_ex(r3, pattern, pattern_len, NULL, &target[i], &errstr) ) { \
        r3_tree_free(r3); \
        Safefree(pad); \
        croak_r3_errstr("insert path"); \
    } \
}

#ifdef PERL_R3_DEBUG
#define DUMP_PAD(pad) { \
    char *p = (char*)pad; \
    printf("DUMP_PAD: (%p)\n", (void*)pad); \
    printf("  r3=%p\n", (void*)(*(node**)p)); \
    p += sizeof(node*); \
    int branch_n = *(int*)p; \
    p += sizeof(int); \
    printf("  branch_n=%d\n  targets:", branch_n); \
    for(int i=0; i<branch_n; ++i) { \
        printf(" %p", (void*)(*(SV**)p)); \
        p += sizeof(SV*); \
    } \
    printf("\n  capture_n:"); \
    for(int i=0; i<branch_n; ++i) { \
        printf(" %d", *(int*)p); \
        p += sizeof(int); \
    } \
    printf("\n  first_capture_key_head:"); \
    for(int i=0; i<branch_n; ++i) { \
        printf(" %p", (void*)(*(char***)p)); \
        p += sizeof(char**); \
    } \
    printf("\n  capture_key:"); \
    for(int i=0; i<capture_n_total; ++i) { \
        printf(" (%p,%p)", (void*)(*(char**)p), (void*)(*(char**)(p + sizeof(char*)))); \
        for(char *pp=*(char**)p; pp!=*(char**)(p + sizeof(char*)); ++pp) \
            printf("%c", *pp); \
        p += sizeof(char*) * 2; \
    } \
    printf("\n  capture_key_pool: "); \
    for(int i=0; i<capture_key_len_total; ++i) { \
        printf("%c", *(char*)p); \
        ++p; \
    } \
    printf("\n"); \
}
#else
#define DUMP_PAD(pad) ;
#endif

void
new(...)
    PPCODE:
        {
            void *r3_pad;
            int branch_n = 0;
            int capture_n_total = 0;
            int capture_key_len_total = 0;
            if( items == 0 )
                croak("Router::R3::new without classname?");
            if( items == 2 && SvROK(ST(1)) ) {
                SV *rv = SvRV(ST(1));
                switch( SvTYPE(rv) ) {
                    case SVt_PVAV: { // [pattern, target, pattern, target, ...]
                        AV *av = (AV*)rv;
                        SSize_t len = av_len(av);
                        if( !(len & 1) )
                            warn("Router::R3::new with odd length array");
                        branch_n = len + 1 >> 1;
                        for(SSize_t i=0; i<=len; i+=2){
                            SV** key = av_fetch(av, i, 0);
                            if( !key || !SvPOK(*key) )
                                warn("The %dth element of the new call argument array should be a string", i);
                            STRLEN pattern_len;
                            char * pattern;
                            if( key )
                                pattern = SvPVbyte(*key, pattern_len);
                            else {
                                pattern = "";
                                pattern_len = 0;
                            }
                            ANALYZE_PATTERN(pattern, pattern_len);
                        }
                        break;
                    }
                    case SVt_PVHV: { // {pattern => target, pattern => target, ...}
                        HV *hv = (HV*)rv;
                        branch_n = hv_iterinit(hv);
                        char *pattern;
                        I32 pattern_len;
                        HE *he;
                        while( he = hv_iternext(hv) ){
                            pattern = hv_iterkey(he, &pattern_len);
                            ANALYZE_PATTERN(pattern, pattern_len);
                        }
                        break;
                    }
                    default:
                        warn("Router::R3::new with invalid reference");
                }
            } else if( items > 2 ) { // pattern, target, pattern, target, ...
                branch_n = items >> 1;
                if( !(items & 1) )
                    warn("Router::R3::new with odd arguments");
                for(I32 i=1; i<items; i+=2) {
                    SV * key = ST(i);
                    if( !SvPOK(key) )
                        warn("The %dth argument for new call should be a string", i);
                    STRLEN pattern_len;
                    char * pattern = SvPVbyte(key, pattern_len);
                    ANALYZE_PATTERN(pattern, pattern_len);
                }
            }

R3.xs  view on Meta::CPAN

                                else{
                                    pattern = "";
                                    pattern_len = 0;
                                }
                                FILL_PATTERN(r3_pad, r3, i2, pattern, pattern_len, (pval ? *pval : NULL));
                            }
                            break;
                        }
                        case SVt_PVHV: { // {pattern => target, pattern => target, ...}
                            HV *hv = (HV*)rv;
                            hv_iterinit(hv);
                            char *pattern;
                            I32 pattern_len;
                            SV *val;
                            I32 i2 = 0;
                            while( val = hv_iternextsv(hv, &pattern, &pattern_len) ){
                                FILL_PATTERN(r3_pad, r3, i2, pattern, pattern_len, val);
                                ++i2;
                            }
                            break;
                        }
                        default:
                            warn("Router::R3::new with invalid reference");
                    }
                } else if( items > 2 ) { // pattern, target, pattern, target, ...
                    I32 i;
                    for(i=1; i<items; i+=2) {
                        I32 i2 = i >> 1;
                        SV *val = i+1 < items ? ST(i+1) : NULL;
                        STRLEN pattern_len;
                        char * pattern = SvPVbyte(ST(i), pattern_len);
                        FILL_PATTERN(r3_pad, r3, i2, pattern, pattern_len, val);
                    }
                }
                DUMP_PAD(r3_pad);
                int errno;
                char *errstr;
                if(( errno = r3_tree_compile(r3, &errstr) )) {
                    r3_tree_free(r3);
                    Safefree(r3_pad);
                    croak_r3_errstr("creating R3 routing tree fail");
                }
            }

            SV* ret = newSV(0);
            SvUPGRADE(ret, SVt_RV);
            SvROK_on(ret);
            SvRV(ret) = (SV*)r3_pad;

            SV * obj = newRV_noinc(ret);
            STRLEN classname_len;
            char * classname = SvPVbyte(ST(0), classname_len);
            HV * stash = gv_stashpvn(classname, classname_len, 0);
            sv_bless(obj, stash);
            EXTEND(SP, 1);
            PUSHs(sv_2mortal(obj));
        }

void
match(SV* r3_sv, SV *str_sv)
    PPCODE:
        void* r3_pad = SvRV(SvRV(r3_sv));
        node* r3 = *(node**)r3_pad;

        char *str;
        STRLEN str_len;
        str = SvPVbyte(str_sv, str_len);

        match_entry* entry = match_entry_createl(str, str_len);
        node* matched_node = r3_tree_matchl(r3, str, str_len, entry);

        if( matched_node ){
            SV** target_p = (SV**) matched_node->data;
#ifdef PERL_R3_DEBUG
            printf("matched target_p = %p\n", (void*)target_p);
            printf("matched target = %p\n", (void*)(*(SV**)target_p));
#endif
            EXTEND(SP, 2);
            PUSHs(sv_2mortal(newSVsv(*(SV**)target_p)));

            HV* captures_hv = newHV();
            int capture_n = entry->vars->len;
            if( capture_n > 0 ) {
                int match_i = target_p - (SV**)( (char*)r3_pad + sizeof(node*) + sizeof(int) );
                int branch_n = *(int*)( (char*)r3_pad + sizeof(node*) );
                int my_capture_n = *(int*)( (char*)r3_pad + sizeof(node*) + sizeof(int) + sizeof(SV*) * branch_n + sizeof(int) * match_i );
                char **capture_key_cursor = *(char***)( (char*)r3_pad + sizeof(node*) + sizeof(int) + sizeof(SV*) * branch_n + sizeof(int) * branch_n + sizeof(char**) * match_i );
                char ** captures = entry->vars->tokens;
#ifdef PERL_R3_DEBUG
                printf("capture # = %d\n", entry->vars->len);
#endif
                for(int i=0; i<capture_n && i<my_capture_n; ++i){
#ifdef PERL_R3_DEBUG
                    printf("capture_key_cursor = %p -> %p\n", (void*)capture_key_cursor, (void*)*capture_key_cursor);
#endif
                    hv_store(
                        captures_hv,
                        *capture_key_cursor, *(capture_key_cursor+1) - *capture_key_cursor,
                        newSVpv(captures[i], 0),
                        0
                    );
                    capture_key_cursor += 2;
                }
            }
            PUSHs(sv_2mortal(newRV_noinc((SV*)captures_hv)));
        }
        match_entry_free(entry);

void DESTROY(SV* r3_sv)
    PPCODE:
        void* pad = SvRV(SvRV(r3_sv));
        int branch_n = *(int*)((char*)pad + sizeof(node*));
        SV** target = (SV**)((char*)pad + sizeof(node*) + sizeof(int));
        for(int i=0; i<branch_n; ++i)
            SvREFCNT_dec(target[i]);
        r3_tree_free(*(node**)pad);
        Safefree(pad);
        SvRV(SvRV(r3_sv)) = 0;

#ifdef PERL_R3_DEBUG

void
test()
    CODE:
        _test();

#endif



( run in 1.918 second using v1.01-cache-2.11-cpan-5511b514fd6 )