Newer
Older
c-interpreter / modules / libkc / src / kc_list.c
Nomura Kei on 9 Aug 2023 18 KB UPDATE
  1. /**
  2. * @file kc_list.c
  3. * @brief リストモジュール
  4. * @copyright 2003 - 2023 Nomura Kei
  5. */
  6. #if defined(__GNUC__)
  7. #define _GNU_SOURCE 1
  8. #define qsort_s qsort_r
  9. #endif
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <stdint.h>
  13. #include <string.h>
  14.  
  15. #include <kc_lock_guard.h>
  16. #include <kc_memory.h>
  17. #include <kc_list.h>
  18.  
  19.  
  20.  
  21.  
  22.  
  23. ////////////////////////////////////////////////////////////////////////////////
  24. //
  25. // KcArrayList
  26. //
  27.  
  28.  
  29. /**
  30. * KcArrayList 管理情報
  31. */
  32. typedef struct
  33. {
  34. mtx_t mutex; //!< ロック用
  35. size_t element_size; //!< 要素のサイズ
  36. int init_capacity; //!< 初期指定容量
  37. int capacity; //!< 現在の容量
  38. int size; //!< 現在の要素数
  39. void* data; //!< データ格納用バッファ
  40. } KcArrayListInfo;
  41.  
  42.  
  43. // =============================================================================
  44. // プロトタイプ宣言
  45. // =============================================================================
  46. static int KcArrayList_size(KcList* list);
  47. static bool KcArrayList_is_empty(KcList* list);
  48. static bool KcArrayList_contains(KcList* list, const void* element, size_t size);
  49. static bool KcArrayList_add(KcList* list, int index, const void* element, size_t size);
  50. static bool KcArrayList_remove(KcList* list, int index, void* element, size_t* size);
  51. static void KcArrayList_sort(KcList* list,
  52. int (*comparator)(const void* element1, size_t size1,
  53. const void* element2, size_t size2, void* args), void* args);
  54. static void KcArrayList_clear(KcList* list);
  55. static void* KcArrayList_get(KcList* list, int index, size_t* size);
  56. static bool KcArrayList_set(KcList* list, int index, const void* element, size_t size,
  57. void* org_element, size_t* org_size);
  58. static int KcArrayList_index_of(KcList* list, const void* element, size_t size);
  59. static int KcArrayList_last_index_of(KcList* list, const void* element, size_t size);
  60. static KcIterator* KcArrayList_iterator(KcList* list, int index);
  61.  
  62. static bool KcArrayList_increase_capacity(KcArrayListInfo* info);
  63. static void KcArrayList_reduce_capacity(KcArrayListInfo* list);
  64. static bool KcArrayList_set_capacity(KcArrayListInfo* info, int capacity);
  65.  
  66.  
  67. /**
  68. * 指定されたサイズの要素を扱う ArrayList を構築します。
  69. *
  70. * @param size 要素のサイズ
  71. * @param cap リストの初期容量
  72. */
  73. KcList* KcArrayList_new_ArrayList(size_t size, int cap)
  74. {
  75. // KcArrayList の管理構造
  76. // +--------------+
  77. // | KcList |
  78. // | ... |
  79. // | _info -----------+
  80. // +--------------+ |
  81. // | <_info> | <---+
  82. // | element_size |
  83. // | capacity | +------------+
  84. // | data -------------->| <data> |
  85. // +--------------+ | element[0] |
  86. // | : |
  87. // +------------+
  88. KcList* list = (KcList*) malloc(sizeof(KcList) + sizeof(KcArrayListInfo));
  89. void* data = malloc(size * cap);
  90.  
  91. if ((list != NULL) && (data != NULL))
  92. {
  93. list->size = KcArrayList_size;
  94. list->is_empty = KcArrayList_is_empty;
  95. list->contains = KcArrayList_contains;
  96. list->add = KcArrayList_add;
  97. list->remove = KcArrayList_remove;
  98. list->sort = KcArrayList_sort;
  99. list->clear = KcArrayList_clear;
  100. list->get = KcArrayList_get;
  101. list->set = KcArrayList_set;
  102. list->index_of = KcArrayList_index_of;
  103. list->last_index_of = KcArrayList_last_index_of;
  104. list->iterator = KcArrayList_iterator;
  105. list->_info = (list + 1);
  106.  
  107. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  108. mtx_init(&(info->mutex), mtx_plain | mtx_recursive);
  109. info->element_size = size;
  110. info->init_capacity = cap;
  111. info->capacity = cap;
  112. info->size = 0;
  113. info->data = data;
  114. }
  115. else
  116. { // 何れかのメモリ確保に失敗したら、メモリを解放する。
  117. free(list);
  118. list = NULL;
  119. free(data);
  120. data = NULL;
  121. }
  122. return list;
  123. }
  124.  
  125.  
  126. // -----------------------------------------------------------------------------
  127. // size
  128. // -----------------------------------------------------------------------------
  129. /**
  130. * 対象リスト内にある要素の数を返します。
  131. *
  132. * @param list 対象リスト
  133. * @return 対象リスト内の要素数
  134. */
  135. static int KcArrayList_size(KcList* list)
  136. {
  137. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  138. int size = -1;
  139. kc_lock_guard(&(info->mutex))
  140. {
  141. size = info->size;
  142. }
  143. return size;
  144. }
  145.  
  146.  
  147. // -----------------------------------------------------------------------------
  148. // is_empty
  149. // -----------------------------------------------------------------------------
  150. /**
  151. * 対象リストに要素がない場合に true を返します。
  152. *
  153. * @param list 対象リスト
  154. * @return 対象リストに要素が含まれていない場合は true
  155. */
  156. static bool KcArrayList_is_empty(KcList* list)
  157. {
  158. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  159. bool is_empty = true;
  160. kc_lock_guard(&(info->mutex))
  161. {
  162. is_empty = (info->size == 0);
  163. }
  164. return is_empty;
  165. }
  166.  
  167.  
  168. // -----------------------------------------------------------------------------
  169. // contains
  170. // -----------------------------------------------------------------------------
  171. /**
  172. * 指定の要素が対象リストに含まれている場合に true を返します。
  173. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  174. *
  175. * @param list 対象リスト
  176. * @param element 対象リスト内にあるかどうか判定される要素
  177. * @param size 要素のサイズ
  178. * @return 指定された要素が対象リスト内にある場合は true
  179. */
  180. static bool KcArrayList_contains(KcList* list, const void* element, size_t size)
  181. {
  182. UNUSED_VARIABLE(size);
  183. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  184. typedef uint8_t element_type[info->element_size];
  185. element_type* info_data = (element_type*) info->data;
  186.  
  187. int res;
  188. bool is_contains = false;
  189. kc_lock_guard(&(info->mutex))
  190. {
  191. for (int idx = 0; idx < info->size; idx++)
  192. {
  193. res = memcmp(&info_data[idx], element, info->element_size);
  194. if (res == 0)
  195. {
  196. is_contains = true;
  197. break;
  198. }
  199. }
  200.  
  201. }
  202. return is_contains;
  203. }
  204.  
  205.  
  206. // -----------------------------------------------------------------------------
  207. // add
  208. // -----------------------------------------------------------------------------
  209. /**
  210. * 対象リスト内の指定された位置に、指定された要素を挿入します。
  211. * その位置の現在の要素(ある場合)とそれ以降の要素を右に移動します。(インデックスに1を加算)。
  212. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  213. *
  214. * @param list 対象リスト
  215. * @param index 指定の要素が挿入される位置のインデックス
  216. * @param element 挿入される要素
  217. * @param size 要素のサイズ
  218. * @return true/false (格納成功/失敗)
  219. */
  220. static bool KcArrayList_add(KcList* list, int index, const void* element, size_t size)
  221. {
  222. UNUSED_VARIABLE(size);
  223. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  224. typedef uint8_t element_type[info->element_size];
  225. element_type* info_data = (element_type*) info->data;
  226.  
  227. bool is_success = true;
  228. kc_lock_guard(&(info->mutex))
  229. {
  230. is_success = ((0 <= index) && (index <= info->size));
  231. is_success = is_success && KcArrayList_increase_capacity(info);
  232. if (is_success)
  233. {
  234. if (index < info->size)
  235. { // index 以降の要素を右に移動
  236. size_t n = (info->size - index) * info->element_size;
  237. memmove(&info_data[index + 1], &info_data[index], n);
  238. }
  239.  
  240. // データを追加
  241. memcpy(&info_data[index], element, info->element_size);
  242. info->size++;
  243. }
  244. }
  245. return is_success;
  246. }
  247.  
  248.  
  249. // -----------------------------------------------------------------------------
  250. // remove
  251. // -----------------------------------------------------------------------------
  252. /**
  253. * 対象リスト内の指定された位置にある要素を削除します。
  254. * 後続の要素を左に移動します(インデックスから1を減算)。
  255. * element が NULL でない場合、削除された要素のコピーが格納されます。
  256. * size が NULL でない場合、削除された要素のサイズが格納されます。
  257. *
  258. * @param list 対象リスト
  259. * @param index 削除される要素のインデックス
  260. * @param element 削除された要素をコピーが格納されます。
  261. * @param size 削除された要素のサイズが格納されます。
  262. * @return true/false (削除成功/失敗)
  263. */
  264. static bool KcArrayList_remove(KcList* list, int index, void* element, size_t* size)
  265. {
  266. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  267. typedef uint8_t element_type[info->element_size];
  268. element_type* info_data = (element_type*) info->data;
  269.  
  270. bool is_success = true;
  271. kc_lock_guard(&(info->mutex))
  272. {
  273. is_success = ((0 <= index) && (index < info->size));
  274. if (is_success)
  275. {
  276. if (element != NULL)
  277. {
  278. memcpy(element, &info_data[index], info->element_size);
  279. }
  280. if (size != NULL)
  281. {
  282. *size = info->element_size;
  283. }
  284.  
  285. if (index != (info->size - 1))
  286. { // index 以降の要素を左に移動
  287. size_t n = (info->size - (index + 1)) * info->element_size;
  288. memmove(&info_data[index], &info_data[index + 1], n);
  289. }
  290. info->size--;
  291. }
  292.  
  293. // 容量削減
  294. KcArrayList_reduce_capacity(info);
  295. }
  296. return is_success;
  297. }
  298.  
  299.  
  300.  
  301. // -----------------------------------------------------------------------------
  302. // sort
  303. // -----------------------------------------------------------------------------
  304. /**
  305. * [内部利用]
  306. * ソート情報
  307. */
  308. typedef struct
  309. {
  310. int (*comparator)(const void* element1, size_t size1,
  311. const void* element2, size_t size2, void* args);
  312. size_t element_size;
  313. void* user_args;
  314. } KcListSortInfo;
  315.  
  316.  
  317. /**
  318. * [内部利用]
  319. * KcArrayList_sort にて利用される、qsort_s に渡される comparator です。
  320. *
  321. * @param x 比較する要素1
  322. * @param y 比較する要素2
  323. * @param context コンテキスト(KcListSortInfo)
  324. * @return 比較結果
  325. */
  326. static int KcArrayList_comparator(const void* x, const void* y, void* context)
  327. {
  328. KcListSortInfo* sort_info = (KcListSortInfo*) context;
  329. int ret = sort_info->comparator(x, sort_info->element_size, y, sort_info->element_size, sort_info->user_args);
  330. return ret;
  331. }
  332.  
  333.  
  334. /**
  335. * 指定された comparator が示す順序に従って、対象リストをソートします。
  336. *
  337. * @param list 対象リスト
  338. * @param comparator リスト要素を比較するために使用される comparator
  339. * @param args comparator の第5引数に渡すオブジェクト
  340. * @return true/false (ソート成功/ソート失敗)
  341. */
  342. static void KcArrayList_sort(KcList* list,
  343. int (*comparator)(const void* element1, size_t size1,
  344. const void* element2, size_t size2, void* args), void* args)
  345. {
  346. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  347. typedef uint8_t element_type[info->element_size];
  348. element_type* info_data = (element_type*) info->data;
  349.  
  350. kc_lock_guard(&(info->mutex))
  351. {
  352. KcListSortInfo sort_info;
  353. sort_info.comparator = comparator;
  354. sort_info.element_size = info->element_size;
  355. sort_info.user_args = args;
  356.  
  357. qsort_s(
  358. info_data,
  359. info->size,
  360. info->element_size,
  361. KcArrayList_comparator,
  362. &sort_info);
  363. }
  364. }
  365.  
  366.  
  367. // -----------------------------------------------------------------------------
  368. // clear
  369. // -----------------------------------------------------------------------------
  370. /**
  371. * すべての要素を対象リストから削除します。
  372. *
  373. * @param list 対象リスト
  374. */
  375. static void KcArrayList_clear(KcList* list)
  376. {
  377. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  378.  
  379. kc_lock_guard(&(info->mutex))
  380. {
  381. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  382. info->size = 0;
  383.  
  384. KcArrayList_set_capacity(info, info->init_capacity);
  385. }
  386. }
  387.  
  388.  
  389. // -----------------------------------------------------------------------------
  390. // get
  391. // -----------------------------------------------------------------------------
  392. /**
  393. * 対象リスト内の指定された位置にある要素を返します。
  394. *
  395. * @param list 対象リスト
  396. * @param index 取得する要素のインデックス
  397. * @param size 要素のサイズを格納するポインタ
  398. * @return 対象リスト内の指定された位置にある要素
  399. */
  400. void* KcArrayList_get(KcList* list, int index, size_t* size)
  401. {
  402. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  403. typedef uint8_t element_type[info->element_size];
  404. element_type* info_data = (element_type*) info->data;
  405.  
  406. element_type* res = NULL;
  407. kc_lock_guard(&(info->mutex))
  408. {
  409. if ((0 <= index) && (index < info->size))
  410. {
  411. res = &info_data[index];
  412. if (size != NULL)
  413. {
  414. *size = info->element_size;
  415. }
  416. }
  417. }
  418. return res;
  419. }
  420.  
  421.  
  422. // -----------------------------------------------------------------------------
  423. // set
  424. // -----------------------------------------------------------------------------
  425. /**
  426. * 対象リスト内の指定された位置にある要素を、指定された要素に置き換えます。
  427. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  428. * org_element が NULL でない場合、置き換え前の要素のコピーが格納されます。
  429. * org_size が NULL でない場合、置き換え前の要素のサイズが格納されます。
  430. *
  431. * @param list 対象リスト
  432. * @param index 置換される要素のインデックス
  433. * @param element 指定された位置に格納される要素
  434. * @param size 指定された位置に格納される要素のサイズ
  435. * @param org_element 指定された位置に以前あった要素のコピーが格納されます。
  436. * @param org_size 指定された位置に以前あった要素のサイズが格納されます。
  437. * @return true/false (置換成功/失敗)
  438. */
  439. bool KcArrayList_set(KcList* list, int index, const void* element, size_t size,
  440. void* org_element, size_t* org_size)
  441. {
  442. UNUSED_VARIABLE(size);
  443. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  444. typedef uint8_t element_type[info->element_size];
  445. element_type* info_data = (element_type*) info->data;
  446.  
  447. bool is_success = true;
  448. kc_lock_guard(&(info->mutex))
  449. {
  450. is_success = ((0 <= index) && (index < info->size));
  451. if (is_success)
  452. {
  453. if (org_element != NULL)
  454. {
  455. memcpy(org_element, &info_data[index], info->element_size);
  456. }
  457. if (org_size != NULL)
  458. {
  459. *org_size = info->element_size;
  460. }
  461. memcpy(&info_data[index], element, info->element_size);
  462. }
  463. }
  464. return is_success;
  465. }
  466.  
  467.  
  468. // -----------------------------------------------------------------------------
  469. // index_of
  470. // -----------------------------------------------------------------------------
  471. /**
  472. * 指定された要素がこのリスト内で最初に検出された位置のインデックスを返します。
  473. * 指定された要素がこのリストにない場合は -1 を返します。
  474. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  475. *
  476. * @param list 対象リスト
  477. * @param element 検索する要素
  478. * @param size 検索する要素のサイズ
  479. * @return 指定された要素がこのリスト内で最初に検出された位置のインデックス
  480. */
  481. int KcArrayList_index_of(KcList* list, const void* element, size_t size)
  482. {
  483. UNUSED_VARIABLE(size);
  484. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  485. typedef uint8_t element_type[info->element_size];
  486. element_type* info_data = (element_type*) info->data;
  487.  
  488. int res;
  489. int result_index = -1;
  490. kc_lock_guard(&(info->mutex))
  491. {
  492. for (int idx = 0; idx < info->size; idx++)
  493. {
  494. res = memcmp(&info_data[idx], element, info->element_size);
  495. if (res == 0)
  496. {
  497. result_index = idx;
  498. break;
  499. }
  500. }
  501.  
  502. }
  503. return result_index;
  504. }
  505.  
  506.  
  507. // -----------------------------------------------------------------------------
  508. // last_index_of
  509. // -----------------------------------------------------------------------------
  510. /**
  511. * 指定された要素がこのリスト内で最後に検出された位置のインデックスを返します。
  512. * 指定された要素がこのリストにない場合は -1 を返します。
  513. * 要素サイズ固定のリストを扱う場合、size の値は無視されます。
  514. *
  515. * @param list 対象リスト
  516. * @param element 検索する要素
  517. * @param size 検索する要素のサイズ
  518. * @return 指定された要素がこのリスト内で最後に検出された位置のインデックス
  519. */
  520. int KcArrayList_last_index_of(KcList* list, const void* element, size_t size)
  521. {
  522. UNUSED_VARIABLE(size);
  523. KcArrayListInfo* info = (KcArrayListInfo*) list->_info;
  524. typedef uint8_t element_type[info->element_size];
  525. element_type* info_data = (element_type*) info->data;
  526.  
  527. int res;
  528. int result_index = -1;
  529. kc_lock_guard(&(info->mutex))
  530. {
  531. for (int idx = (info->size - 1); idx >= 0; idx--)
  532. {
  533. res = memcmp(&info_data[idx], element, info->element_size);
  534. if (res == 0)
  535. {
  536. result_index = idx;
  537. break;
  538. }
  539. }
  540.  
  541. }
  542. return result_index;
  543. }
  544.  
  545.  
  546. /**
  547. * このリスト内の指定された位置で始まる、リスト内の要素を反復するイテレータを返します。
  548. *
  549. * @param list 対象リスト
  550. * @param index イテレータから返される最初の要素のインデックス
  551. * @return リスト内の指定された位置で始まる、リスト内の要素を反復するイテレータ
  552. */
  553. KcIterator* KcArrayList_iterator(KcList* list, int index)
  554. {
  555. (void) list;
  556. (void) index;
  557. return NULL;
  558. }
  559.  
  560.  
  561. /**
  562. * 指定されたリスト情報のデータ容量を増やします。
  563. * 容量を増やす必要がない場合、何もせず true を返します。
  564. * 容量を増やすことができない場合、false を返します。
  565. *
  566. * @param info リスト情報
  567. * @return true/false (成功/失敗)
  568. */
  569. bool KcArrayList_increase_capacity(KcArrayListInfo* info)
  570. {
  571. bool is_success = true;
  572. if (info->size >= info->capacity)
  573. {
  574. int new_capacity = info->capacity * 2;
  575. is_success = KcArrayList_set_capacity(info, new_capacity);
  576. }
  577. return is_success;
  578. }
  579.  
  580.  
  581. /**
  582. * 指定されたリスト情報のデータ容量を削減します。
  583. *
  584. * @param info リスト情報
  585. */
  586. void KcArrayList_reduce_capacity(KcArrayListInfo* info)
  587. {
  588. if ((info->capacity > info->init_capacity) && (info->size <= (info->capacity / 4)))
  589. { // 初期容量より大きく、要素数が容量の1/4以下となった場合、容量を1/2に減らす。
  590. int new_capacity = info->capacity / 2;
  591. KcArrayList_set_capacity(info, new_capacity);
  592. }
  593. }
  594.  
  595.  
  596. /**
  597. * 指定されたリスト情報のデータ容量を指定された capacity に変更します。
  598. *
  599. * @param info リスト情報
  600. * @return true/false (成功/失敗)
  601. */
  602. bool KcArrayList_set_capacity(KcArrayListInfo* info, int capacity)
  603. {
  604. printf("p = %p\n", info->data);
  605. printf("size = %ld\n", info->element_size * capacity);
  606. void* ptr = realloc(info->data, (info->element_size * capacity));
  607. if (ptr != NULL)
  608. {
  609. info->data = ptr;
  610. info->capacity = capacity;
  611. return true;
  612. }
  613. return false;
  614. }
  615.