klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

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 }