1 /* a managed FILE* ... for lazy file read
2  */
3 
4 /*
5 
6     Copyright (C) 1991-2003 The National Gallery
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License along
19     with this program; if not, write to the Free Software Foundation, Inc.,
20     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 
22  */
23 
24 /*
25 
26     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
27 
28  */
29 
30 #include "ip.h"
31 
32 /*
33 #define DEBUG
34  */
35 
36 static ManagedClass *parent_class = NULL;
37 
38 /* Track all instances here.
39  */
40 static GHashTable *managedstring_all = NULL;
41 
42 #ifdef DEBUG
43 /* Number of managed strings, number we have expanded to the heap.
44  */
45 int managed_total = 0;
46 int managed_expanded = 0;
47 #endif /*DEBUG*/
48 
49 static void
managedstring_finalize(GObject * gobject)50 managedstring_finalize( GObject *gobject )
51 {
52 	Managedstring *managedstring = MANAGEDSTRING( gobject );
53 
54 #ifdef DEBUG
55 	printf( "managedstring_finalize: \"%s\", ", managedstring->string );
56 	iobject_print( IOBJECT( managedstring ) );
57 #endif /*DEBUG*/
58 
59 #ifdef DEBUG
60 {
61 	PElement pe;
62 
63 	PEPOINTE( &pe, &managedstring->e );
64 	if( !PEISNOVAL( &pe ) )
65 		managed_expanded -= 1;
66 	managed_total -= 1;
67 }
68 #endif /*DEBUG*/
69 
70 	heap_unregister_element( MANAGED( managedstring )->heap,
71 		&managedstring->e );
72 	g_hash_table_remove( managedstring_all, managedstring );
73 	IM_FREE( managedstring->string );
74 
75 	G_OBJECT_CLASS( parent_class )->finalize( gobject );
76 }
77 
78 static void
managedstring_info(iObject * iobject,VipsBuf * buf)79 managedstring_info( iObject *iobject, VipsBuf *buf )
80 {
81 	Managedstring *managedstring = MANAGEDSTRING( iobject );
82 
83 	vips_buf_appendf( buf, "managedstring->string = \"%s\"\n",
84 		managedstring->string );
85 
86 	IOBJECT_CLASS( parent_class )->info( iobject, buf );
87 }
88 
89 /* Hash and equality for a managed string: we need the string and the heap to
90  * match.
91  */
92 static unsigned int
managedstring_hash(Managedstring * managedstring)93 managedstring_hash( Managedstring *managedstring )
94 {
95 	return( g_str_hash( managedstring->string ) |
96 		GPOINTER_TO_UINT( ((Managed *) managedstring)->heap ) );
97 }
98 
99 static gboolean
managedstring_equal(Managedstring * a,Managedstring * b)100 managedstring_equal( Managedstring *a, Managedstring *b )
101 {
102 	return( ((Managed *) a)->heap == ((Managed *) b)->heap &&
103 		g_str_equal( a->string, b->string ) );
104 }
105 
106 static void
managedstring_all_init(void)107 managedstring_all_init( void )
108 {
109 	if( !managedstring_all )
110 		managedstring_all = g_hash_table_new(
111 			(GHashFunc) managedstring_hash,
112 			(GEqualFunc) managedstring_equal );
113 }
114 
115 static void
managedstring_class_init(ManagedstringClass * class)116 managedstring_class_init( ManagedstringClass *class )
117 {
118 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
119 	iObjectClass *iobject_class = IOBJECT_CLASS( class );
120 
121 	parent_class = g_type_class_peek_parent( class );
122 
123 	gobject_class->finalize = managedstring_finalize;
124 
125 	iobject_class->info = managedstring_info;
126 
127 	managedstring_all_init();
128 }
129 
130 static void
managedstring_init(Managedstring * managedstring)131 managedstring_init( Managedstring *managedstring )
132 {
133 #ifdef DEBUG
134 	printf( "managedstring_init: %p\n", managedstring );
135 #endif /*DEBUG*/
136 
137 #ifdef DEBUG
138 	managed_total += 1;
139 #endif /*DEBUG*/
140 
141 	managedstring->string = NULL;
142 	managedstring->e.type = ELEMENT_NOVAL;
143 	managedstring->e.ele = NULL;
144 }
145 
146 GType
managedstring_get_type(void)147 managedstring_get_type( void )
148 {
149 	static GType type = 0;
150 
151 	if( !type ) {
152 		static const GTypeInfo info = {
153 			sizeof( ManagedstringClass ),
154 			NULL,           /* base_init */
155 			NULL,           /* base_finalize */
156 			(GClassInitFunc) managedstring_class_init,
157 			NULL,           /* class_finalize */
158 			NULL,           /* class_data */
159 			sizeof( Managedstring ),
160 			32,             /* n_preallocs */
161 			(GInstanceInitFunc) managedstring_init,
162 		};
163 		type = g_type_register_static( TYPE_MANAGED,
164 			"Managedstring", &info, 0 );
165 	}
166 
167 	return( type );
168 }
169 
170 static Managedstring *
managedstring_new(Heap * heap,const char * string)171 managedstring_new( Heap *heap, const char *string )
172 {
173 	Managedstring *managedstring;
174 
175 #ifdef DEBUG
176 	printf( "managedstring_new: %p, %s\n", heap, string );
177 #endif /*DEBUG*/
178 
179 	/* Disallow "" as string, we want to represent that as [].
180 	 */
181 	g_assert( strcmp( string, "" ) != 0 );
182 
183 	managedstring = g_object_new( TYPE_MANAGEDSTRING, NULL );
184 	managed_link_heap( MANAGED( managedstring ), heap );
185 	heap_register_element( heap, &managedstring->e );
186 	if( !(managedstring->string = im_strdup( NULL, string )) )
187 		return( NULL );
188 
189 	g_assert( !g_hash_table_lookup( managedstring_all, managedstring ) );
190 	g_hash_table_insert( managedstring_all, managedstring, managedstring );
191 
192 	MANAGED( managedstring )->hash = managedstring_hash( managedstring );
193 
194 	return( managedstring );
195 }
196 
197 Managedstring *
managedstring_lookup(Heap * heap,const char * string)198 managedstring_lookup( Heap *heap, const char *string )
199 {
200 	Managedstring managedstring;
201 
202 	((Managed *) &managedstring)->heap = heap;
203 	managedstring.string = string;
204 	managedstring_all_init();
205 
206 	return( g_hash_table_lookup( managedstring_all, &managedstring ) );
207 }
208 
209 Managedstring *
managedstring_find(Heap * heap,const char * string)210 managedstring_find( Heap *heap, const char *string )
211 {
212 	Managedstring *managedstring;
213 
214 	if( !(managedstring = managedstring_lookup( heap, string )) )
215 		if( !(managedstring = managedstring_new( heap, string )) )
216 			return( NULL );
217 
218 	return( managedstring );
219 }
220 
221 gboolean
managedstring_get(Managedstring * managedstring,PElement * out)222 managedstring_get( Managedstring *managedstring, PElement *out )
223 {
224 	PElement pe;
225 
226 	PEPOINTE( &pe, &managedstring->e );
227 	if( PEISNOVAL( &pe ) ) {
228 		if( !heap_string_new( MANAGED( managedstring )->heap,
229 			managedstring->string, &pe ) )
230 			return( FALSE );
231 
232 #ifdef DEBUG
233 		managed_expanded += 1;
234 		printf( "expanding %s to the heap\n", managedstring->string );
235 		printf( "\t(%d of %d now expanded)\n",
236 			managed_expanded, managed_total );
237 #endif /*DEBUG*/
238 	}
239 
240 	PEPUTE( out, &managedstring->e );
241 
242 	return( TRUE );
243 }
244