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 static void str_destroy (void * str)
37 {
38  * ((char *) str - 1) = 0;
39  free ((char *) str - 5);
40 }
41 
42 EXPORT char * str_get (const char * str)
43 {
44  if (! str)
45  return NULL;
46 
47  char * copy;
48  pthread_mutex_lock (& mutex);
49 
50  if (! table)
51  table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, str_destroy);
52 
53  if ((copy = g_hash_table_lookup (table, str)))
54  {
55  void * mem = copy - 5;
56  (* (int32_t *) mem) ++;
57  }
58  else
59  {
60  void * mem = malloc (6 + strlen (str));
61  (* (int32_t *) mem) = 1;
62 
63  copy = (char *) mem + 5;
64  copy[-1] = '@';
65  strcpy (copy, str);
66 
67  g_hash_table_insert (table, copy, copy);
68  }
69 
70  pthread_mutex_unlock (& mutex);
71  return copy;
72 }
73 
74 EXPORT char * str_ref (char * str)
75 {
76  if (! str)
77  return NULL;
78 
79  pthread_mutex_lock (& mutex);
80  STR_CHECK (str);
81 
82  void * mem = str - 5;
83  (* (int32_t *) mem) ++;
84 
85  pthread_mutex_unlock (& mutex);
86  return str;
87 }
88 
89 EXPORT void str_unref (char * str)
90 {
91  if (! str)
92  return;
93 
94  pthread_mutex_lock (& mutex);
95  STR_CHECK (str);
96 
97  void * mem = str - 5;
98  if (! -- (* (int32_t *) mem))
99  g_hash_table_remove (table, str);
100 
101  pthread_mutex_unlock (& mutex);
102 }
103 
104 EXPORT char * str_nget (const char * str, int len)
105 {
106  if (memchr (str, 0, len))
107  return str_get (str);
108 
109  char buf[len + 1];
110  memcpy (buf, str, len);
111  buf[len] = 0;
112 
113  return str_get (buf);
114 }
115 
116 EXPORT char * str_printf (const char * format, ...)
117 {
118  va_list args;
119 
120  va_start (args, format);
121  int len = vsnprintf (NULL, 0, format, args);
122  va_end (args);
123 
124  char buf[len + 1];
125 
126  va_start (args, format);
127  vsnprintf (buf, sizeof buf, format, args);
128  va_end (args);
129 
130  return str_get (buf);
131 }
132 
133 EXPORT void strpool_abort (char * str)
134 {
135  fprintf (stderr, "String not in pool: %s\n", str);
136  abort ();
137 }
138 
139 static void str_leaked (void * key, void * str, void * unused)
140 {
141  fprintf (stderr, "String not freed: %s\n", (char *) str);
142 }
143 
144 EXPORT void strpool_shutdown (void)
145 {
146  if (! table)
147  return;
148 
149  g_hash_table_foreach (table, str_leaked, NULL);
150  g_hash_table_destroy (table);
151  table = NULL;
152 }