Newer
Older
libkc / modules / src / kc_list_linked.c
  1. /**
  2. * @file kc_list_linked.c
  3. * @brief Linked リストモジュール
  4. * @copyright 2003 - 2023 Nomura Kei
  5. */
  6. #include <kc.h>
  7. #if defined(__GNUC__)
  8. #define _GNU_SOURCE 1
  9. #if !(KC_IS_WINDOWS)
  10. #define qsort_s qsort_r
  11. #endif
  12. #endif // defined(__GNUC__)
  13.  
  14. #include <stdlib.h>
  15. #include <stdint.h>
  16. #include <string.h>
  17. #include <errno.h>
  18.  
  19. #include <kc_lock_guard.h>
  20. #include <kc_memory.h>
  21. #include <kc_list.h>
  22. #include <kc_iterator.h>
  23.  
  24. /**
  25. * KcLinkedList Entry 情報
  26. */
  27. typedef struct KcLinkedListEntry_
  28. {
  29. void *value; //!< 値
  30. size_t size; //!< 値のサイズ
  31. struct KcLinkedListEntry_ *next; //!< 次のエントリ
  32. struct KcLinkedListEntry_ *prev; //!< 前のエントリ
  33. } KcLinkedListEntry;
  34.  
  35. /**
  36. * KcLinkedList 管理情報
  37. */
  38. typedef struct
  39. {
  40. mtx_t mutex; //!< ロック用
  41. size_t size; //!< エントリ数
  42. KcLinkedListEntry *head; //!< 先頭エントリ
  43. KcLinkedListEntry *tail; //!< 末尾エントリ
  44. } KcLinkedListInfo;
  45.  
  46. // =============================================================================
  47. // プロトタイプ宣言
  48. // =============================================================================
  49. static int KcLinkedList_size(KcList *list);
  50. static bool KcLinkedList_is_empty(KcList *list);
  51. static bool KcLinkedList_contains(KcList *list, const void *element, size_t size);
  52. static bool KcLinkedList_add(KcList *list, int index, const void *element, size_t size);
  53. static bool KcLinkedList_remove(KcList *list, int index, void *element, size_t *size);
  54. static void KcLinkedList_sort(KcList *list,
  55. int (*comparator)(const void *element1, size_t size1,
  56. const void *element2, size_t size2, void *args),
  57. void *args);
  58. static void KcLinkedList_clear(KcList *list);
  59. static void *KcLinkedList_get(KcList *list, int index, size_t *size);
  60. static bool KcLinkedList_set(KcList *list, int index, const void *element, size_t size,
  61. void *org_element, size_t *org_size);
  62. static int KcLinkedList_index_of(KcList *list, const void *element, size_t size);
  63. static int KcLinkedList_last_index_of(KcList *list, const void *element, size_t size);
  64. static KcIterator *KcLinkedList_iterator(KcList *list, int index);
  65. static void KcLinkedList_cleanup_info(KcList *list);
  66.  
  67. // [内部関数用]
  68. static KcLinkedListEntry *KcLinkedList_search(KcLinkedListInfo *info, int index);
  69. static KcLinkedListEntry *KcLinkedList_new_entry(const void *value, size_t size);
  70.  
  71. /**
  72. * LinkedList を構築します。
  73. *
  74. * @return LinkedList
  75. */
  76. KcList *KcList_new_LinkedList(void)
  77. {
  78. // KcLinkedList の管理構造
  79. // +--------------+
  80. // | KcList |
  81. // | ... |
  82. // | _info -----------+
  83. // +--------------+ |
  84. // | <_info> | <---+
  85. // | next --------+
  86. // | prev --------|--+
  87. // +--------------+ | |
  88. // | <Entry> |<-+ |
  89. // | <Entry> |<----+
  90. // +--------------+
  91. KcList *list = (KcList *)malloc(
  92. sizeof(KcList) + sizeof(KcLinkedListInfo) + (sizeof(KcLinkedListEntry) * 2));
  93. if (list != NULL)
  94. {
  95. list->size = KcLinkedList_size;
  96. list->is_empty = KcLinkedList_is_empty;
  97. list->contains = KcLinkedList_contains;
  98. list->add = KcLinkedList_add;
  99. list->remove = KcLinkedList_remove;
  100. list->sort = KcLinkedList_sort;
  101. list->clear = KcLinkedList_clear;
  102. list->get = KcLinkedList_get;
  103. list->set = KcLinkedList_set;
  104. list->index_of = KcLinkedList_index_of;
  105. list->last_index_of = KcLinkedList_last_index_of;
  106. list->iterator = KcLinkedList_iterator;
  107. list->cleanup_info = KcLinkedList_cleanup_info;
  108. list->_info = (list + 1);
  109.  
  110. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  111. mtx_init(&(info->mutex), mtx_plain | mtx_recursive);
  112. info->head = (KcLinkedListEntry *)(info + 1);
  113. info->tail = info->head + 1;
  114. info->size = 0;
  115. info->head->next = info->head->prev = info->tail;
  116. info->tail->next = info->tail->prev = info->head;
  117. info->head->value = info->tail->value = NULL;
  118. }
  119. return list;
  120. }
  121.  
  122. // -----------------------------------------------------------------------------
  123. // size
  124. // -----------------------------------------------------------------------------
  125. /**
  126. * 対象リスト内にある要素の数を返します。
  127. *
  128. * @param list 対象リスト
  129. * @return 対象リスト内の要素数
  130. */
  131. static int KcLinkedList_size(KcList *list)
  132. {
  133. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  134. int size = -1;
  135. kc_lock_guard(&(info->mutex))
  136. {
  137. size = info->size;
  138. }
  139. return size;
  140. }
  141.  
  142. // -----------------------------------------------------------------------------
  143. // is_empty
  144. // -----------------------------------------------------------------------------
  145. /**
  146. * 対象リストに要素がない場合に true を返します。
  147. *
  148. * @param list 対象リスト
  149. * @return 対象リストに要素が含まれていない場合は true
  150. */
  151. static bool KcLinkedList_is_empty(KcList *list)
  152. {
  153. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  154. bool is_empty = true;
  155. kc_lock_guard(&(info->mutex))
  156. {
  157. is_empty = (info->size == 0);
  158. }
  159. return is_empty;
  160. }
  161.  
  162. // -----------------------------------------------------------------------------
  163. // contains
  164. // -----------------------------------------------------------------------------
  165. /**
  166. * 指定の要素が対象リストに含まれている場合に true を返します。
  167. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  168. *
  169. * @param list 対象リスト
  170. * @param element 対象リスト内にあるかどうか判定される要素
  171. * @param size 要素のサイズ
  172. * @return 指定された要素が対象リスト内にある場合は true
  173. */
  174. static bool KcLinkedList_contains(KcList *list, const void *element, size_t size)
  175. {
  176. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  177. bool is_contains = false;
  178. kc_lock_guard(&(info->mutex))
  179. {
  180. KcLinkedListEntry *entry = info->head->next;
  181. while (entry != info->tail)
  182. {
  183. if ((entry->size == size) && (memcmp(entry->value, element, size) == 0))
  184. {
  185. is_contains = true;
  186. break;
  187. }
  188. entry = entry->next;
  189. }
  190. }
  191. return is_contains;
  192. }
  193.  
  194. // -----------------------------------------------------------------------------
  195. // add
  196. // -----------------------------------------------------------------------------
  197. /**
  198. * 対象リスト内の指定された位置に、指定された要素を挿入します。
  199. * index に負値を指定した場合、末尾に要素を追加します。
  200. * その位置の現在の要素(ある場合)とそれ以降の要素を右に移動します。(インデックスに1を加算)。
  201. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  202. *
  203. * @param list 対象リスト
  204. * @param index 指定の要素が挿入される位置のインデックス
  205. * @param element 挿入される要素
  206. * @param size 要素のサイズ
  207. * @return true/false (格納成功/失敗)
  208. */
  209. static bool KcLinkedList_add(KcList *list, int index, const void *element, size_t size)
  210. {
  211. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  212. bool is_success = false;
  213. kc_lock_guard(&(info->mutex))
  214. {
  215. KcLinkedListEntry *insert_pos = KcLinkedList_search(info, index);
  216. if (insert_pos != NULL)
  217. { // エントリ作成
  218. KcLinkedListEntry *entry = KcLinkedList_new_entry(element, size);
  219. if (entry != NULL)
  220. { // リストに追加 (insert_pos の一つ前に追加)
  221. info->size++;
  222. entry->next = insert_pos;
  223. entry->prev = insert_pos->prev;
  224. insert_pos->prev->next = entry;
  225. insert_pos->prev = entry;
  226. is_success = true;
  227. }
  228. }
  229. }
  230. return is_success;
  231. }
  232.  
  233. // -----------------------------------------------------------------------------
  234. // remove
  235. // -----------------------------------------------------------------------------
  236. /**
  237. * 対象リスト内の指定された位置にある要素を削除します。
  238. * 後続の要素を左に移動します(インデックスから1を減算)。
  239. * element と size が共に NULL でない場合、削除された要素のコピーが格納されます。
  240. *
  241. * @param list 対象リスト
  242. * @param index 削除される要素のインデックス
  243. * @param element 削除された要素をコピーが格納されます。
  244. * @param size element のバッファサイズを指定します。また、削除された要素のサイズが格納されます。
  245. * @return true/false (削除成功/失敗)
  246. */
  247. static bool KcLinkedList_remove(KcList *list, int index, void *element, size_t *size)
  248. {
  249. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  250. bool is_success = false;
  251. kc_lock_guard(&(info->mutex))
  252. {
  253. KcLinkedListEntry *entry = KcLinkedList_search(info, index);
  254. if ((entry != NULL) && (entry != info->tail))
  255. {
  256. if ((element != NULL) && (size != NULL))
  257. {
  258. size_t copy_size = (entry->size < *size) ? entry->size : *size;
  259. memcpy(element, entry->value, copy_size);
  260. *size = entry->size;
  261. }
  262. entry->prev->next = entry->next;
  263. entry->next->prev = entry->prev;
  264. free(entry);
  265. info->size--;
  266. is_success = true;
  267. }
  268. }
  269. return is_success;
  270. }
  271.  
  272. // -----------------------------------------------------------------------------
  273. // sort
  274. // -----------------------------------------------------------------------------
  275.  
  276. /**
  277. * [内部利用]
  278. * ソート情報
  279. */
  280. typedef struct
  281. {
  282. int (*comparator)(const void *element1, size_t size1,
  283. const void *element2, size_t size2, void *args);
  284. size_t element_size;
  285. void *user_args;
  286. } KcListSortInfo;
  287.  
  288. /**
  289. * [内部利用]
  290. * KcLinkedList_sort にて利用される、qsort_s に渡される comparator です。
  291. *
  292. * @param x 比較する要素1
  293. * @param y 比較する要素2
  294. * @param context コンテキスト(KcListSortInfo)
  295. * @return 比較結果
  296. */
  297. #if (KC_IS_WINDOWS)
  298. static int KcLinkedList_comparator(void *context, const void *x, const void *y)
  299. #else
  300. static int KcLinkedList_comparator(const void *x, const void *y, void *context)
  301. #endif // KC_IS_WINDOWS
  302. {
  303. KcListSortInfo *sort_info = (KcListSortInfo *)context;
  304. const KcLinkedListEntry **entry_x = (const KcLinkedListEntry **)x;
  305. const KcLinkedListEntry **entry_y = (const KcLinkedListEntry **)y;
  306. int ret = sort_info->comparator(
  307. (*entry_x)->value,
  308. (*entry_x)->size,
  309. (*entry_y)->value,
  310. (*entry_y)->size,
  311. sort_info->user_args);
  312. return ret;
  313. }
  314.  
  315. /**
  316. * 指定された comparator が示す順序に従って、対象リストをソートします。
  317. *
  318. * @param list 対象リスト
  319. * @param comparator リスト要素を比較するために使用される comparator
  320. * @param args comparator の第5引数に渡すオブジェクト
  321. */
  322. static void KcLinkedList_sort(KcList *list,
  323. int (*comparator)(const void *element1, size_t size1,
  324. const void *element2, size_t size2, void *args),
  325. void *args)
  326. {
  327. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  328.  
  329. kc_lock_guard(&(info->mutex))
  330. {
  331. // Linked List エントリへのポインタを格納する配列を生成する。
  332. KcLinkedListEntry **ptr_list = (KcLinkedListEntry **)calloc(
  333. info->size, sizeof(KcLinkedListEntry *));
  334. int idx = 0;
  335. for (KcLinkedListEntry *entry = info->head->next; entry != info->tail; entry = entry->next)
  336. {
  337. ptr_list[idx] = entry;
  338. idx++;
  339. }
  340.  
  341. // ソート処理
  342. KcListSortInfo sort_info;
  343. sort_info.comparator = comparator;
  344. sort_info.user_args = args;
  345.  
  346. qsort_s(
  347. ptr_list,
  348. info->size,
  349. sizeof(KcLinkedListEntry *),
  350. KcLinkedList_comparator,
  351. &sort_info);
  352.  
  353. // 配列の情報を元にエントリを再構成する。
  354. KcLinkedListEntry *prev_entry = info->head;
  355. for (int idx2 = 0; idx2 < (int)info->size; idx2++)
  356. {
  357. KcLinkedListEntry *entry = ptr_list[idx2];
  358. prev_entry->next = entry;
  359. entry->prev = prev_entry;
  360. prev_entry = entry;
  361. }
  362. prev_entry->next = info->tail;
  363. info->tail->prev = prev_entry;
  364. free(ptr_list);
  365. }
  366. }
  367.  
  368. // -----------------------------------------------------------------------------
  369. // clear
  370. // -----------------------------------------------------------------------------
  371. /**
  372. * すべての要素を対象リストから削除します。
  373. *
  374. * @param list 対象リスト
  375. */
  376. static void KcLinkedList_clear(KcList *list)
  377. {
  378. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  379. kc_lock_guard(&(info->mutex))
  380. {
  381. KcLinkedListEntry *entry;
  382. entry = info->head->next;
  383. while (entry != info->tail)
  384. {
  385. entry = entry->next;
  386. free(entry->prev);
  387. }
  388. info->size = 0;
  389. info->head->next = info->head->prev = info->tail;
  390. info->tail->next = info->tail->prev = info->head;
  391. info->head->value = info->tail->value = NULL;
  392. }
  393. }
  394.  
  395. // -----------------------------------------------------------------------------
  396. // get
  397. // -----------------------------------------------------------------------------
  398. /**
  399. * 対象リスト内の指定された位置にある要素を返します。
  400. *
  401. * @param list 対象リスト
  402. * @param index 取得する要素のインデックス
  403. * @param size 要素のサイズを格納するポインタ
  404. * @return 対象リスト内の指定された位置にある要素
  405. */
  406. static void *KcLinkedList_get(KcList *list, int index, size_t *size)
  407. {
  408. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  409.  
  410. void *res = NULL;
  411. kc_lock_guard(&(info->mutex))
  412. {
  413. KcLinkedListEntry *entry = KcLinkedList_search(info, index);
  414. if ((entry != NULL) && (entry != info->tail))
  415. {
  416. res = entry->value;
  417. if (size)
  418. {
  419. *size = entry->size;
  420. }
  421. }
  422. else
  423. {
  424. errno = EINVAL;
  425. }
  426. }
  427. return res;
  428. }
  429.  
  430. // -----------------------------------------------------------------------------
  431. // set
  432. // -----------------------------------------------------------------------------
  433. /**
  434. * 対象リスト内の指定された位置にある要素を、指定された要素に置き換えます。
  435. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  436. * org_element と org_size が共にNULL でない場合、置き換え前の要素のコピーが格納されます。
  437. *
  438. * @param list 対象リスト
  439. * @param index 置換される要素のインデックス
  440. * @param element 指定された位置に格納される要素
  441. * @param size 指定された位置に格納される要素のサイズ
  442. * @param org_element 指定された位置に以前あった要素のコピーが格納されます。
  443. * @param org_size org_element のサイズを指定します。また、指定された位置に以前あった要素のサイズが格納されます。
  444. * @return true/false (置換成功/失敗)
  445. */
  446. static bool KcLinkedList_set(KcList *list, int index, const void *element, size_t size,
  447. void *org_element, size_t *org_size)
  448. {
  449. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  450. bool is_success = false;
  451. kc_lock_guard(&(info->mutex))
  452. {
  453. KcLinkedListEntry *remove_entry = KcLinkedList_search(info, index);
  454. if ((remove_entry != NULL) && (remove_entry != info->tail))
  455. {
  456. KcLinkedListEntry *new_entry = KcLinkedList_new_entry(element, size);
  457. if (new_entry)
  458. {
  459. if ((org_element != NULL) && (org_size != NULL))
  460. {
  461. size_t copy_size = (remove_entry->size < *org_size) ? remove_entry->size : *org_size;
  462. memcpy(org_element, remove_entry->value, copy_size);
  463. *org_size = remove_entry->size;
  464. }
  465. // 削除する位置に新たなエントリを追加
  466. new_entry->next = remove_entry->next;
  467. new_entry->prev = remove_entry->prev;
  468. remove_entry->prev->next = new_entry;
  469. remove_entry->next->prev = new_entry;
  470. free(remove_entry);
  471. is_success = true;
  472. }
  473. }
  474. }
  475. return is_success;
  476. }
  477.  
  478. // -----------------------------------------------------------------------------
  479. // index_of
  480. // -----------------------------------------------------------------------------
  481. /**
  482. * 指定された要素がこのリスト内で最初に検出された位置のインデックスを返します。
  483. * 指定された要素がこのリストにない場合は -1 を返します。
  484. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  485. *
  486. * @param list 対象リスト
  487. * @param element 検索する要素
  488. * @param size 検索する要素のサイズ
  489. * @return 指定された要素がこのリスト内で最初に検出された位置のインデックス
  490. */
  491. static int KcLinkedList_index_of(KcList *list, const void *element, size_t size)
  492. {
  493. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  494. int result_index = -1;
  495. kc_lock_guard(&(info->mutex))
  496. {
  497. int idx = 0;
  498. for (KcLinkedListEntry *entry = info->head->next; entry != info->tail; entry = entry->next)
  499. {
  500. if ((size == entry->size) && (memcmp(entry->value, element, entry->size) == 0))
  501. {
  502. result_index = idx;
  503. break;
  504. }
  505. idx++;
  506. }
  507. }
  508. return result_index;
  509. }
  510.  
  511. // -----------------------------------------------------------------------------
  512. // last_index_of
  513. // -----------------------------------------------------------------------------
  514. /**
  515. * 指定された要素がこのリスト内で最後に検出された位置のインデックスを返します。
  516. * 指定された要素がこのリストにない場合は -1 を返します。
  517. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  518. *
  519. * @param list 対象リスト
  520. * @param element 検索する要素
  521. * @param size 検索する要素のサイズ
  522. * @return 指定された要素がこのリスト内で最後に検出された位置のインデックス
  523. */
  524. static int KcLinkedList_last_index_of(KcList *list, const void *element, size_t size)
  525. {
  526. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  527. int result_index = -1;
  528. kc_lock_guard(&(info->mutex))
  529. {
  530. int idx = info->size;
  531. for (KcLinkedListEntry *entry = info->tail->prev; entry != info->head; entry = entry->prev)
  532. {
  533. idx--;
  534. if ((size == entry->size) && (memcmp(entry->value, element, entry->size) == 0))
  535. {
  536. result_index = idx;
  537. break;
  538. }
  539. }
  540. }
  541. return result_index;
  542. }
  543.  
  544. ////////////////////////////////////////////////////////////////////////////////
  545. //
  546. // Iterator
  547. //
  548.  
  549. /**
  550. * LinkedListe の Iterator 管理用構造体
  551. */
  552. typedef struct KcLinkedListIteratorEntry_
  553. {
  554. KcLinkedListInfo *info; //!< ArrayList情報
  555. KcLinkedListEntry *current; //!< 現在のエントリ
  556. } KcLinkedListIteratorEntry;
  557.  
  558. /**
  559. * 次の要素があるか否かを返します。
  560. *
  561. * @param ite Iterator
  562. * @return true/false (次の要素が存在する/存在しない)
  563. */
  564. static bool KcLinkedListIterator_hasNext(KcIterator *ite)
  565. {
  566. KcLinkedListIteratorEntry *entry = (KcLinkedListIteratorEntry *)ite->_info;
  567. return (entry->current != entry->info->tail);
  568. }
  569.  
  570. /**
  571. * 次の要素を取得します。
  572. * size が指定されている場合、次の要素が size に格納されます。
  573. * 次の要素がない場合、NULL を返します。
  574. *
  575. * @param ite Iterator
  576. * @param size 要素のサイズ格納用
  577. * @return 次の要素
  578. */
  579. static const void *KcLinkedListIterator_next(KcIterator *ite, size_t *size)
  580. {
  581. KcLinkedListIteratorEntry *entry = (KcLinkedListIteratorEntry *)ite->_info;
  582. if (size != NULL)
  583. {
  584. *size = entry->current->size;
  585. }
  586. entry->current = entry->current->next;
  587. return (entry->current->prev->value);
  588. }
  589.  
  590. /**
  591. * このリスト内の指定された位置で始まる、リスト内の要素を反復するイテレータを返します。
  592. *
  593. * @param list 対象リスト
  594. * @param index イテレータから返される最初の要素のインデックス
  595. * @return リスト内の指定された位置で始まる、リスト内の要素を反復するイテレータ
  596. */
  597. static KcIterator *KcLinkedList_iterator(KcList *list, int index)
  598. {
  599. size_t ite_size = sizeof(KcIterator) + sizeof(KcLinkedListIteratorEntry);
  600. KcIterator *ite = (KcIterator *)malloc(ite_size);
  601. if (ite)
  602. {
  603. ite->hasNext = KcLinkedListIterator_hasNext;
  604. ite->next = KcLinkedListIterator_next;
  605. KcLinkedListIteratorEntry *entry = (KcLinkedListIteratorEntry *)(((KcIterator *)ite) + 1);
  606. ite->_info = entry;
  607.  
  608. entry->info = list->_info;
  609. entry->current = KcLinkedList_search(entry->info, index);
  610. }
  611. return ite;
  612. }
  613.  
  614. /**
  615. * リスト情報をクリアします。
  616. *
  617. * @param list 対象リスト
  618. */
  619. static void KcLinkedList_cleanup_info(KcList *list)
  620. {
  621. KcLinkedListInfo *info = (KcLinkedListInfo *)list->_info;
  622. list->clear(list);
  623. mtx_destroy(&(info->mutex));
  624. }
  625.  
  626. ////////////////////////////////////////////////////////////////////////////////
  627. //
  628. // 内部関数
  629. //
  630.  
  631. /**
  632. * [内部関数] リストより指定されたインデックスのエントリを取得します。
  633. * インデックスが -1 または、現在の size 位置の場合、 tail を返します。
  634. * インデックス位置が不正な場合、エラーコード EINVAL がセットされ NULL を返します。
  635. *
  636. * @param info リスト情報
  637. * @param index インデックス
  638. * @return エントリ
  639. */
  640. static KcLinkedListEntry *KcLinkedList_search(KcLinkedListInfo *info, int index)
  641. {
  642.  
  643. KcLinkedListEntry *entry = NULL;
  644. kc_lock_guard(&(info->mutex))
  645. {
  646. if (index > (int)info->size)
  647. { // インデックス不正のためエラーを設定
  648. errno = EINVAL;
  649. }
  650. else if ((index == -1) || (index == (int)info->size))
  651. { // インデックス -1 or 末尾のため、tail を返す。
  652. entry = info->tail;
  653. }
  654. else
  655. {
  656. int half_size = info->size / 2;
  657. if (index < half_size)
  658. { // 前半のindexのため、前方より検索
  659. entry = info->head;
  660. for (int idx = 0; idx <= index; idx++)
  661. {
  662. entry = entry->next;
  663. }
  664. }
  665. else
  666. { // 後半のindexのため、後方より検索
  667. // head 0 1 2 3 tail
  668. entry = info->tail;
  669. for (int idx = info->size; idx > index; idx--)
  670. {
  671. entry = entry->prev;
  672. }
  673. }
  674. }
  675. }
  676. return entry;
  677. }
  678.  
  679. /**
  680. * 新たなエントリを生成します。
  681. * 生成に失敗した場合、errno に ENOMEM がセットされ、NULL が返されます。
  682. *
  683. * @param value 値
  684. * @param size サイズ
  685. * @return 生成したエントリ
  686. */
  687. static KcLinkedListEntry *KcLinkedList_new_entry(const void *value, size_t size)
  688. {
  689. size_t entry_size = size + sizeof(KcLinkedListEntry);
  690. KcLinkedListEntry *entry = (KcLinkedListEntry *)malloc(entry_size);
  691. if (entry != NULL)
  692. {
  693. entry->value = (entry + 1);
  694. entry->size = size;
  695. memcpy(entry->value, value, size);
  696. }
  697. else
  698. { // メモリ確保失敗
  699. errno = ENOMEM;
  700. }
  701. return entry;
  702. }