1 /*
2 * Copyright © 2011 Mozilla Foundation
3 *
4 * This program is made available under an ISC-style license. See the
5 * accompanying file LICENSE for details.
6 */
7
8 #include "cubeb_strings.h"
9
10 #include <assert.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #define CUBEB_STRINGS_INLINE_COUNT 4
15
16 struct cubeb_strings {
17 uint32_t size;
18 uint32_t count;
19 char ** data;
20 char * small_store[CUBEB_STRINGS_INLINE_COUNT];
21 };
22
23 int
cubeb_strings_init(cubeb_strings ** strings)24 cubeb_strings_init(cubeb_strings ** strings)
25 {
26 cubeb_strings* strs = NULL;
27
28 if (!strings) {
29 return CUBEB_ERROR;
30 }
31
32 strs = calloc(1, sizeof(cubeb_strings));
33 assert(strs);
34
35 if (!strs) {
36 return CUBEB_ERROR;
37 }
38
39 strs->size = sizeof(strs->small_store) / sizeof(strs->small_store[0]);
40 strs->count = 0;
41 strs->data = strs->small_store;
42
43 *strings = strs;
44
45 return CUBEB_OK;
46 }
47
48 void
cubeb_strings_destroy(cubeb_strings * strings)49 cubeb_strings_destroy(cubeb_strings * strings)
50 {
51 char ** sp = NULL;
52 char ** se = NULL;
53
54 if (!strings) {
55 return;
56 }
57
58 sp = strings->data;
59 se = sp + strings->count;
60
61 for ( ; sp != se; sp++) {
62 if (*sp) {
63 free(*sp);
64 }
65 }
66
67 if (strings->data != strings->small_store) {
68 free(strings->data);
69 }
70
71 free(strings);
72 }
73
74 /** Look for string in string storage.
75 @param strings Opaque pointer to interned string storage.
76 @param s String to look up.
77 @retval Read-only string or NULL if not found. */
78 static char const *
cubeb_strings_lookup(cubeb_strings * strings,char const * s)79 cubeb_strings_lookup(cubeb_strings * strings, char const * s)
80 {
81 char ** sp = NULL;
82 char ** se = NULL;
83
84 if (!strings || !s) {
85 return NULL;
86 }
87
88 sp = strings->data;
89 se = sp + strings->count;
90
91 for ( ; sp != se; sp++) {
92 if (*sp && strcmp(*sp, s) == 0) {
93 return *sp;
94 }
95 }
96
97 return NULL;
98 }
99
100 static char const *
cubeb_strings_push(cubeb_strings * strings,char const * s)101 cubeb_strings_push(cubeb_strings * strings, char const * s)
102 {
103 char * is = NULL;
104
105 if (strings->count == strings->size) {
106 char ** new_data;
107 uint32_t value_size = sizeof(char const *);
108 uint32_t new_size = strings->size * 2;
109 if (!new_size || value_size > (uint32_t)-1 / new_size) {
110 // overflow
111 return NULL;
112 }
113
114 if (strings->small_store == strings->data) {
115 // First time heap allocation.
116 new_data = malloc(new_size * value_size);
117 if (new_data) {
118 memcpy(new_data, strings->small_store, sizeof(strings->small_store));
119 }
120 } else {
121 new_data = realloc(strings->data, new_size * value_size);
122 }
123
124 if (!new_data) {
125 // out of memory
126 return NULL;
127 }
128
129 strings->size = new_size;
130 strings->data = new_data;
131 }
132
133 is = strdup(s);
134 strings->data[strings->count++] = is;
135
136 return is;
137 }
138
139 char const *
cubeb_strings_intern(cubeb_strings * strings,char const * s)140 cubeb_strings_intern(cubeb_strings * strings, char const * s)
141 {
142 char const * is = NULL;
143
144 if (!strings || !s) {
145 return NULL;
146 }
147
148 is = cubeb_strings_lookup(strings, s);
149 if (is) {
150 return is;
151 }
152
153 return cubeb_strings_push(strings, s);
154 }
155
156