kbytevector.c (5570B)
1 /* 2 ** kbytevector.c 3 ** Kernel Byte Vectors 4 ** See Copyright Notice in klisp.h 5 */ 6 7 #include <string.h> 8 9 #include "kbytevector.h" 10 #include "kobject.h" 11 #include "kstate.h" 12 #include "kmem.h" 13 #include "kgc.h" 14 /* for immutable table */ 15 #include "kstring.h" 16 17 /* Constructors */ 18 19 /* General constructor for bytevectors */ 20 TValue kbytevector_new_bs_g(klisp_State *K, bool m, const uint8_t *buf, 21 uint32_t size) 22 { 23 return m? kbytevector_new_bs(K, buf, size) : 24 kbytevector_new_bs_imm(K, buf, size); 25 } 26 27 /* LOCK: GIL should be acquired */ 28 static uint32_t get_bytevector_hash(const uint8_t *buf, uint32_t size) 29 { 30 uint32_t h = size; /* seed */ 31 size_t step = (size>>5)+1; /* if bytevector is too long, don't hash all 32 its bytes */ 33 size_t size1; 34 for (size1 = size; size1 >= step; size1 -= step) /* compute hash */ 35 h = h ^ ((h<<5)+(h>>2)+ buf[size1-1]); 36 37 return h; 38 } 39 40 /* Looks for a bytevector in the stringtable and returns a pointer 41 to it if found or NULL otherwise. */ 42 static Bytevector *search_in_bb_table(klisp_State *K, const uint8_t *buf, 43 uint32_t size, uint32_t h) 44 { 45 46 for (GCObject *o = G(K)->strt.hash[lmod(h, G(K)->strt.size)]; 47 o != NULL; o = o->gch.next) { 48 klisp_assert(o->gch.tt == K_TKEYWORD || o->gch.tt == K_TSYMBOL || 49 o->gch.tt == K_TSTRING || o->gch.tt == K_TBYTEVECTOR); 50 51 if (o->gch.tt != K_TBYTEVECTOR) continue; 52 53 Bytevector *tb = (Bytevector *) o; 54 if (tb->size == size && (memcmp(buf, tb->b, size) == 0)) { 55 /* bytevector may be dead */ 56 if (isdead(G(K), o)) changewhite(o); 57 return tb; 58 } 59 } 60 return NULL; 61 } 62 63 64 /* 65 ** Constructors for immutable bytevectors 66 */ 67 68 /* main constructor for immutable bytevectors */ 69 TValue kbytevector_new_bs_imm(klisp_State *K, const uint8_t *buf, uint32_t size) 70 { 71 uint32_t h = get_bytevector_hash(buf, size); 72 73 /* first check to see if it's in the stringtable */ 74 Bytevector *new_bb = search_in_bb_table(K, buf, size, h); 75 76 if (new_bb != NULL) { /* found */ 77 return gc2bytevector(new_bb); 78 } 79 80 /* If it exits the loop, it means it wasn't found, hash is still in h */ 81 /* REFACTOR: move all of these to a new function */ 82 83 if (size > (SIZE_MAX - sizeof(Bytevector))) 84 klispM_toobig(K); 85 86 new_bb = (Bytevector *) klispM_malloc(K, sizeof(Bytevector) + size); 87 88 /* header + gc_fields */ 89 /* can't use klispC_link, because strings use the next pointer 90 differently */ 91 new_bb->gct = klispC_white(G(K)); 92 new_bb->tt = K_TBYTEVECTOR; 93 new_bb->kflags = K_FLAG_IMMUTABLE; 94 new_bb->si = NULL; 95 96 /* bytevector specific fields */ 97 new_bb->hash = h; 98 new_bb->mark = KFALSE; 99 new_bb->size = size; 100 101 if (size != 0) { 102 memcpy(new_bb->b, buf, size); 103 } 104 105 /* add to the string/symbol table (and link it) */ 106 stringtable *tb; 107 tb = &G(K)->strt; 108 h = lmod(h, tb->size); 109 new_bb->next = tb->hash[h]; /* chain new entry */ 110 tb->hash[h] = (GCObject *)(new_bb); 111 tb->nuse++; 112 TValue ret_tv = gc2bytevector(new_bb); 113 if (tb->nuse > ((uint32_t) tb->size) && tb->size <= INT32_MAX / 2) { 114 krooted_tvs_push(K, ret_tv); /* save in case of gc */ 115 klispS_resize(K, tb->size*2); /* too crowded */ 116 krooted_tvs_pop(K); 117 } 118 119 return ret_tv; 120 } 121 122 /* 123 ** Constructors for mutable bytevectors 124 */ 125 126 /* main constructor for mutable bytevectors */ 127 /* with just size */ 128 TValue kbytevector_new_s(klisp_State *K, uint32_t size) 129 { 130 Bytevector *new_bb; 131 132 if (size == 0) { 133 klisp_assert(ttisbytevector(G(K)->empty_bytevector)); 134 return G(K)->empty_bytevector; 135 } 136 137 new_bb = klispM_malloc(K, sizeof(Bytevector) + size); 138 139 /* header + gc_fields */ 140 klispC_link(K, (GCObject *) new_bb, K_TBYTEVECTOR, 0); 141 142 /* bytevector specific fields */ 143 new_bb->mark = KFALSE; 144 new_bb->size = size; 145 146 /* the buffer is initialized elsewhere */ 147 return gc2bytevector(new_bb); 148 } 149 150 /* with buffer & size */ 151 TValue kbytevector_new_bs(klisp_State *K, const uint8_t *buf, uint32_t size) 152 { 153 if (size == 0) { 154 klisp_assert(ttisbytevector(G(K)->empty_bytevector)); 155 return G(K)->empty_bytevector; 156 } 157 158 TValue new_bb = kbytevector_new_s(K, size); 159 memcpy(kbytevector_buf(new_bb), buf, size); 160 return new_bb; 161 } 162 163 /* with size and fill uint8_t */ 164 TValue kbytevector_new_sf(klisp_State *K, uint32_t size, uint8_t fill) 165 { 166 if (size == 0) { 167 klisp_assert(ttisbytevector(G(K)->empty_bytevector)); 168 return G(K)->empty_bytevector; 169 } 170 171 TValue new_bb = kbytevector_new_s(K, size); 172 memset(kbytevector_buf(new_bb), fill, size); 173 return new_bb; 174 } 175 176 /* both obj1 and obj2 should be bytevectors */ 177 bool kbytevector_equalp(klisp_State *K, TValue obj1, TValue obj2) 178 { 179 klisp_assert(ttisbytevector(obj1) && ttisbytevector(obj2)); 180 181 Bytevector *bytevector1 = tv2bytevector(obj1); 182 Bytevector *bytevector2 = tv2bytevector(obj2); 183 184 if (bytevector1->size == bytevector2->size) { 185 return (bytevector1->size == 0) || 186 (memcmp(bytevector1->b, bytevector2->b, bytevector1->size) == 0); 187 } else { 188 return false; 189 } 190 } 191 192 bool kbytevectorp(TValue obj) { return ttisbytevector(obj); } 193 bool kimmutable_bytevectorp(TValue obj) 194 { 195 return ttisbytevector(obj) && kis_immutable(obj); 196 } 197 bool kmutable_bytevectorp(TValue obj) 198 { 199 return ttisbytevector(obj) && kis_mutable(obj); 200 }