Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4973 | right-hear | 1 | /******************************************************************* |
2 | * |
||
3 | * ttcache.h 1.1 |
||
4 | * |
||
5 | * Generic object cache |
||
6 | * |
||
7 | * Copyright 1996-1999 by |
||
8 | * David Turner, Robert Wilhelm, and Werner Lemberg. |
||
9 | * |
||
10 | * This file is part of the FreeType project, and may only be used |
||
11 | * modified and distributed under the terms of the FreeType project |
||
12 | * license, LICENSE.TXT. By continuing to use, modify, or distribute |
||
13 | * this file you indicate that you have read the license and |
||
14 | * understand and accept it fully. |
||
15 | * |
||
16 | * |
||
17 | * This component defines and implements object caches. |
||
18 | * |
||
19 | * An object class is a structure layout that encapsulate one |
||
20 | * given type of data used by the FreeType engine. Each object |
||
21 | * class is completely described by: |
||
22 | * |
||
23 | * - a 'root' or 'leading' structure containing the first |
||
24 | * important fields of the class. The root structure is |
||
25 | * always of fixed size. |
||
26 | * |
||
27 | * It is implemented as a simple C structure, and may |
||
28 | * contain several pointers to sub-tables that can be |
||
29 | * sized and allocated dynamically. |
||
30 | * |
||
31 | * Examples: TFace, TInstance, TGlyph & TExecution_Context |
||
32 | * (defined in 'ttobjs.h') |
||
33 | * |
||
34 | * - we make a difference between 'child' pointers and 'peer' |
||
35 | * pointers. A 'child' pointer points to a sub-table that is |
||
36 | * owned by the object, while a 'peer' pointer points to any |
||
37 | * other kind of data the object isn't responsible for. |
||
38 | * |
||
39 | * An object class is thus usually a 'tree' of 'child' tables. |
||
40 | * |
||
41 | * - each object class needs a constructor and a destructor. |
||
42 | * |
||
43 | * A constructor is a function which receives the address of |
||
44 | * freshly allocated and zeroed object root structure and |
||
45 | * 'builds' all the valid child data that must be associated |
||
46 | * to the object before it becomes 'valid'. |
||
47 | * |
||
48 | * A destructor does the inverse job: given the address of |
||
49 | * a valid object, it must discard all its child data and |
||
50 | * zero its main fields (essentially the pointers and array |
||
51 | * sizes found in the root fields). |
||
52 | * |
||
53 | * |
||
54 | * Important notes: |
||
55 | * |
||
56 | * When the constructor fails to allocate an object, it must |
||
57 | * return immediately with an error code, and not try to release |
||
58 | * what it has previously allocated before the error. The cache |
||
59 | * manager detects the error and calls the destructor on the |
||
60 | * partial object, before returning the error to the caller (along |
||
61 | * with a NULL pointer for the "new" object). |
||
62 | * |
||
63 | * The destructor must thus be able to deal with "partial objects", |
||
64 | * i.e., objects where only part of the child tables are allocated, |
||
65 | * and only release these ones. As the TT_Free() function accepts |
||
66 | * a NULL parameter (and returns successfuly in this case), no check |
||
67 | * is really necessary when using the macro 'FREE()'. |
||
68 | * |
||
69 | * Currently, there is no check in the cache manager to see if a |
||
70 | * destructor fails (double error state!). |
||
71 | * |
||
72 | * This scheme is more compact and more maintanable than the one |
||
73 | * where de-allocation code is duplicated in the constructor |
||
74 | * _and_ the destructor. |
||
75 | * |
||
76 | * |
||
77 | * |
||
78 | * Changes between 1.1 and 1.0: |
||
79 | * |
||
80 | * - introduced the refreshed and finalizer class definition/implementation |
||
81 | * - inserted an engine instance pointer in the cache structure |
||
82 | * |
||
83 | ******************************************************************/ |
||
84 | |||
85 | #ifndef TTCACHE_H |
||
86 | #define TTCACHE_H |
||
87 | |||
88 | #include "tttypes.h" |
||
89 | #include "ttconfig.h" |
||
90 | #include "ttmutex.h" |
||
91 | |||
92 | #ifdef __cplusplus |
||
93 | extern "C" { |
||
94 | #endif |
||
95 | |||
96 | typedef TT_Error TConstructor( void* object, |
||
97 | void* parent ); |
||
98 | |||
99 | typedef TT_Error TDestructor ( void* object ); |
||
100 | |||
101 | typedef TConstructor TRefresher; |
||
102 | typedef TDestructor TFinalizer; |
||
103 | |||
104 | typedef TConstructor* PConstructor; |
||
105 | typedef TDestructor* PDestructor; |
||
106 | typedef TRefresher* PRefresher; |
||
107 | typedef TFinalizer* PFinalizer; |
||
108 | |||
109 | |||
110 | /* A Cache class record holds the data necessary to define */ |
||
111 | /* a cache kind. */ |
||
112 | struct TCache_Class_ |
||
113 | { |
||
114 | ULong object_size; |
||
115 | Long idle_limit; |
||
116 | PConstructor init; |
||
117 | PDestructor done; |
||
118 | PRefresher reset; |
||
119 | PFinalizer finalize; |
||
120 | }; |
||
121 | |||
122 | typedef struct TCache_Class_ TCache_Class; |
||
123 | typedef TCache_Class* PCache_Class; |
||
124 | |||
125 | |||
126 | |||
127 | /* Simple list node record. A list element is said to be 'unlinked' */ |
||
128 | /* when it doesn't belong to any list. */ |
||
129 | struct TList_Element_; |
||
130 | |||
131 | typedef struct TList_Element_ TList_Element; |
||
132 | typedef TList_Element* PList_Element; |
||
133 | |||
134 | struct TList_Element_ |
||
135 | { |
||
136 | PList_Element next; |
||
137 | void* data; |
||
138 | }; |
||
139 | |||
140 | |||
141 | /* Simple singly-linked list record - LIFO style, no tail field */ |
||
142 | typedef PList_Element TSingle_List; |
||
143 | |||
144 | struct TCache_ |
||
145 | { |
||
146 | PEngine_Instance engine; |
||
147 | PCache_Class clazz; /* 'class' is a reserved word in C++ */ |
||
148 | TMutex* lock; |
||
149 | TSingle_List active; |
||
150 | TSingle_List idle; |
||
151 | Long idle_count; |
||
152 | }; |
||
153 | |||
154 | typedef struct TCache_ TCache; |
||
155 | typedef TCache* PCache; |
||
156 | |||
157 | /* Returns a new list element, either fresh or recycled. */ |
||
158 | /* Note: the returned element is unlinked. */ |
||
159 | |||
160 | /* An object cache holds two lists tracking the active and */ |
||
161 | /* idle objects that are currently created and used by the */ |
||
162 | /* engine. It can also be 'protected' by a mutex. */ |
||
163 | |||
164 | /* Initializes a new cache, of class 'clazz', pointed by 'cache', */ |
||
165 | /* protected by the 'lock' mutex. Set 'lock' to NULL if the cache */ |
||
166 | /* doesn't need protection */ |
||
167 | |||
168 | LOCAL_DEF |
||
169 | TT_Error Cache_Create( PEngine_Instance engine, |
||
170 | PCache_Class clazz, |
||
171 | TCache* cache, |
||
172 | TMutex* lock ); |
||
173 | |||
174 | /* Destroys a cache and all its listed objects */ |
||
175 | |||
176 | LOCAL_DEF |
||
177 | TT_Error Cache_Destroy( TCache* cache ); |
||
178 | |||
179 | |||
180 | /* Extracts a new object from the cache */ |
||
181 | |||
182 | LOCAL_DEF |
||
183 | TT_Error Cache_New( TCache* cache, |
||
184 | void** new_object, |
||
185 | void* parent_object ); |
||
186 | |||
187 | |||
188 | /* Returns an object to the cache, or discards it depending */ |
||
189 | /* on the cache class' 'idle_limit' field */ |
||
190 | |||
191 | LOCAL_DEF |
||
192 | TT_Error Cache_Done( TCache* cache, void* data ); |
||
193 | |||
194 | #define CACHE_New( _cache, _newobj, _parent ) \ |
||
195 | Cache_New( (TCache*)_cache, (void**)&_newobj, (void*)_parent ) |
||
196 | |||
197 | #define CACHE_Done( _cache, _obj ) \ |
||
198 | Cache_Done( (TCache*)_cache, (void*)_obj ) |
||
199 | |||
200 | |||
201 | |||
202 | LOCAL_DEF |
||
203 | TT_Error TTCache_Init( PEngine_Instance engine ); |
||
204 | |||
205 | LOCAL_DEF |
||
206 | TT_Error TTCache_Done( PEngine_Instance engine ); |
||
207 | |||
208 | |||
209 | #ifdef __cplusplus |
||
210 | } |
||
211 | #endif |
||
212 | |||
213 | #endif /* TTCACHE_H */ |
||
214 | |||
215 | |||
216 | /* END */ |