;;
let code (c,_,_) = c
type quote
= { price
:int; } (* 銘柄の値段.実際には、他にも多くの情報が含まれている *) ;;
type response = {
req: request; (* どのリクエストに対するレスポンスか *)
body: quote; (* レスポンスの内容 *)
seq
:int; (* レスポンス中、何番目のメッセージか *) total
:int; (* 応答メッセージの総数 *) }
;;
(* 受信途中のレスポンスのバッファを次の連想テーブル(Map)で構成する。
OCamlのMapは、キーの型と比較関数をMap.Makeに渡せば得られる *)
struct
type t = request (* リクエスト型をキーとして *)
end)
;;
(* レスポンスを保持するバッファ。 一息で書いたのでやたら複雑な型だが、
リクエストをキー(上記)として、受信途中のレスポンスをペア (int * quote option array) で保持する。
このペアは (受信済みメッセージ数, 銘柄データの配列) という意味だ。
- 未受信のメッセージをNoneで埋めておきたいがため option 型の配列になっている。
- 同じキーをもつ複数のレスポンスを同時に扱う格納するため、リストにしてある。
- グローバル変数なのは醜いけれど、クロージャに入れればすぐになんとかなる
*)
let buf
: (int * quote
option array) list M
.t
ref = ref M
.empty
;;
(* 株価のリストをデータベースに保存する. ダミーで画面への出力関数にしてある *)
| Some q
-> Printf.printf
"%d;" q
.price
| None -> failwith "impossible"
end quotes;
;;
(*
メッセージrをバッファに格納する。 レスポンス全体が得られたら、saveで保存する。
*)
let receive_quote
(r
:response
) : unit = if r.total=1 then save (code r.req) [Some r.body] (* 総レコードが1件のみであればすぐに保存 *)
else begin
let map = !buf in
(* このリクエストに対するレスポンスのリスト(更新前) *)
let all = try M.find r.req map with Not_found -> [] in
(* バッファに新しいレスポンスを追加 *)
let newentry () =
let arr
= Array.make r
.total None
in (* レスポンス全体をNoneで初期化 *) arr.(r.seq) <- Some r.body;
buf := M.add r.req ((1, arr)::all) map (* 1つ受信しましたよとバッファを更新 *)
in
(* レスポンスのリストを走査し適切な位置に格納 / レスポンス全体が満たされたら保存 *)
let rec addentry rest = function
| [] -> newentry () (* 受信ずみレスポンスなし. 新しいレスポンスを追加する *)
| (cnt, arr) as y::ys -> (* 受信ずみレスポンスあり *)
match arr.(r.seq) with (* 当該の連番は受信済みか *)
| None ->
arr.(r.seq) <- Some r.body; (* レスポンスの該当する連番を満たす *)
if cnt+1=r.total then begin
(* レスポンス全体が満たされた. 保存後、この配列をバッファから除く *)
save
(code r
.req
) (Array.to_list arr
) (* 保存 *); buf
:= M
.add r
.req
(List.rev_append rest ys
) map
(* yの削除によりバッファを更新 *) end else
(* また足りない.受信済み数をインクリメントしバッファを更新 *)
buf
:= M
.add r
.req
(List.rev_append rest
((cnt
+1, arr
)::ys
)) map
| Some q -> (* このレスポンスでは格納済み. 次のレスポンスを見る *)
addentry (y::rest) ys
in
addentry [] all
end
;;
let test =
let a="A","1","4" and b = "B","1","2" in
let resps = [
{req=a; body={price=1100}; total=4; seq=0};
{req=a; body={price=1098}; total=4; seq=1};
{req=a; body={price=1100}; total=4; seq=0};
{req=b; body={price=910}; total=2; seq=0};
{req=a; body={price=1098}; total=4; seq=1};
{req=a; body={price=1081}; total=4; seq=2};
{req=a; body={price=1081}; total=4; seq=2};
{req=a; body={price=1120}; total=4; seq=3};
{req=b; body={price=940}; total=2; seq=1};
{req=a; body={price=1120}; total=4; seq=3};
] in
List.iter receive_quote resps