2 * Copyright (C) 2013-2014 Intel Corporation.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * José Bollo <jose.bollo@open.eurogiciel.org>
20 * Stéphane Desneux <stephane.desneux@open.eurogiciel.org>
21 * Jean-Benoit Martin <jean-benoit.martin@open.eurogiciel.org>
33 #ifndef INITIAL_SCRATCH_CAPACITY
34 #define INITIAL_SCRATCH_CAPACITY 240
37 #if INITIAL_SCRATCH_CAPACITY <= 0
38 #error "bad value for INITIAL_SCRATCH_CAPACITY"
43 #define SET_CAPACITY 97
44 #define HASHCODE_INIT 5381
45 #define HASHCODE_NEXT(H,C) (((H) << 5) + (H) + (C))
48 #ifndef NOT_MULTI_THREAD_SAFE
52 #if !(defined(NOT_MULTI_THREAD_SAFE) || INSTANCIATE)
53 static __thread void *global_scratch = NULL;
55 static void *global_scratch = NULL;
57 #if INSTANCIATE && !defined(NOT_MULTI_THREAD_SAFE)
58 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
62 /* structure for recording items in the hash map */
64 struct set_item *next; /* chain to next item */
65 size_t hashcode; /* hash of the string */
66 size_t length; /* length of the string including null */
69 /* the array of recorded strings */
70 static struct set_item *global_path_set[SET_CAPACITY]; /* initialized to zeros */
72 /* instanciate (or retrieve an instance) of the 'string' that
73 is granted to have the 'length' including terminating null and a
74 hash code 'hashcode' */
75 static const char *instantiate(const char *string, size_t length, size_t hashcode)
77 struct set_item **pp, *item;
80 /* get first item in the table */
81 pp = &global_path_set[hashcode % SET_CAPACITY];
84 /* inspect the item */
87 /* no item: create it */
88 item = malloc(length + sizeof * item);
93 item->hashcode = hashcode;
94 item->length = length;
95 result = (char *)(item + 1);
96 memcpy(result, string, length);
99 } else if (item->hashcode == hashcode
100 && item->length == length
101 && 0 == strcmp(string, (const char *)(item + 1))) {
103 result = (char *)(item + 1);
114 /* CAUTION: in a multitheaded context, it is expected that
115 =========== the function scratchcat is call under a mutex.
116 If it is not the case please check for initializing 'tlskey'
117 only one time before use of it. */
119 #if INSTANCIATE && !defined(NOT_MULTI_THREAD_SAFE)
120 static const char *_scratchcat( int ispath, const char **strings);
122 const char *scratchcat( int ispath, const char **strings)
125 pthread_mutex_lock(&mutex);
126 result = _scratchcat( ispath, strings);
127 pthread_mutex_unlock(&mutex);
131 static const char *_scratchcat( int ispath, const char **strings)
133 const char *scratchcat( int ispath, const char **strings)
138 size_t length, capacity;
142 size_t hashcode = HASHCODE_INIT;
145 /* get the recorded pointer on scrtch area */
146 scratch = global_scratch;
148 /* create the scratch area if needed */
149 if (scratch == NULL) {
150 capacity = INITIAL_SCRATCH_CAPACITY;
151 p = malloc( capacity + sizeof(size_t));
154 *((size_t*)p) = capacity;
159 /* set local data for scratch area */
160 capacity = *((size_t*)scratch);
161 result = (char*)(1+((size_t*)scratch));
164 /* copy the strings */
177 else if(c != '/' && pc != '/')
179 else if(c == '/' && pc == '/') {
194 /* extend the scratch area if needed */
195 if (length == capacity) {
196 capacity = 2 * capacity;
197 p = realloc( scratch, capacity + sizeof(size_t));
200 *((size_t*)p) = capacity;
204 result = (char*)(1+((size_t*)p));
208 /* append the char */
209 pc = result[length++] = c;
211 hashcode = HASHCODE_NEXT(hashcode, (size_t)c);
216 return instantiate(result, length, hashcode);
225 int main(int argc, const char**argv) {
228 ispath = argv[0] && argv[0][0] == '-' && argv[0][1] == 'p';
229 for (i = 0 ; i < 2 ; i++) {
231 while (iter < argc) {
232 const char *p = scratchcat(ispath,argv+iter++);
233 printf("%p: %s\n",p,p);