cubeb_strings.c (2859B)
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 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 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 * 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 * 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 * 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 }