Newer
Older
snipet / libsc / trunk / src / sc_list.c
  1. /* vim: ts=4 sw=4 sts=4 ff=unix fenc=utf-8 :
  2. * =====================================================================
  3. * sc_list.c
  4. * Copyright (c) 2003 - 2011 sys0tem
  5. * LICENSE :
  6. * LGPL (GNU Lesser General Public License - Version 3,29 June 2007)
  7. * http://www.gnu.org/copyleft/lesser.html
  8. * or
  9. * EPL (Eclipse Public License - v1.0)
  10. * http://www.eclipse.org/legal/epl-v10.html
  11. * =====================================================================
  12. */
  13. #include <string.h>
  14. #include <sc_os.h>
  15. #include <sc_error.h>
  16. #include <sc_mmgr.h>
  17. #include <sc_list.h>
  18.  
  19.  
  20. /* ---------------------------------------------------------------------
  21. * プロトタイプ宣言
  22. * ---------------------------------------------------------------------
  23. */
  24. static void* SC_List_add (SC_List*, int index, const void* obj, size_t size);
  25. static char* SC_List_addStr(SC_List* list, int index, const char* obj);
  26. static void* SC_List_get (SC_List*, int index, size_t* size);
  27. static char* SC_List_getStr(SC_List*, int index);
  28. static void SC_List_remove(SC_List*, int index);
  29. static void SC_List_clear (SC_List*);
  30. static SC_List_Entry* SC_List_search(SC_List* list, int index);
  31. static SC_List_Entry* SC_List_newEntry(const void* obj, size_t size);
  32.  
  33.  
  34. SC_List* SC_List_new(void)
  35. {
  36. SC_List* list;
  37. size_t size;
  38.  
  39. size = sizeof(SC_List) + (sizeof(SC_List_Entry) * 2);
  40. list = (SC_List*) malloc(size);
  41. if (list == NULL)
  42. { /* メモリ確保失敗 */
  43. return NULL;
  44. }
  45. list->_head = (SC_List_Entry*) (list + 1);
  46. list->_tail = list->_head + 1;
  47.  
  48. /* 初期設定 */
  49. list->size = 0;
  50. list->_head->next = list->_head->prev = list->_tail;
  51. list->_tail->next = list->_tail->prev = list->_head;
  52. list->_head->value = list->_tail->value = NULL;
  53.  
  54. list->add = SC_List_add;
  55. list->addStr = SC_List_addStr;
  56. list->get = SC_List_get;
  57. list->getStr = SC_List_getStr;
  58. list->remove = SC_List_remove;
  59. list->clear = SC_List_clear;
  60.  
  61. return list;
  62. }
  63.  
  64.  
  65. /**
  66. * リストを破棄します。
  67. * [注意] 参照していた値も破棄します。
  68. *
  69. * @param list リスト
  70. */
  71. void SC_List_delete(SC_List* list)
  72. {
  73. list->clear(list);
  74. free(list);
  75. }
  76.  
  77.  
  78. /**
  79. * リストの指定された index 位置にオブジェクトを挿入します。
  80. * オブジェクトはコピーされ、リストに保持されます。
  81. * 不正なインデックスが指定された場合、エラーコード SC_EINVAL が
  82. * メモリの確保に失敗した場合、エラーコード SC_ENOMEM がセットされ、
  83. * NULL を返します。
  84. *
  85. * @param list リスト
  86. * @param index インデックス
  87. * @param obj 挿入するオブジェクト
  88. * @param size オブジェクトのサイズ
  89. * @return 挿入したオブジェクトのコピー
  90. */
  91. static
  92. void* SC_List_add(SC_List* list, int index, const void* obj, size_t size)
  93. {
  94. SC_List_Entry* entry;
  95. SC_List_Entry* insertEntry;
  96.  
  97. /* 挿入位置取得 */
  98. insertEntry = SC_List_search(list, index);
  99. if (insertEntry == NULL)
  100. { /* 挿入位置不正 */
  101. return NULL;
  102. }
  103.  
  104. /* エントリ作成 */
  105. entry = SC_List_newEntry(obj, size);
  106. if (entry == NULL)
  107. { /* メモリ確保失敗 */
  108. return NULL;
  109. }
  110.  
  111. /* リストに追加 (insertEntry より1つ前に追加) */
  112. list->size++;
  113. entry->next = insertEntry;
  114. entry->prev = insertEntry->prev;
  115. insertEntry->prev->next = entry;
  116. insertEntry->prev = entry;
  117. return entry->value;
  118. }
  119.  
  120.  
  121. /**
  122. * リストの指定された index 位置に文字列を挿入します。
  123. * 文字列はコピーされ、リストに保持されます。
  124. * 不正なインデックスが指定された場合、エラーコード SC_EINVAL が
  125. * メモリの確保に失敗した場合、エラーコード SC_ENOMEM がセットされ、
  126. * NULL を返します。
  127. *
  128. * @param list リスト
  129. * @param index インデックス
  130. * @param obj 挿入する文字列
  131. * @return 挿入した文字列のコピー
  132. */
  133. static
  134. char* SC_List_addStr(SC_List* list, int index, const char* obj)
  135. {
  136. return (char*) SC_List_add(list, index, obj, strlen(obj) + 1);
  137. }
  138.  
  139.  
  140. /**
  141. * 指定されたインデックス位置にある値を取得します。
  142. * size には、取得された値のサイズが格納されます。
  143. * (値のサイズが不要な場合、NULL を指定することが可能です。)
  144. * 不正なインデックスが指定された場合、エラーコード
  145. * SC_EINVAL がセットされ、NULL が返されます。
  146. *
  147. * @param list リスト
  148. * @param index インデックス
  149. * @param size 値のサイズが格納される
  150. * @return 値
  151. */
  152. static
  153. void* SC_List_get(SC_List* list, int index, size_t* size)
  154. {
  155. SC_List_Entry* entry;
  156. entry = SC_List_search(list, index);
  157. if ((entry == NULL) || (entry == list->_tail))
  158. { /* インデックス不正 */
  159. SC_setError(SC_EINVAL);
  160. return NULL;
  161. }
  162.  
  163. if (size != NULL)
  164. { /* サイズ格納 */
  165. *size = entry->size;
  166. }
  167. return entry->value;
  168. }
  169.  
  170.  
  171. /**
  172. * 指定されたインデックス位置にある文字列を取得します。
  173. * size には、取得された値のサイズが格納されます。
  174. * (値のサイズが不要な場合、NULL を指定することが可能です。)
  175. * 不正なインデックスが指定された場合、エラーコード
  176. * SC_EINVAL がセットされ、NULL が返されます。
  177. *
  178. * @param list リスト
  179. * @param index インデックス
  180. * @param size 値のサイズが格納される
  181. * @return 文字列
  182. */
  183. static
  184. char* SC_List_getStr(SC_List* list, int index)
  185. {
  186. return (char*) SC_List_get(list, index, NULL);
  187. }
  188.  
  189.  
  190. /**
  191. * 指定されたインデックス位置にある値を削除します。
  192. * [注意] 参照していた値も削除されます。
  193. *
  194. * @param list リスト
  195. * @param index インデックス
  196. */
  197. static
  198. void SC_List_remove(SC_List* list, int index)
  199. {
  200. SC_List_Entry* entry;
  201. entry = SC_List_search(list, index);
  202. if ((entry == NULL) || (entry == list->_tail))
  203. { /* インデックス不正 */
  204. return;
  205. }
  206. entry->prev->next = entry->next;
  207. entry->next->prev = entry->prev;
  208. free(entry);
  209. list->size--;
  210. }
  211.  
  212.  
  213. /**
  214. * リストをクリアします。
  215. * [注意] 参照していた値も削除されます。
  216. *
  217. * @param list リスト
  218. */
  219. static void SC_List_clear(SC_List* list)
  220. {
  221. SC_List_Entry* entry;
  222. entry = list->_head->next;
  223. while (entry != list->_tail)
  224. {
  225. entry = entry->next;
  226. free(entry->prev);
  227. }
  228. list->size = 0;
  229. list->_head->next = list->_head->prev = list->_tail;
  230. list->_tail->next = list->_tail->prev = list->_head;
  231. list->_head->value = list->_tail->value = NULL;
  232. }
  233.  
  234.  
  235. /**
  236. * リストより指定されたインデックスのエントリを取得します。
  237. * インデックスが -1 または、現在の size 位置の場合、
  238. * list->tail を返します。
  239. * インデックス位置が不正な場合、エラーコード SC_EINVAL が
  240. * セットされ、NULL を返します。
  241. *
  242. * @param list リスト
  243. * @param index インデックス
  244. * @return エントリ
  245. */
  246. static
  247. SC_List_Entry* SC_List_search(SC_List* list, int index)
  248. {
  249. SC_List_Entry* tmpEntry;
  250. int i;
  251. int halfSize;
  252.  
  253. if (index > (int) list->size)
  254. { /* インデックス位置不正 */
  255. SC_setError(SC_EINVAL);
  256. return NULL;
  257. }
  258.  
  259. if ((index == -1) || (index == (int) list->size))
  260. { /* 最後尾 */
  261. return list->_tail;
  262. }
  263.  
  264. halfSize = (int) list->size / 2;
  265. if (index > halfSize)
  266. { /* 前方より検索 */
  267. tmpEntry = list->_head;
  268. for (i = 0; i <= index; i++)
  269. {
  270. tmpEntry = tmpEntry->next;
  271. }
  272. }
  273. else
  274. { /* 後方より検索 */
  275. tmpEntry = list->_tail;
  276. for (i = list->size; i > index; i--)
  277. {
  278. tmpEntry = tmpEntry->prev;
  279. }
  280. }
  281. return tmpEntry;
  282. }
  283.  
  284.  
  285. /**
  286. * 新たなエントリを生成します。
  287. * 生成に失敗した場合、エラーコード SC_ENOMEM が
  288. * セットされ、NULL が返されます。
  289. *
  290. * @param obj オブジェクト
  291. * @param size サイズ
  292. * @return リストエントリ
  293. */
  294. static
  295. SC_List_Entry* SC_List_newEntry(const void* obj, size_t size)
  296. {
  297. size_t newSize = size + sizeof(SC_List_Entry);
  298. SC_List_Entry* entry = (SC_List_Entry*) malloc (newSize);
  299. if (entry == NULL)
  300. { /* メモリ確保失敗 */
  301. SC_setError(SC_ENOMEM);
  302. return NULL;
  303. }
  304. entry->value = (entry + 1);
  305. entry->size = size;
  306. memcpy(entry->value, obj, size);
  307. return entry;
  308. }
  309.