C言語 で foreach

さすがに、チマチマmallocするのは面倒になってきたので、ちょっとLinkedList風なものを作ってみました。その最中に冗談で、なんちゃってforeachを書いたら動いてしまいました。(cygwin + gcc)

foreach (it, list) {
Point* p = it->element;
....
}

#本当に書いてみただけなので、バグとかあるかもしれません。

#include <stdio.h>
#include <stdlib.h>
void* xalloc(size_t sz)
{
void* p;
p = calloc(1, sz);
if (!p) exit(1);
return p;
}
/* Iterator */
typedef struct _iterator {
void* element;
struct _iterator* next;
} Iterator;
/* Linked List */
typedef struct _list {
int element_size;
struct _iterator* head;
struct _iterator* tail;
} List;
/* Linked Listの生成 */
#define list_alloc(list, type) \
    list = xalloc(sizeof(List)); \
    list->element_size = sizeof(type);
/* Iteratorに格納する要素のalloc */
void* list_new_element(List* list)
{
return xalloc(list->element_size);
}
/* Iteratorの取得 */
Iterator* get_iterator(List* list)
{
return list->head;
}
/* 要素を持っているか? */
int iterator_has_value(Iterator* ite)
{
return ite != NULL;
}
/* 次の要素を取得する */
void* iterator_next(Iterator* ite)
{
return ite->next;
}
/* Linked Listにオブジェクトを追加する */
void list_add(List* list, void* new_element)
{
if (list->tail == NULL) {
/* 最初の要素 */
list->tail = list->head = xalloc(sizeof(Iterator));
} else {
Iterator* old_tail = list->tail;
old_tail->next = xalloc(sizeof(Iterator));
list->tail = old_tail->next;
}
list->tail->element = new_element;
}
/* Linked Listを開放する */
void list_free(List* list)
{
Iterator* it = get_iterator(list);
while (1) {
Iterator* old_it = it;
if (it == NULL) break;
free(it->element);
it = it->next;
free(old_it);
}
}
/* なんちゃって foreach */
#define foreach(it, list) for(it = get_iterator(list); iterator_has_value(it); it = iterator_next(it))

追記:使ってない部分もあったので、追いおい、修正します。使用する側でallocしなくていいようにしました。

使い方は↓

typedef struct _point {
int x;
int y;
} Point;                        /* 適当な構造体サンプル */
int main(int argc, char** argv)
{
List* list;
Iterator* it;
int i;
list_alloc(list, Point);    /* リストを作る */
for (i = 0; i < 10; i++) {
Point* p1 = list_new_element(list);  /* リストに格納するelementの領域を貰う */
p1->x = i;
p1->y = i;
list_add(list, p1);     /* Point構造体をリストに追加する */
}
foreach (it, list) {        /* なんちゃってforeachの使い方 */
Point* p = it->element;
printf("point: (%d, %d)\n", p->x, p->y);
}
list_free(list);
return 0;
}

C++では、Boost.Foreach ってのがあるんですね。boost::lambda とか。。。

興味はあるんですが、C++を知らない。

追記:不要なキャストを削除しました。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


The reCAPTCHA verification period has expired. Please reload the page.

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください