Max 5 API Reference
順序づけられたリストの項目 (item) を効果的に挿入、削除したいような場合、このようなリストを保守する Max の t_linklist データ構造が役に立ちます。ただし、リストのサイズが大きくなるにつれて、個々の項目へのランダムアクセスはかなり遅くなります。 t_linklist はデフォルトではスレッドセーフですが、単一スレッドアプリケーションのパフォーマンスの恩恵を受けるために、このスレッドセーフティ機能をオフにすることが可能です。その場合、リンクリストの使用が、本当に単一スレッドでなされるかどうかを(Max のスレッドモデルを理解した上で)確認してから、スレッドセーフティ機能をオフにするようにして下さい。
t_linklist は、デフォルトではMax オブジェクトへのポインタを保持しています。しかし、リンクリストが保持しているものを、linklist_flags() 関数を使って開放するようなオブジェクトではなく、データとして取り扱うことが可能です。
次のコードは、 t_linklist の使用法に関するシンプルな例です。5個のシンボルを格納した後のコードでは、格納したデータをソートし、特定の項目の検索を行い、項目を削除し、すべての項目を表示した後、構造体全体を開放しています。Max の中のシンボルが開放されることはないため、 linklist_flags() を使って、オブジェクトへのポインタではなく、格納されるデータを指定しています。
void mylistfun() { t_linklist *list; list = (t_linklist *)linklist_new(); linklist_flags(list, OBJ_FLAG_DATA); // データの追加 linklist_append(list, gensym("one")); linklist_append(list, gensym("two")); linklist_append(list, gensym("three")); linklist_append(list, gensym("four")); linklist_append(list, gensym("five")); // ソート (Sort) linklist_sort(list, (t_cmpfn)mysortfun); // 検索(Search) index = linklist_findfirst(list, &found, mysearchfun, gensym("four")); // find the "four" symbol if (index != -1) // 見つかった場合 (found) linklist_chuckindex(list, index); // 繰り返し処理 (iterate) linklist_funall(list, myprintfun, NULL); // 削除 (delete) linklist_chuck(list); }
ソート (sort) を行う関数はリストの中の2つの項目を比較し、第1の項目が第2の項目の前に置く必要がある場合に非ゼロの値を返します。
long mysortfun(void *a, void *b) { t_symbol *sa = (t_symbol *)a; t_symbol *sb = (t_symbol *)b; return strcmp(sa->s_name, sb->s_name) > 0; }
検索 (search) を行なう関数は linklist_findfirst() への最後の引数として渡されます。そして、この場合、合致したシンボルそのものが渡されます。Max のすべてのシンボルはユニークであるため、ここではポインタが等しいかどうかをテストしています。 もっと複雑なデータをリンクリストに格納した場合、より洗練された検索方法を使用することも可能です。
繰り返し処理(iteration) を行う関数はリストのすべての項目上で何らかの処理を行ないます。 linklist_funall() に渡す第3の引数は、繰り返し処理を行う関数の第2の引数として渡されます。この例では、この引数は全く使用していません
リンクリストの操作を行なう関数はまだまだ数多くあります。これらに関する記述は リンクリスト 関数リファレンス(Linked List function reference)で調べて下さい。
ハッシュテーブルはいくつかのデータをユニークなキーに関連付けるデータ構造です。キーの値が分かっている場合、リンクリストよりもずっと速くデータを検索することができます。この速さの差は、格納されているデータ項目の数が大きくなるにつれて顕著になります。Max のハッシュテーブル t_hashtab はシンボルへのポインタをキーとする動作に最適化されています。しかし、それぞれがユニークな値であれば、任意のポインタや数値を使うことも可能です。
t_hashtab を作成するには hashtab_new() を使います。項目を追加するには hashtab_store() を使います。追加された項目を検索するには hashtab_lookup() を使います。
リンクリストや配列とは対照的に、ハッシュテーブルは項目の順序に関して強い意味づけを持っていません。 hashtab_funall() を使用してすべての項目に対する繰り返し処理を行なうことはできますが、項目の追加や削除が行なわれるため、正確な処理の順序をコントロールすることはできません。また、ハッシュテーブルを「ソート」する手段はありません。
例:
次の例では、ハッシュテーブル (hashtab) を作成し、データ(この例では単純な数値になっています) を追加、検索して、ハッシュテーブル (hashtab) を削除する方法を示しています。
t_hashtab *tab = (t_hashtab *)hashtab_new(0); long result, value; hashtab_store(tab, gensym("a great number"), (t_object *)74); result = hashtab_lookup(tab, gensym("a great number"), (t_object **)value); if (!result) post("found the value and it is %ld",value); else post("did not find the value"); hashtab_chuck(tab);
パッチのデータを保守するために使用される Max の t_dictionary が t_hashtab として実装されていることを覚えておいて下さい。