Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
strpool.c
Go to the documentation of this file.
1 /*
2  * strpool.c
3  * Copyright 2011 John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <glib.h>
21 #include <pthread.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "core.h"
29 
30 /* Each string in the pool is allocated with five leading bytes: a 32-bit
31  * reference count and a one-byte signature, the '@' character. */
32 
33 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
34 static GHashTable * table;
35 
36 #ifdef STRPOOL_DEBUG
37 static GHashTable * logged;
38 
39 static void str_log (const char * str, const char * op, const char * file, int line)
40 {
41  if (! logged)
42  logged = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
43 
44  GList * list = g_hash_table_lookup (logged, str);
45  list = g_list_prepend (list, g_strdup_printf ("%s by %s:%d", op, file, line));
46  g_hash_table_insert (logged, g_strdup (str), list);
47 }
48 
49 static void str_log_dump (const char * str)
50 {
51  if (! logged)
52  return;
53 
54  for (GList * node = g_hash_table_lookup (logged, str); node; node = node->next)
55  printf (" - %s\n", (char *) node->data);
56 }
57 #endif
58 
59 static void str_destroy (void * str)
60 {
61  * ((char *) str - 1) = 0;
62  free ((char *) str - 5);
63 }
64 
65 #ifdef STRPOOL_DEBUG
66 EXPORT char * str_get_debug (const char * str, const char * file, int line)
67 #else
68 EXPORT char * str_get (const char * str)
69 #endif
70 {
71  if (! str)
72  return NULL;
73 
74  char * copy;
75  pthread_mutex_lock (& mutex);
76 
77 #ifdef STRPOOL_DEBUG
78  str_log (str, "get", file, line);
79 #endif
80 
81  if (! table)
82  table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, str_destroy);
83 
84  if ((copy = g_hash_table_lookup (table, str)))
85  {
86  void * mem = copy - 5;
87  (* (int32_t *) mem) ++;
88  }
89  else
90  {
91  void * mem = malloc (6 + strlen (str));
92  (* (int32_t *) mem) = 1;
93 
94  copy = (char *) mem + 5;
95  copy[-1] = '@';
96  strcpy (copy, str);
97 
98  g_hash_table_insert (table, copy, copy);
99  }
100 
101  pthread_mutex_unlock (& mutex);
102  return copy;
103 }
104 
105 #ifdef STRPOOL_DEBUG
106 EXPORT char * str_ref_debug (char * str, const char * file, int line)
107 #else
108 EXPORT char * str_ref (char * str)
109 #endif
110 {
111  if (! str)
112  return NULL;
113 
114  pthread_mutex_lock (& mutex);
115  STR_CHECK (str);
116 
117 #ifdef STRPOOL_DEBUG
118  str_log (str, "ref", file, line);
119 #endif
120 
121  void * mem = str - 5;
122  (* (int32_t *) mem) ++;
123 
124  pthread_mutex_unlock (& mutex);
125  return str;
126 }
127 
128 #ifdef STRPOOL_DEBUG
129 EXPORT void str_unref_debug (char * str, const char * file, int line)
130 #else
131 EXPORT void str_unref (char * str)
132 #endif
133 {
134  if (! str)
135  return;
136 
137  pthread_mutex_lock (& mutex);
138  STR_CHECK (str);
139 
140 #ifdef STRPOOL_DEBUG
141  str_log (str, "unref", file, line);
142 #endif
143 
144  void * mem = str - 5;
145  if (! -- (* (int32_t *) mem))
146  g_hash_table_remove (table, str);
147 
148  pthread_mutex_unlock (& mutex);
149 }
150 
151 EXPORT char * str_nget (const char * str, int len)
152 {
153  if (strlen (str) <= len)
154  return str_get (str);
155 
156  char buf[len + 1];
157  memcpy (buf, str, len);
158  buf[len] = 0;
159 
160  return str_get (buf);
161 }
162 
163 EXPORT char * str_printf (const char * format, ...)
164 {
165  va_list args;
166 
167  va_start (args, format);
168  int len = vsnprintf (NULL, 0, format, args);
169  va_end (args);
170 
171  char buf[len + 1];
172 
173  va_start (args, format);
174  vsnprintf (buf, sizeof buf, format, args);
175  va_end (args);
176 
177  return str_get (buf);
178 }
179 
180 EXPORT void strpool_abort (char * str)
181 {
182  fprintf (stderr, "String not in pool: %s\n", str);
183 #ifdef STRPOOL_DEBUG
184  str_log_dump (str);
185 #endif
186  abort ();
187 }
188 
189 static void str_leaked (void * key, void * str, void * unused)
190 {
191  fprintf (stderr, "String not freed: %s\n", (char *) str);
192 #ifdef STRPOOL_DEBUG
193  str_log_dump (str);
194 #endif
195 }
196 
197 EXPORT void strpool_shutdown (void)
198 {
199  if (! table)
200  return;
201 
202  g_hash_table_foreach (table, str_leaked, NULL);
203  g_hash_table_destroy (table);
204  table = NULL;
205 }
void strpool_shutdown(void)
Definition: strpool.c:197
int format
Definition: audio.c:132
static void str_destroy(void *str)
Definition: strpool.c:59
static GHashTable * table
Definition: strpool.c:34
char * str_printf(const char *format,...)
Definition: strpool.c:163
static pthread_mutex_t mutex
Definition: strpool.c:33
char * str_ref(char *str)
Definition: strpool.c:108
char * str_nget(const char *str, int len)
Definition: strpool.c:151
#define STR_CHECK(str)
Definition: core.h:55
#define NULL
Definition: core.h:29
void str_unref(char *str)
Definition: strpool.c:131
void strpool_abort(char *str)
Definition: strpool.c:180
static void str_leaked(void *key, void *str, void *unused)
Definition: strpool.c:189
char * str_get(const char *str)
Definition: strpool.c:68