Line data Source code
1 : /* 2 : * intern.c 3 : * Patater GUI Kit 4 : * 5 : * Created by Jaeden Amero on 2019-05-06. 6 : * Copyright 2019. SPDX-License-Identifier: AGPL-3.0-or-later 7 : */ 8 : 9 : #include "guikit/intern.h" 10 : #include "guikit/array.h" 11 : #include "guikit/hash.h" 12 : #include "guikit/hashmap.h" 13 : #include "guikit/pmemory.h" 14 : #include "guikit/ptypes.h" 15 : #include <stddef.h> 16 : #include <string.h> 17 : 18 : static struct hashmap *intern_map = NULL; 19 : static int num_hits = 0; 20 : static char **intern_array; 21 : 22 5 : void intern_free(void) 23 : { 24 : size_t len; 25 : size_t i; 26 : 27 5 : hashmap_free(intern_map); 28 5 : intern_map = NULL; 29 : 30 5 : len = array_len(intern_array); 31 11 : for (i = 0; i < len; i++) 32 : { 33 6 : pfree(intern_array[i]); 34 : } 35 5 : array_free(intern_array); 36 : 37 5 : num_hits = 0; 38 5 : } 39 : 40 8 : const char *intern(const char *s) 41 : { 42 : size_t len; 43 : const char *interned; 44 : char *copy; 45 8 : u32 key[2]; 46 : 47 : /* Lazy load the intern map */ 48 8 : if (!intern_map) 49 : { 50 5 : intern_map = hashmap_alloc(); 51 : } 52 : 53 8 : len = strlen(s); 54 8 : hash64(key, s, len); 55 8 : interned = (const char *)hashmap_get(intern_map, key); 56 8 : if (interned != 0) 57 : { 58 : /* Found previous copy */ 59 2 : num_hits += 1; 60 2 : return interned; 61 : } 62 : 63 : /* Didn't find previous copy, so add it to the intern map. */ 64 : /* Note that we own the memory for the string we are interning. We do this 65 : * so that one can intern strings they've made up on the fly (temporary 66 : * strings) without the intern storage disappearing out from under us. 67 : * 68 : * We track pointers to allocated memory in the intern array. This allows 69 : * us to free all the memory we've allocated without using the hash map. 70 : * 71 : * We don't provide a way to avoid string copying at the moment, although 72 : * this would be straightforward to implement given we are tracking 73 : * allocated memory. If we did not have a separate intern_array, we would 74 : * find it very hard to track such things as the pointers in the hash map's 75 : * values array may or may not be strings we've allocated. TODO add a 76 : * function to not copy-intern to enable callers to make more efficient use 77 : * of string storage. */ 78 6 : copy = pmalloc(len + 1); 79 6 : strcpy(copy, s); 80 6 : array_push(intern_array, copy); /* Track allocated memory */ 81 6 : hashmap_put(intern_map, key, (ptrdiff_t)copy); 82 6 : interned = copy; 83 : 84 6 : return interned; 85 : } 86 : 87 4 : int intern_num_hits(void) 88 : { 89 4 : return num_hits; 90 : } 91 : 92 4 : int intern_num_interned(void) 93 : { 94 4 : return array_len(intern_array); 95 : }