source: libcf/trunk/src/cf_list.c@ 149

Last change on this file since 149 was 149, checked in by cheese, 11 years ago

#1 rename context-implemented structures for readability

File size: 6.8 KB
Line 
1/**
2 * \file cf_list.c
3 *
4 * \author myusgun <myusgun@gmail.com>
5 *
6 * \brief 연결 리스트 구현
7 */
8#include "cf_list.h"
9#include "cf_local.h"
10#include "cf_error.h"
11
12#include <stdlib.h>
13
14#define ASSERT_CTX(__ctx) \
15 if (__ctx == NULL) \
16 return CF_ERROR_DS_INVALID_CTX
17
18#define ASSERT_TRAVERSER(__trav) \
19 if (__trav == NULL) \
20 return CF_ERROR_DS_INVALID_TRAVERSER
21
22#define ASSERT_ARGS(x) \
23 if ((x)) \
24 return CF_ERROR_DS_INVALID_ARGS
25
26/** 리스트 노드 (CF_Traverser의 구현) */
27typedef struct __cf_node__
28{
29 void * element;
30 struct __cf_node__ * prev;
31 struct __cf_node__ * next;
32} CF_NODE;
33
34/** 리스트 컨텍스트 (CF_List_Ctx의 구현) */
35typedef struct __cf_list__
36{
37 int size;
38 CF_NODE * front;
39 CF_NODE * rear;
40} CF_LIST_CONTEXT;
41
42/**
43 * 리스트 컨텍스트 생성
44 *
45 * \return 성공 시, CF_OK; 실패 시, 오류 코드
46 *
47 * \param ctx 리스트 컨텍스트 포인터
48 */
49int
50CF_List_CreateCtx (CF_List_Ctx * ctx)
51{
52 CF_LIST_CONTEXT * context = NULL;
53
54 ASSERT_ARGS (ctx == NULL);
55
56 context = (CF_LIST_CONTEXT *) calloc (sizeof (CF_LIST_CONTEXT), 1);
57 if (context == NULL)
58 return CF_ERROR_DS_CREATE_CTX;
59
60 *ctx = (CF_List_Ctx) context;
61
62 return CF_OK;
63}
64
65/**
66 * 리스트 컨텍스트 해제
67 *
68 * \return 성공 시, CF_OK; 실패 시, 오류 코드
69 *
70 * \param ctx 리스트 컨텍스트
71 */
72int
73CF_List_DestroyCtx (CF_List_Ctx ctx)
74{
75 CF_LIST_CONTEXT * context = (CF_LIST_CONTEXT *) ctx;
76
77 ASSERT_CTX (ctx);
78
79 CF_List_RemoveAll (ctx);
80
81 free (context);
82
83 return CF_OK;
84}
85
86/**
87 * 리스트 탐색자(Traverser)를 Front 위치로 설정
88 *
89 * \return 성공 시, CF_OK; 실패 시, 오류 코드
90 *
91 * \param ctx 리스트 컨텍스트
92 * \param traverser 리스트 탐색자 주소
93 */
94int
95CF_List_Front (CF_List_Ctx ctx,
96 CF_Traverser * traverser)
97{
98 CF_LIST_CONTEXT * context = (CF_LIST_CONTEXT *) ctx;
99
100 ASSERT_CTX (ctx);
101 ASSERT_TRAVERSER (traverser);
102
103 *traverser = (CF_Traverser *) context->front;
104
105 return CF_OK;
106}
107
108/**
109 * 리스트 탐색자(Traverser)를 Rear 위치로 설정
110 *
111 * \return 성공 시, CF_OK; 실패 시, 오류 코드
112 *
113 * \param ctx 리스트 컨텍스트
114 * \param traverser 리스트 탐색자 주소
115 */
116int
117CF_List_Rear (CF_List_Ctx ctx,
118 CF_Traverser * traverser)
119{
120 CF_LIST_CONTEXT * context = (CF_LIST_CONTEXT *) ctx;
121
122 ASSERT_CTX (ctx);
123 ASSERT_TRAVERSER (traverser);
124
125 *traverser = (CF_Traverser *) context->rear;
126
127 return CF_OK;
128}
129
130/**
131 * 리스트에 새 데이터 삽입
132 *
133 * \return 성공 시, CF_OK; 실패 시, 오류 코드
134 *
135 * \param ctx 리스트 컨텍스트
136 * \param traverser 리스트 탐색자
137 * \param direction 탐색자의 전/후를 지정
138 * \param element 삽입할 데이터 주소
139 *
140 * \remarks
141 * traverser가 NULL일 때,
142 * direction이 CF_DIRECTION_BEFORE라면 Front 위치이고
143 * direction이 CF_DIRECTION_AFTER라면 Rear 위치에 삽입
144 */
145int
146CF_List_Insert (CF_List_Ctx ctx,
147 const CF_Traverser traverser,
148 const CF_DIRECTION direction,
149 const void * element)
150{
151 CF_LIST_CONTEXT * context = (CF_LIST_CONTEXT *) ctx;
152 CF_NODE * node = NULL;
153 CF_NODE * newnode = NULL;
154
155 ASSERT_CTX (ctx);
156
157 newnode = (CF_NODE *) calloc (sizeof (CF_NODE), 1);
158 if (newnode == NULL)
159 return CF_ERROR_DS_CREATE_NODE;
160
161 newnode->element = (void *) element;
162
163 TRY
164 {
165 if (CF_List_GetSize (ctx) == 0)
166 {
167 context->front = context->rear = newnode;
168 TRY_BREAK;
169 }
170
171 if (direction == CF_DIRECTION_BEFORE)
172 {
173 node = traverser ? (CF_NODE *) traverser : context->front;
174
175 newnode->next = node;
176 if (node)
177 {
178 newnode->prev = node->prev;
179 node->prev = newnode;
180 if (newnode->prev)
181 newnode->prev->next = newnode;
182 }
183
184 if (node == context->front)
185 context->front = newnode;
186 }
187 else /* if (direction == CF_DIRECTION_AFTER) */
188 {
189 node = traverser ? (CF_NODE *) traverser : context->rear;
190
191 newnode->prev = node;
192 if (node)
193 {
194 newnode->next = node->next;
195 node->next = newnode;
196 if (newnode->next)
197 newnode->next->prev = newnode;
198 }
199
200 if (node == context->rear)
201 context->rear = newnode;
202 }
203 } NO_CATCH;
204
205 context->size++;
206
207 return CF_OK;
208}
209
210/**
211 * 리스트에서 탐색자 위치의 항목을 삭제
212 *
213 * \return 성공 시, CF_OK; 실패 시, 오류 코드
214 *
215 * \param ctx 리스트 컨텍스트
216 * \param traverser 리스트 탐색자 주소
217 */
218int
219CF_List_Remove (CF_List_Ctx ctx,
220 CF_Traverser * traverser)
221{
222 CF_LIST_CONTEXT * context = (CF_LIST_CONTEXT *) ctx;
223 CF_NODE * node = NULL;
224
225 ASSERT_CTX (ctx);
226 ASSERT_TRAVERSER (traverser);
227 ASSERT_ARGS (*traverser == NULL);
228
229 node = (CF_NODE *) *traverser;
230
231 if (node->prev)
232 {
233 node->prev->next = node->next;
234 if (node == context->rear)
235 context->rear = node->prev;
236 }
237
238 if (node->next)
239 {
240 node->next->prev = node->prev;
241 if (node == context->front)
242 context->front = node->next;
243 }
244
245 free (node);
246
247 *traverser = NULL;
248
249 context->size--;
250
251 if (CF_List_GetSize (ctx) == 0)
252 context->front = context->rear = NULL;
253
254 return CF_OK;
255}
256
257/**
258 * 리스트에서 모든 항목을 삭제
259 *
260 * \return 성공 시, CF_OK; 실패 시, 오류 코드
261 *
262 * \param ctx 리스트 컨텍스트
263 */
264int
265CF_List_RemoveAll (CF_List_Ctx ctx)
266{
267 CF_Traverser traverser = NULL;
268
269 ASSERT_CTX (ctx);
270
271 while (CF_List_GetSize (ctx) > 0)
272 {
273 CF_List_Front (ctx, &traverser);
274 CF_List_Remove (ctx, &traverser);
275 }
276
277 return CF_OK;
278}
279
280/**
281 * 탐색자 위치의 데이터를 가져옴
282 *
283 * \return 성공 시, CF_OK; 실패 시, 오류 코드
284 *
285 * \param traverser 리스트 탐색자
286 * \param element 데이터 주소
287 */
288int
289CF_List_GetElement (const CF_Traverser traverser,
290 void ** element)
291{
292 CF_NODE * node = (CF_NODE *) traverser;
293
294 ASSERT_TRAVERSER (traverser);
295 ASSERT_ARGS (element == NULL);
296
297 *element = node->element;
298
299 return CF_OK;
300}
301
302/**
303 * 탐색자 위치를 이전으로 이동
304 *
305 * \return 성공 시, CF_OK; 실패 시, 오류 코드
306 *
307 * \param traverser 리스트 탐색자 주소
308 */
309int
310CF_List_Prev (CF_Traverser * traverser)
311{
312 CF_NODE * node = (CF_NODE *) *traverser;
313
314 ASSERT_TRAVERSER (traverser);
315 ASSERT_ARGS (*traverser == NULL);
316
317 node = node->prev;
318 *traverser = (CF_Traverser *) node;
319 if (node == NULL)
320 return CF_ERROR_DS_NO_MORE;
321
322 return CF_OK;
323}
324
325/**
326 * 탐색자 위치를 다음으로 이동
327 *
328 * \return 성공 시, CF_OK; 실패 시, 오류 코드
329 *
330 * \param traverser 리스트 탐색자 주소
331 */
332int
333CF_List_Next (CF_Traverser * traverser)
334{
335 CF_NODE * node = (CF_NODE *) *traverser;
336
337 ASSERT_TRAVERSER (traverser);
338 ASSERT_ARGS (*traverser == NULL);
339
340 node = node->next;
341 *traverser = (CF_Traverser *) node;
342 if (node == NULL)
343 return CF_ERROR_DS_NO_MORE;
344
345 return CF_OK;
346}
347
348/**
349 * 리스트에 등록된 항목의 수를 가져옴
350 *
351 * \return 성공 시, 항목 수; 실패 시, 오류 코드
352 *
353 * \param ctx 리스트 컨텍스트
354 */
355int
356CF_List_GetSize (CF_List_Ctx ctx)
357{
358 CF_LIST_CONTEXT * context = (CF_LIST_CONTEXT *) ctx;
359
360 ASSERT_CTX (ctx);
361
362 return context->size;
363}
Note: See TracBrowser for help on using the repository browser.