/* vim: ts=4 sw=4 sts=4 ff=unix fenc=utf-8 : * ===================================================================== * sc_list.c * Copyright (c) 2003 - 2011 sys0tem * LICENSE : * LGPL (GNU Lesser General Public License - Version 3,29 June 2007) * http://www.gnu.org/copyleft/lesser.html * or * EPL (Eclipse Public License - v1.0) * http://www.eclipse.org/legal/epl-v10.html * ===================================================================== */ #include <string.h> #include <sc_os.h> #include <sc_error.h> #include <sc_mmgr.h> #include <sc_list.h> /* --------------------------------------------------------------------- * プロトタイプ宣言 * --------------------------------------------------------------------- */ static void* SC_List_add (SC_List*, int index, const void* obj, size_t size); static char* SC_List_addStr(SC_List* list, int index, const char* obj); static void* SC_List_get (SC_List*, int index, size_t* size); static char* SC_List_getStr(SC_List*, int index); static void SC_List_remove(SC_List*, int index); static void SC_List_clear (SC_List*); static SC_List_Entry* SC_List_search(SC_List* list, int index); static SC_List_Entry* SC_List_newEntry(const void* obj, size_t size); SC_List* SC_List_new(void) { SC_List* list; size_t size; size = sizeof(SC_List) + (sizeof(SC_List_Entry) * 2); list = (SC_List*) malloc(size); if (list == NULL) { /* メモリ確保失敗 */ return NULL; } list->_head = (SC_List_Entry*) (list + 1); list->_tail = list->_head + 1; /* 初期設定 */ list->size = 0; list->_head->next = list->_head->prev = list->_tail; list->_tail->next = list->_tail->prev = list->_head; list->_head->value = list->_tail->value = NULL; list->add = SC_List_add; list->addStr = SC_List_addStr; list->get = SC_List_get; list->getStr = SC_List_getStr; list->remove = SC_List_remove; list->clear = SC_List_clear; return list; } /** * リストを破棄します。 * [注意] 参照していた値も破棄します。 * * @param list リスト */ void SC_List_delete(SC_List* list) { list->clear(list); free(list); } /** * リストの指定された index 位置にオブジェクトを挿入します。 * オブジェクトはコピーされ、リストに保持されます。 * 不正なインデックスが指定された場合、エラーコード SC_EINVAL が * メモリの確保に失敗した場合、エラーコード SC_ENOMEM がセットされ、 * NULL を返します。 * * @param list リスト * @param index インデックス * @param obj 挿入するオブジェクト * @param size オブジェクトのサイズ * @return 挿入したオブジェクトのコピー */ static void* SC_List_add(SC_List* list, int index, const void* obj, size_t size) { SC_List_Entry* entry; SC_List_Entry* insertEntry; /* 挿入位置取得 */ insertEntry = SC_List_search(list, index); if (insertEntry == NULL) { /* 挿入位置不正 */ return NULL; } /* エントリ作成 */ entry = SC_List_newEntry(obj, size); if (entry == NULL) { /* メモリ確保失敗 */ return NULL; } /* リストに追加 (insertEntry より1つ前に追加) */ list->size++; entry->next = insertEntry; entry->prev = insertEntry->prev; insertEntry->prev->next = entry; insertEntry->prev = entry; return entry->value; } /** * リストの指定された index 位置に文字列を挿入します。 * 文字列はコピーされ、リストに保持されます。 * 不正なインデックスが指定された場合、エラーコード SC_EINVAL が * メモリの確保に失敗した場合、エラーコード SC_ENOMEM がセットされ、 * NULL を返します。 * * @param list リスト * @param index インデックス * @param obj 挿入する文字列 * @return 挿入した文字列のコピー */ static char* SC_List_addStr(SC_List* list, int index, const char* obj) { return (char*) SC_List_add(list, index, obj, strlen(obj) + 1); } /** * 指定されたインデックス位置にある値を取得します。 * size には、取得された値のサイズが格納されます。 * (値のサイズが不要な場合、NULL を指定することが可能です。) * 不正なインデックスが指定された場合、エラーコード * SC_EINVAL がセットされ、NULL が返されます。 * * @param list リスト * @param index インデックス * @param size 値のサイズが格納される * @return 値 */ static void* SC_List_get(SC_List* list, int index, size_t* size) { SC_List_Entry* entry; entry = SC_List_search(list, index); if ((entry == NULL) || (entry == list->_tail)) { /* インデックス不正 */ SC_setError(SC_EINVAL); return NULL; } if (size != NULL) { /* サイズ格納 */ *size = entry->size; } return entry->value; } /** * 指定されたインデックス位置にある文字列を取得します。 * size には、取得された値のサイズが格納されます。 * (値のサイズが不要な場合、NULL を指定することが可能です。) * 不正なインデックスが指定された場合、エラーコード * SC_EINVAL がセットされ、NULL が返されます。 * * @param list リスト * @param index インデックス * @param size 値のサイズが格納される * @return 文字列 */ static char* SC_List_getStr(SC_List* list, int index) { return (char*) SC_List_get(list, index, NULL); } /** * 指定されたインデックス位置にある値を削除します。 * [注意] 参照していた値も削除されます。 * * @param list リスト * @param index インデックス */ static void SC_List_remove(SC_List* list, int index) { SC_List_Entry* entry; entry = SC_List_search(list, index); if ((entry == NULL) || (entry == list->_tail)) { /* インデックス不正 */ return; } entry->prev->next = entry->next; entry->next->prev = entry->prev; free(entry); list->size--; } /** * リストをクリアします。 * [注意] 参照していた値も削除されます。 * * @param list リスト */ static void SC_List_clear(SC_List* list) { SC_List_Entry* entry; entry = list->_head->next; while (entry != list->_tail) { entry = entry->next; free(entry->prev); } list->size = 0; list->_head->next = list->_head->prev = list->_tail; list->_tail->next = list->_tail->prev = list->_head; list->_head->value = list->_tail->value = NULL; } /** * リストより指定されたインデックスのエントリを取得します。 * インデックスが -1 または、現在の size 位置の場合、 * list->tail を返します。 * インデックス位置が不正な場合、エラーコード SC_EINVAL が * セットされ、NULL を返します。 * * @param list リスト * @param index インデックス * @return エントリ */ static SC_List_Entry* SC_List_search(SC_List* list, int index) { SC_List_Entry* tmpEntry; int i; int halfSize; if (index > (int) list->size) { /* インデックス位置不正 */ SC_setError(SC_EINVAL); return NULL; } if ((index == -1) || (index == (int) list->size)) { /* 最後尾 */ return list->_tail; } halfSize = (int) list->size / 2; if (index > halfSize) { /* 前方より検索 */ tmpEntry = list->_head; for (i = 0; i <= index; i++) { tmpEntry = tmpEntry->next; } } else { /* 後方より検索 */ tmpEntry = list->_tail; for (i = list->size; i > index; i--) { tmpEntry = tmpEntry->prev; } } return tmpEntry; } /** * 新たなエントリを生成します。 * 生成に失敗した場合、エラーコード SC_ENOMEM が * セットされ、NULL が返されます。 * * @param obj オブジェクト * @param size サイズ * @return リストエントリ */ static SC_List_Entry* SC_List_newEntry(const void* obj, size_t size) { size_t newSize = size + sizeof(SC_List_Entry); SC_List_Entry* entry = (SC_List_Entry*) malloc (newSize); if (entry == NULL) { /* メモリ確保失敗 */ SC_setError(SC_ENOMEM); return NULL; } entry->value = (entry + 1); entry->size = size; memcpy(entry->value, obj, size); return entry; }