Gauche:イテレータの反転の汎用化
yamasushi(2013/03/26 04:23:30 UTC)イテレータの反転を汎用的にしてみました。
; イテレータ反転 (define-module inverter (use gauche.generator) (use util.stream) ; (use util.queue) (use gauche.threads) ; (export generator-inverter stream-inverter mtgenerator-inverter mtstream-inverter ; pipeline ) ) (select-module inverter) ;イテレータを反転してgeneratorにする手続きを返す ; produce ..... yield手続きを引数にもつ手続き ; consume ..... ジェネレータを引数にもつ手続き (define (generator-inverter) (^[produce consume] (consume (generate produce) ) ) ) ;イテレータを反転してstreamににする手続きを返す ; produce ..... yield手続きを引数にもつ手続き ; consume ..... ジェネレータを引数にもつ手続き (define (stream-inverter) (^[produce consume] (consume (iterator->stream (^[next end] (produce (^x (if (eof-object? x) (end) (next x) ) ) ) ) ) ) ) ) (define (mtqueue->generator mtq) (generate (^[yield] (let loop [(xc (dequeue/wait! mtq))] (if (eof-object? xc) (yield (eof-object)) (begin (yield xc) (loop (dequeue/wait! mtq) ) ) ) ) ) ) ) (define (mtqueue->stream mtq) (iterator->stream (^[next end] (let loop [(xc (dequeue/wait! mtq))] (if (eof-object? xc) (end) (begin (next xc) (loop (dequeue/wait! mtq) ) ) ) ) ) ) ) ;イテレータを反転してgeneratorなどににする手続き(スレッドを使用) ; mtquere->x ..... mtqueureからgeneratorなどにする手続き ; produce ..... yield手続きを引数にもつ手続き ; consume ..... ジェネレータを引数にもつ手続き (define (mt-inverter mtqueue->x produce consume :key (queue-size 100)) (define (make-producer mtq) (^ [] (guard (e [else (enqueue/wait! mtq (eof-object)) (print (standard-error-port) (ref e 'message) ) (raise e) ] ) (produce (cut enqueue/wait! mtq <>)) (enqueue/wait! mtq (eof-object)) ) ) ) (define (make-consumer mtq producer-thread) (^ [] (guard (e [else (print (standard-error-port) (ref e 'message) ) (thread-terminate! producer-thread) (raise e) ]) (consume (mtqueue->x mtq) ) ) ) ) (and-let* [ ( mtq (make-mtqueue :max-length queue-size)) ( p (make-thread (make-producer mtq ) ) ) ( c (make-thread (make-consumer mtq p ) ) ) (tc (thread-start! c)) (tp (thread-start! p)) ] (thread-join! tp) (thread-join! tc) ; <----consumerの値を返す ) ) ;イテレータを反転してgeneratorにする手続きを返す(スレッドを使用) ; produce ..... yield手続きを引数にもつ手続き ; consume ..... ジェネレータを引数にもつ手続き (define (mtgenerator-inverter :key (queue-size 100)) (^[produce consume] (mt-inverter mtqueue->generator produce consume :queue-size queue-size) ) ) ;イテレータを反転してstreamににする手続きを返す(スレッドを使用) ; produce ..... yield手続きを引数にもつ手続き ; consume ..... ジェネレータを引数にもつ手続き (define (mtstream-inverter :key (queue-size 100)) (^[produce consume] (mt-inverter mtqueue->stream produce consume :queue-size queue-size) ) ) ; cmd-x .... ( g yield ) : g ... source generator , yield .... output (define (pipeline inverter cmd-in cmd-out) (^[ g yield] (inverter (^[yield] (cmd-in g yield) ) (^g (cmd-out g yield) ) ) ) )
これを使い、ポートを「反転」します。
; ポートの反転 (define-module port-inverter (use gauche.vport) (use gauche.generator) (use gauche.uvector) ; (use inverter) (export mtport-inverter )) (select-module port-inverter) ; :key ; queue-size ..... スレッド同期につかうキューサイズ ; buffer-size ..... データ転送バッファサイズ ; ---> ; [^ (produce consume) ... ] ; produce .... 出力ポートを引数にもつ手続き(producer) ; consume .... 入力ポートを引数にもつ手続き(consumer) (define (mtport-inverter :key (queue-size 100) (buffer-size 8000) ) (let1 inverter (mtgenerator-inverter :queue-size queue-size) (^[produce consume] (inverter (^[yield] (let1 outp (make <buffered-output-port> :buffer-size buffer-size :flush (^ (u8v flag) (yield (u8vector-copy u8v)) (uvector-length u8v) ) ) (produce outp) (yield (eof-object)) )) (^g (let1 vp (make <buffered-input-port> :buffer-size buffer-size :fill (^(u8v-dst) (let1 u8v-src (g) (if (eof-object? u8v-src) 0 (let [(ndst (uvector-length u8v-dst)) (nsrc (uvector-length u8v-src ))] (if (>= ndst nsrc ) (begin (u8vector-copy! u8v-dst 0 u8v-src ) ;#?= u8v-dst nsrc ) (begin ; ここには来ないはずだが念の為 (error "ndst < nsrc") ) ) ) ) ) ) ) (consume vp) ) ) ) ) ) )
すると、http-getをcall-with系のようにアクセスできます。
; http-getのパラメタ指定してhttp-get、procに仮想ポートを渡す。 (define (call-with-input-http-get http-param proc :key (queue-size 100) (buffer-size 8000) ) (let1 inverter (mtport-inverter :queue-size queue-size :buffer-size buffer-size) (inverter (^[outp] (apply http-get (append http-param `(:sink ,outp :flusher ,(^ _ (flush outp) #t) )))) (^[inp] (proc inp) ) ) ) ) (define call-with-input-http call-with-input-http-get) ; http-postのパラメタ指定してhttp-post、procに仮想ポートを渡す。 (define (call-with-input-http-post http-param proc :key (queue-size 100) (buffer-size 8000) ) (let1 inverter (mtport-inverter :queue-size queue-size :buffer-size buffer-size) (inverter (^[outp] (apply http-post (append http-param `(:sink ,outp :flusher ,(^ _ (flush outp) #t) )))) (^[inp] (proc inp) ) ) ) )
Tags: gauche.generator, util.stream