File-Raw

 view release on metacpan or  search on metacpan

file.c  view on Meta::CPAN

    HV *hash;
    SV **idx_sv;
    IV idx;

    PERL_UNUSED_VAR(items);

    if (PL_dirty) XSRETURN_EMPTY;

    if (!SvROK(ST(0)) || SvTYPE(SvRV(ST(0))) != SVt_PVHV) {
        XSRETURN_EMPTY;
    }

    hash = (HV*)SvRV(ST(0));
    idx_sv = hv_fetch(hash, "_idx", 4, 0);
    idx = idx_sv ? SvIV(*idx_sv) : -1;

    if (idx >= 0) {
        file_mmap_close(idx);
    }
    XSRETURN_EMPTY;
}

XS_INTERNAL(xs_lines_iter) {
    dXSARGS;
    const char *path;
    IV idx;
    SV *idx_sv;

    if (items < 1)
        croak("Usage: file::lines_iter(path [, plugin => ..., key => value ...])");

    path = SvPV_nolen(ST(0));

    /* Plugin path: slurp + dispatch READ, wrap the resulting AoA in an
     * iterator that walks records in order. This is eager (whole AoA
     * held in memory) - for true streaming use each_line($p, $cb,
     * plugin => ...). The iterator interface itself is preserved so
     * code that stores the iterator handle still composes. */
    if (items > 1) {
        HV *opts;
        SV *bytes;
        SV *out;
        AV *records;
        LineIterEntry *entry;

        opts = file_plugin_build_opts(aTHX_ &ST(0), 1, items, "lines_iter");
        bytes = file_slurp_internal(aTHX_ path);
        out = file_plugin_dispatch_read(aTHX_ opts, path, bytes);
        SvREFCNT_dec((SV *)opts);
        if (!out) {
            SvREFCNT_dec(bytes);
            ST(0) = &PL_sv_undef;
            XSRETURN(1);
        }
        if (out != bytes) SvREFCNT_dec(bytes);
        if (!SvROK(out) || SvTYPE(SvRV(out)) != SVt_PVAV) {
            SvREFCNT_dec(out);
            croak("File::Raw::lines_iter: plugin must return an arrayref of records");
        }
        records = (AV *)SvRV(out);
        SvREFCNT_inc(records);   /* keep the AV alive on its own */
        SvREFCNT_dec(out);       /* drop the RV wrapper */

        idx = alloc_iter_slot();
        entry = &g_iters[idx];
        entry->fd           = -1;        /* sentinel: no file behind us */
        entry->buffer       = NULL;
        entry->buf_size     = 0;
        entry->buf_pos      = 0;
        entry->buf_len      = 0;
        entry->eof          = 0;
        entry->refcount     = 1;
        entry->path         = NULL;
        entry->records      = records;
        entry->records_idx  = 0;

        idx_sv = newSViv(idx);
        ST(0) = sv_2mortal(sv_bless(newRV_noinc(idx_sv),
                                    gv_stashpv("File::Raw::lines", GV_ADD)));
        XSRETURN(1);
    }

    idx = file_lines_open(aTHX_ path);

    if (idx < 0) {
        ST(0) = &PL_sv_undef;
        XSRETURN(1);
    }

    /* Use simple IV reference - much faster than hash */
    idx_sv = newSViv(idx);
    ST(0) = sv_2mortal(sv_bless(newRV_noinc(idx_sv), gv_stashpv("File::Raw::lines", GV_ADD)));
    XSRETURN(1);
}

XS_INTERNAL(xs_lines_iter_next) {
    dXSARGS;
    SV *rv;
    IV idx;
    LineIterEntry *entry;
    char *line_start;
    char *newline;
    size_t line_len;
    SV *result;
    ssize_t n;

    if (items != 1) croak("Usage: $iter->next");

    rv = ST(0);
    if (UNLIKELY(!SvROK(rv))) {
        croak("Invalid lines iterator object");
    }

    /* Direct IV access - no hash lookup */
    idx = SvIV(SvRV(rv));

    if (UNLIKELY(idx < 0 || idx >= g_iters_count)) {
        ST(0) = &PL_sv_undef;
        XSRETURN(1);
    }



( run in 1.479 second using v1.01-cache-2.11-cpan-14f38c9f855 )