単連結リストの整列 #63 別の機能を付加した関数を代わりに呼び出させる
さて。#60の最後で書いたように、
> 利用者が提供する比較処理にカウント処理を埋め込むことはできない
わけで、それならどうするかを考える必要がある。
利用者が提供する比較処理中に利用者自身が計数処理の埋め込みを強制させないのなら、
リスト側で利用者が提供する比較処理を含んだ計数処理付き比較処理を用意し、
この比較処理を整列関数listsortに引き渡すようにすることで、やりたいことがとりあえず実現できると思う。
インタフェイスを定義したintlist用の整列関数intlist_sortは以下のような感じで実現できるはずである。
struct combined_arg { void *arg; int (*issup)(cintelem_t, cintelem_t, void *); intlist_t list; }; static int issuperior(const void *p, const void *q, void *args) { (((struct combined_arg *)args)->list->compare_counts)++; return (((struct combined_arg *)args)->issup)(p, q, ((struct combined_arg *)args)->arg); } void intlist_sort(intlist_t list, int (*issup)(cintelem_t, cintelem_t, void *), void *arg) { struct combined_arg args; if (list == NULL) return; args.arg = arg; args.issup = issup; args.list = list; listsort(list, head, next, isvalid, swap, NULL, issuperior, &args); }
最初に定義した構造体combined_argは、
利用者が用意する比較処理、すなわちリスト要素の順位定義関数issupに渡されるべき利用者定義の任意引数argと、
リストが用意する計数処理付き比較処理を行う関数issuperior内で計数処理のために利用するリストの参照listと、
同じくissuperior内で比較処理を委譲するために必要なissupへの関数ポインタ、
この三つをまとめてissuperiorに渡せるようにしている。
関数issuperiorのシグニチャは順位定義関数として整列関数listsortに渡せるようにインタフェイスを合わせてある。
内部では、計数処理を行ったうえで、処理をcombined_arg構造体のissupメンバに委譲してその結果を返している。
そして、リストintlistの整列関数intlist_sortはcombined_arg構造体のメンバを適切に設定した上で、
汎用の整列関数listsortに順位定義関数としてissuperiorを与えて呼び出している。
多分これで動くと思うのだが。