OSDN Git Service

referenceCountを導入。今のところ正常に動作している。メモリリークについても一部改善。69.67KB(1852/2023)>36.59KB(588/2163)
[chnosproject/CHNOSProject.git] / CHNOSProject / chn / chnlib.c
1 //\r
2 //  chnlib.c\r
3 //  AI003\r
4 //\r
5 //  Created by 西田 耀 on 13/01/28.\r
6 //  Copyright (c) 2013年 Hikaru Nishida. All rights reserved.\r
7 //\r
8 \r
9 //  ライブラリ全体を支援する関数群\r
10 \r
11 //\r
12 //Include headers\r
13 //\r
14 \r
15 #include <stdio.h>\r
16 #include <stdarg.h>\r
17 #include <stdlib.h>\r
18 #include <string.h>\r
19 \r
20 #include "chnlib.h"\r
21 \r
22 //\r
23 //Define static values\r
24 //\r
25 int CHNLIB_Debug_PrintStructureData_RecursiveCounter;\r
26 \r
27 //\r
28 //Declare internal functions\r
29 //\r
30 const char *CHNLIB_Debug_Internal_GetStructTypeNameByID(uint typeid);\r
31 void CHNLIB_Debug_Internal_PrintStructureDataSub(void *structure, uint level);\r
32 void CHNLIB_Debug_Internal_PrintIndent(int level);\r
33 \r
34 //\r
35 //Define types\r
36 //\r
37 \r
38 //\r
39 //Functions\r
40 //\r
41 \r
42 void CHNLIB_Debug(const char format[], const char filename[], int line, const char funcname[], ...)\r
43 {\r
44     //デバッグ用printf\r
45     char s[CHNLIB_MAX_STRING_LENGTH];\r
46     va_list varg;\r
47     \r
48     fprintf(stdout, "CHNLIB:Debug:%s@%s:%d:", funcname, filename, line);\r
49     \r
50     va_start(varg, funcname);\r
51     vsnprintf(s, sizeof(s), format, varg);\r
52     va_end(varg);\r
53     \r
54     fputs(s, stdout);\r
55     fputs("\n", stdout);\r
56         \r
57         fflush(stdout);\r
58         \r
59     return;\r
60 }\r
61 \r
62 void CHNLIB_Debug_PrintStructureData(void *structure, uint level)\r
63 {\r
64     //ライブラリ定義の構造体の中身を表示する。\r
65     //structureがUIPArrayを指していた場合、その中身も表示する。表示する階層はlevelで制限できる。\r
66     //-level == 0:全階層\r
67     //-level >= 1:level階層まで\r
68 \r
69     CHNLIB_Debug_PrintStructureData_RecursiveCounter = level - 1;\r
70     \r
71     CHNLIB_Debug_Internal_PrintStructureDataSub(structure, 0);\r
72     \r
73     return;\r
74 }\r
75 \r
76 void CHNLIB_ReportError(const char format[], const char filename[], int line, const char funcname[], ...)\r
77 {\r
78     //stderrにprintfの書式に従って出力する。\r
79     char s[CHNLIB_MAX_STRING_LENGTH];\r
80     va_list varg;\r
81     \r
82     fprintf(stderr, "CHNLIB:Error:%s@%s:%d:", funcname, filename, line);\r
83     \r
84     va_start(varg, funcname);\r
85     vsnprintf(s, sizeof(s), format, varg);\r
86     va_end(varg);\r
87     \r
88     fputs(s, stderr);\r
89         fputs("\n", stderr);\r
90     \r
91     return;\r
92 }\r
93 \r
94 void CHNLIB_StructureHeader_Initialize(CHNLIB_StructureHeader *header, uint typeid)\r
95 {\r
96     //ライブラリ共通構造体ヘッダの初期化を行う。\r
97     //各構造体のInitializeで呼ばれることを想定している。\r
98     //referenceCountは1で初期化される(初期化を行った関数が所有すると考える)\r
99     if(header == NULL){\r
100         CHNLIB_ReportError("Null structure.", CHNLIB_DEBUG_ARGUMENTS);\r
101         return;\r
102     }\r
103     \r
104     header->signature = CHNLIB_STRUCTURE_SIGNATURE;\r
105     header->typeid = typeid;\r
106 #ifdef DEBUG_MEMORY_REFERENCE_COUNT\r
107     CHNLIB_Debug("Init with referenceCount = 1 [%p].", CHNLIB_DEBUG_ARGUMENTS, header);\r
108 #endif\r
109     header->referenceCount = 1;\r
110     header->destructor = NULL;\r
111     return;\r
112 }\r
113 \r
114 uint CHNLIB_StructureHeader_GetTypeID(const void *structure)\r
115 {\r
116     //structureが指す構造体のヘッダを確認して、その構造体のtypeidを返す。\r
117     //ポインタの正当性の実証に利用するとよい。\r
118     CHNLIB_StructureHeader *strhead;\r
119     \r
120     if(structure == NULL){\r
121         return CHNLIB_STRUCT_ID_Null;\r
122     }\r
123     \r
124     strhead = (CHNLIB_StructureHeader *)structure;\r
125     if(strhead->signature == CHNLIB_STRUCTURE_SIGNATURE){\r
126         return strhead->typeid;\r
127     }\r
128     return CHNLIB_STRUCT_ID_Null;\r
129 }\r
130 \r
131 void *CHNLIB_System_AllocateMemory_Strict(int size, const char filename[], int line, const char funcname[])\r
132 {\r
133     //mallocを行い、確保が失敗した場合にメッセージを出力してプログラムを終了する。\r
134     //また、この関数で取得されたメモリはゼロクリアされていることが保証される。\r
135     void *p;\r
136     \r
137     p = malloc(size);\r
138     if(p == NULL){\r
139         CHNLIB_ReportError("An attempt to allocate memory %d bytes in %s@%s:%d: is failed. Abort.", CHNLIB_DEBUG_ARGUMENTS, size, filename, line, funcname);\r
140         exit(EXIT_FAILURE);\r
141     }\r
142     \r
143 #ifdef DEBUG_MEMORY_ALLOCATION\r
144     CHNLIB_Debug("Request allocation %d bytes ->[%p].", CHNLIB_DEBUG_ARGUMENTS, size, p);\r
145 #endif\r
146     \r
147     memset(p, 0, size);\r
148 \r
149     return p;\r
150 }\r
151 \r
152 void CHNLIB_System_FreeMemory(void *p, const char filename[], int line, const char funcname[])\r
153 {\r
154     //ポインタがNullでないことを確認して、Freeする。\r
155     if(p == NULL){\r
156         CHNLIB_ReportError("An attempt to free NULL memory in %s@%s:%d:. Ignore.", CHNLIB_DEBUG_ARGUMENTS, filename, line, funcname);\r
157         return;\r
158     }\r
159     \r
160 #ifdef DEBUG_MEMORY_ALLOCATION\r
161     CHNLIB_Debug("Request ƒree memory [%p].", CHNLIB_DEBUG_ARGUMENTS, p);\r
162 #endif\r
163     \r
164     free(p);\r
165     \r
166     return;\r
167 }\r
168 \r
169 void CHNLIB_Retain(void **structure)\r
170 {\r
171     //structureのreferenceCountをインクリメントする。\r
172     //referenceCountの初期値は1\r
173     \r
174     CHNLIB_StructureHeader *strhead;\r
175     \r
176     if(structure == NULL || *structure == NULL){\r
177         return;\r
178     }\r
179     \r
180     strhead = (CHNLIB_StructureHeader *)*structure;\r
181     if(strhead->signature == CHNLIB_STRUCTURE_SIGNATURE){\r
182 #ifdef DEBUG_MEMORY_REFERENCE_COUNT\r
183         CHNLIB_Debug("Retain [%p].", CHNLIB_DEBUG_ARGUMENTS, *structure);\r
184 #endif\r
185         strhead->referenceCount++;\r
186     }\r
187     \r
188     return;\r
189 }\r
190 \r
191 void CHNLIB_Release(void **structure)\r
192 {\r
193     //structureのreferenceCountをデクリメントする。\r
194     //デクリメントした結果referenceCount==0となった時、そのstructureを解放する。\r
195     //structureが内包しているオブジェクトについては、releaseを行う。\r
196     \r
197     CHNLIB_StructureHeader *strhead;\r
198     \r
199     if(structure == NULL || *structure == NULL){\r
200         return;\r
201     }\r
202     \r
203     strhead = (CHNLIB_StructureHeader *)*structure;\r
204     if(strhead->signature == CHNLIB_STRUCTURE_SIGNATURE){\r
205         if(strhead->referenceCount <= 1){\r
206             if(strhead->destructor == NULL){\r
207 #ifdef DEBUG_MEMORY_REFERENCE_COUNT\r
208                 CHNLIB_Debug("Release(with free)[%p].", CHNLIB_DEBUG_ARGUMENTS, *structure);\r
209 #endif\r
210                 free(*structure);\r
211             } else{\r
212                 strhead->destructor(structure);\r
213             }\r
214         } else{\r
215 #ifdef DEBUG_MEMORY_REFERENCE_COUNT\r
216             CHNLIB_Debug("Release[%p].", CHNLIB_DEBUG_ARGUMENTS, *structure);\r
217 #endif\r
218             strhead->referenceCount--;\r
219             *structure = NULL;\r
220         }\r
221     }\r
222     \r
223     return;\r
224 }\r
225 \r
226 void *CHNLIB_AutoRelease(void *structure)\r
227 {\r
228     //structureのreferenceCountを、destructせずに0にする。\r
229     //オブジェクト確保後に自分の所有権を放棄して他の関数へ渡すときに利用する。\r
230     \r
231     CHNLIB_StructureHeader *strhead;\r
232     \r
233     if(structure != NULL){\r
234         strhead = (CHNLIB_StructureHeader *)structure;\r
235         if(strhead->signature == CHNLIB_STRUCTURE_SIGNATURE){\r
236 #ifdef DEBUG_MEMORY_REFERENCE_COUNT\r
237             CHNLIB_Debug("Set AutoRelease [%p].", CHNLIB_DEBUG_ARGUMENTS, structure);\r
238 #endif\r
239             strhead->referenceCount = 0;\r
240         }\r
241     }\r
242     \r
243     return structure;\r
244 }\r
245 \r
246 //\r
247 //Internal functions\r
248 //\r
249 \r
250 const char *CHNLIB_Debug_Internal_GetStructTypeNameByID(uint typeid)\r
251 {\r
252     //デバッグ出力で利用するための構造体名を取得する。\r
253     //このソース以外から呼び出してはならない。\r
254     switch(typeid){\r
255         case CHNLIB_STRUCT_ID_Null:\r
256             return "Null";\r
257         case CHNLIB_STRUCT_ID_UIPArray:\r
258             return "UIPArray";\r
259         case CHNLIB_STRUCT_ID_String:\r
260             return "String";\r
261     }\r
262     return "Unknown";\r
263 }\r
264 \r
265 void CHNLIB_Debug_Internal_PrintStructureDataSub(void *structure, uint level)\r
266 {\r
267     //デバッグ出力のサブルーチン。\r
268     //このソース以外から呼び出してはならない。\r
269     int typeid, i, j;\r
270     void *p;\r
271     \r
272     typeid = CHNLIB_StructureHeader_GetTypeID(structure);\r
273     \r
274     switch(typeid){\r
275         case CHNLIB_STRUCT_ID_UIPArray:\r
276             i = CHNLIB_UIPArray_GetNumberOfDatas(structure);\r
277             CHNLIB_Debug_Internal_PrintIndent(level);\r
278             CHNLIB_Debug("%s[%p]:Number of datas=%d", "", 0, "", CHNLIB_Debug_Internal_GetStructTypeNameByID(typeid), structure, i);\r
279             for(j = 0; j < i; j++){\r
280                 p = CHNLIB_UIPArray_GetPointerByIndex(structure, j);\r
281                 CHNLIB_Debug_Internal_PrintIndent(level);\r
282                 CHNLIB_Debug("%s[%p]:[%d]=(%u,[%p])", "", 0, "", CHNLIB_Debug_Internal_GetStructTypeNameByID(typeid), structure, j, CHNLIB_UIPArray_GetData32ByIndex(structure, j), p);\r
283                 if(CHNLIB_Debug_PrintStructureData_RecursiveCounter != 0){\r
284                     CHNLIB_Debug_Internal_PrintStructureDataSub(p, level + 1);\r
285                 }\r
286             }\r
287             break;\r
288         case CHNLIB_STRUCT_ID_String:\r
289             CHNLIB_Debug_Internal_PrintIndent(level);\r
290             CHNLIB_Debug("%s[%p]:[%s]", "", 0, "", CHNLIB_Debug_Internal_GetStructTypeNameByID(typeid), structure, CHNLIB_String_GetReferencePointerOfCString(structure));\r
291             break;\r
292         default:\r
293             CHNLIB_Debug_Internal_PrintIndent(level);\r
294             CHNLIB_Debug("%s[%p]:NULL structure or not implemented.", "", 0, "", CHNLIB_Debug_Internal_GetStructTypeNameByID(typeid), structure);\r
295             break;\r
296     }\r
297     return;\r
298 }\r
299 \r
300 void CHNLIB_Debug_Internal_PrintIndent(int level)\r
301 {\r
302     //デバッグ出力のサブルーチン。\r
303     //このソース以外から呼び出してはならない。\r
304     int i;\r
305     \r
306     for(i = 0; i < level; i++){\r
307         fputs("    ", stdout);\r
308     }\r
309         \r
310     return;\r
311 }\r