    /*
     *  call-seq:
     *     term_doc_enum.to_json() -> string
     *
     *  Returns a json representation of the term doc enum. It will also add the
     *  term positions if they are available. You can speed this up by having the
     *  method return arrays instead of objects, simply by passing an argument to
     *  the to_json method. For example;
     *
     *    term_doc_enum.to_json() #=>
     *    # [
     *    #   {"document":1,"frequency":12},
     *    #   {"document":11,"frequency":1},
     *    #   {"document":29,"frequency":120},
     *    #   {"document":30,"frequency":3}
     *    # ]
     *
     *    term_doc_enum.to_json(:fast) #=>
     *    # [
     *    #   [1,12],
     *    #   [11,1],
     *    #   [29,120],
     *    #   [30,3]
     *    # ]
     */
    static VALUE
    frb_tde_to_json(int argc, VALUE *argv, VALUE self)
    {
        TermDocEnum *tde = (TermDocEnum *)DATA_PTR(self);
        VALUE rjson;
        char *json, *jp;
        int capa = 65536;
        char *format;
        char close = (argc > 0) ? ']' : '}';
        bool do_positions = tde->next_position != NULL;
        jp = json = ALLOC_N(char, capa);
        *(jp++) = '[';

        if (do_positions) {
            if (argc == 0) {
                format = "{\"document\":%d,\"frequency\":%d,\"positions\":[";
            }
            else {
                format = "[%d,%d,[";
            }
        }
        else {
            if (argc == 0) {
                format = "{\"document\":%d,\"frequency\":%d},";
            }
            else {
                format = "[%d,%d],";
            }
        }
        while (tde->next(tde)) {
            /* 100 chars should be enough room for an extra entry */
            if ((jp - json) + 100 + tde->freq(tde) * 20 > capa) {
                capa <<= 1;
                REALLOC_N(json, char, capa);
            }
            sprintf(jp, format, tde->doc_num(tde), tde->freq(tde));
            jp += strlen(jp);
            if (do_positions) {
                int pos;
                while (0 <= (pos = tde->next_position(tde))) {
                    sprintf(jp, "%d,", pos);
                    jp += strlen(jp);
                }
                if (*(jp - 1) == ',') jp--;
                *(jp++) = ']';
                *(jp++) = close;
                *(jp++) = ',';
            }
        }
        if (*(jp - 1) == ',') jp--;
        *(jp++) = ']';
        *jp = '\0';

        rjson = rb_str_new2(json);
        free(json);
        return rjson;
    }