]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - util.c
util_swa_* + GMQCC_INLINE
[xonotic/gmqcc.git] / util.c
diff --git a/util.c b/util.c
index c3d3d4fa2d6cc9c220784c079122f146e508ff1f..f4dbfc4b21a65d759bbc2c81da800b6c1be9b1cb 100644 (file)
--- a/util.c
+++ b/util.c
@@ -25,6 +25,7 @@
 #include <errno.h>
 #include "gmqcc.h"
 
+/* TODO: remove globals ... */
 uint64_t mem_ab = 0;
 uint64_t mem_db = 0;
 uint64_t mem_at = 0;
@@ -41,7 +42,7 @@ struct memblock_t {
 static struct memblock_t *mem_start = NULL;
 
 void *util_memory_a(size_t byte, unsigned int line, const char *file) {
-    struct memblock_t *info = malloc(sizeof(struct memblock_t) + byte);
+    struct memblock_t *info = (struct memblock_t*)malloc(sizeof(struct memblock_t) + byte);
     void              *data = (void*)(info+1);
     if (!info) return NULL;
     info->line = line;
@@ -169,81 +170,13 @@ char *util_strdup(const char *s) {
     if (!s)
         return NULL;
 
-    if ((len = strlen(s)) && (ptr = mem_a(len+1))) {
+    if ((len = strlen(s)) && (ptr = (char*)mem_a(len+1))) {
         memcpy(ptr, s, len);
         ptr[len] = '\0';
     }
     return ptr;
 }
 
-/*
- * Remove quotes from a string, escapes from \ in string
- * as well.  This function shouldn't be used to create a
- * char array that is later freed (it uses pointer arith)
- */
-char *util_strrq(const char *s) {
-    char *dst = (char*)s;
-    char *src = (char*)s;
-    char  chr;
-    while ((chr = *src++) != '\0') {
-        if (chr == '\\') {
-            *dst++ = chr;
-            if ((chr = *src++) == '\0')
-                break;
-            *dst++ = chr;
-        } else if (chr != '"')
-            *dst++ = chr;
-    }
-    *dst = '\0';
-    return dst;
-}
-
-/*
- * Chops a substring from an existing string by creating a
- * copy of it and null terminating it at the required position.
- */
-char *util_strchp(const char *s, const char *e) {
-    const char *c = NULL;
-    if (!s || !e)
-        return NULL;
-
-    c = s;
-    while (c != e)
-        c++;
-
-    return util_strdup(s);
-}
-
-/*
- * Returns true if string is all uppercase, otherwise
- * it returns false.
- */
-bool util_strupper(const char *str) {
-    while (*str) {
-        if(!isupper(*str))
-            return false;
-        str++;
-    }
-    return true;
-}
-
-/*
- * Returns true if string is all digits, otherwise
- * it returns false.
- */
-bool util_strdigit(const char *str) {
-    while (*str) {
-        if(!isdigit(*str))
-            return false;
-        str++;
-    }
-    return true;
-}
-
-bool util_strncmpexact(const char *src, const char *ned, size_t len) {
-    return (!strncmp(src, ned, len) && !src[len]);
-}
-
 void util_debug(const char *area, const char *ms, ...) {
     va_list  va;
     if (!opts.debug)
@@ -259,26 +192,75 @@ void util_debug(const char *area, const char *ms, ...) {
 }
 
 /*
- * Endianess swapping, all data must be stored little-endian.  This
- * reorders by stride and length, much nicer than other functions for
- * certian-sized types like short or int.
- */
-void util_endianswap(void *m, int s, int l) {
-    size_t w = 0;
-    size_t i = 0;
+ * only required if big endian .. otherwise no need to swap
+ * data.
+ */   
+#if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_BIG
+    static GMQCC_INLINE void util_swap16(uint16_t *d, size_t l) {
+        while (l--) {
+            d[l] = (d[l] << 8) | (d[l] >> 8);
+        }
+    }
 
-    /* ignore if we're already LE */
-    if(*((char *)&s))
-        return;
+    static GMQCC_INLINE void util_swap32(uint32_t *d, size_t l) {
+        while (l--) {
+            uint32_t v;
+            v = ((d[l] << 8) & 0xFF00FF00) | ((d[l] >> 8) & 0x00FF00FF);
+            d[l] = (v << 16) | (v >> 16);
+        }
+    }
 
-    for(; w < (size_t)l; w++) {
-        for(;  i < (size_t)(s << 1); i++) {
-            unsigned char *p = (unsigned char *)m+w*s;
-            unsigned char  t = p[i];
-            p[i]             = p[s-i-1];
-            p[s-i-1]         = t;
+    /* Some strange system doesn't like constants that big, AND doesn't recognize an ULL suffix
+     * so let's go the safe way
+     */
+    static GMQCC_INLINE void util_swap64(uint32_t *d, size_t l) {
+        /*
+        while (l--) {
+            uint64_t v;
+            v = ((d[l] << 8) & 0xFF00FF00FF00FF00) | ((d[l] >> 8) & 0x00FF00FF00FF00FF);
+            v = ((v << 16) & 0xFFFF0000FFFF0000) | ((v >> 16) & 0x0000FFFF0000FFFF);
+            d[l] = (v << 32) | (v >> 32);
+        }
+        */
+        size_t i;
+        for (i = 0; i < l; i += 2) {
+            uint32_t v1 = d[i];
+            d[i] = d[i+1];
+            d[i+1] = v1;
+            util_swap32(d+i, 2);
         }
     }
+#endif
+
+void util_endianswap(void *_data, size_t length, unsigned int typesize) {
+#   if PLATFORM_BYTE_ORDER == -1 /* runtime check */
+    if (*((char*)&typesize))
+        return;
+#else
+    /* prevent unused warnings */
+    (void) _data;
+    (void) length;
+    (void) typesize;
+
+#   if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_LITTLE
+        return;
+#   else
+        switch (typesize) {
+            case 1: return;
+            case 2:
+                util_swap16((uint16_t*)_data, length>>1);
+                return;
+            case 4:
+                util_swap32((uint32_t*)_data, length>>2);
+                return;
+            case 8:
+                util_swap64((uint32_t*)_data, length>>3);
+                return;
+
+            default: abort(); /* please blow the fuck up! */
+        }
+#   endif
+#endif
 }
 
 /*
@@ -295,7 +277,7 @@ void util_endianswap(void *m, int s, int l) {
  * In most traditional CRC algorithms on uses a reflected table driven method where a value
  * or register is reflected if it's bits are swapped around it's center.  For example:
  * take the bits 0101 is the 4-bit reflection of 1010, and respectfully 0011 would be the
- * reflection of 1100. Quakle however expects a NON-Reflected CRC on the output, but still
+ * reflection of 1100. Quake however expects a NON-Reflected CRC on the output, but still
  * requires a final XOR on the values (0xFFFF and 0x0000) this is a standard CCITT CRC-16
  * which I respectfully as a programmer don't agree with.
  *
@@ -303,58 +285,6 @@ void util_endianswap(void *m, int s, int l) {
  * but those are what Quake seems to request.
  */
 
-/*
- * This is an implementation of CRC32 & CRC16. The polynomials have been
- * offline computed for faster generation at the cost of larger code size.
- *
- * CRC32 Polynomial: 0xEDB88320
- * CRC16 Polynomial: 0x00001021
- */
-static const uint32_t util_crc32_table[] = {
-    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
-    0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
-    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
-    0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
-    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
-    0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
-    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
-    0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
-    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
-    0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
-    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
-    0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
-    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
-    0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
-    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
-    0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
-    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
-    0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
-    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
-    0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
-    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
-    0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
-    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
-    0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
-    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
-    0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
-    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
-    0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
-    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
-    0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
-    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
-    0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
-    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
-    0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
-    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
-    0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
-    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
-    0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
-    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
-    0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
-    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
-    0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
-    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
-};
 static const uint16_t util_crc16_table[] = {
     0x0000,     0x1021,     0x2042,     0x3063,     0x4084,     0x50A5,
     0x60C6,     0x70E7,     0x8108,     0x9129,     0xA14A,     0xB16B,
@@ -401,80 +331,22 @@ static const uint16_t util_crc16_table[] = {
     0x2E93,     0x3EB2,     0x0ED1,     0x1EF0
 };
 
-/*
- * Implements a CRC function for X worth bits using (uint[X]_t)
- * as type. and util_crc[X]_table.
-
- * Quake expects a non-reflective CRC.
- */
-#define CRC(X) \
-uint##X##_t util_crc##X(uint##X##_t current, const char *k, size_t len) {  \
-    register uint##X##_t h= current;                                  \
-    for (; len; --len, ++k)                                           \
-        h = util_crc##X##_table[(h>>8)^((unsigned char)*k)]^(h<<8);   \
-    return h;                                                         \
+/* Non - Reflected */
+uint16_t util_crc16(uint16_t current, const char *k, size_t len) {
+    register uint16_t h = current;
+    for (; len; --len, ++k) 
+        h = util_crc16_table[(h>>8)^((unsigned char)*k)]^(h<<8);
+    return h;
 }
-CRC(32)
-CRC(16)
-#undef CRC
-/*
-#define CRC(X) \
-uint##X##_t util_crc##X(const char *k, int len, const short clamp) {  \
-    register uint##X##_t h= (uint##X##_t)0xFFFFFFFF;                  \
-    for (; len; --len, ++k)                                           \
-        h = util_crc##X##_table[(h^((unsigned char)*k))&0xFF]^(h>>8); \
-    return (~h)%clamp;                                                \
-}
-*/
-
-
-/*
- * Implements libc getline for systems that don't have it, which is
- * assmed all.  This works the same as getline().
- */
-int util_getline(char **lineptr, size_t *n, FILE *stream) {
-    int   chr;
-    int   ret;
-    char *pos;
-
-    if (!lineptr || !n || !stream)
-        return -1;
-    if (!*lineptr) {
-        if (!(*lineptr = (char*)mem_a((*n=64))))
-            return -1;
-    }
-
-    chr = *n;
-    pos = *lineptr;
-
-    for (;;) {
-        int c = getc(stream);
-
-        if (chr < 2) {
-            *n += (*n > 16) ? *n : 64;
-            chr = *n + *lineptr - pos;
-            if (!(*lineptr = (char*)mem_r(*lineptr,*n)))
-                return -1;
-            pos = *n - chr + *lineptr;
-        }
-
-        if (ferror(stream))
-            return -1;
-        if (c == EOF) {
-            if (pos == *lineptr)
-                return -1;
-            else
-                break;
-        }
-
-        *pos++ = c;
-        chr--;
-        if (c == '\n')
-            break;
-    }
-    *pos = '\0';
-    return (ret = pos - *lineptr);
+/* Reflective Varation (for reference) */
+#if 0
+uint16_t util_crc16(const char *k, int len, const short clamp) {
+    register uint16_t h= (uint16_t)0xFFFFFFFF;
+    for (; len; --len, ++k) 
+        h = util_crc16_table[(h^((unsigned char)*k))&0xFF]^(h>>8);
+    return (~h)%clamp; 
 }
+#endif
 
 size_t util_strtocmd(const char *in, char *out, size_t outsz) {
     size_t sz = 1;
@@ -492,26 +364,17 @@ size_t util_strtononcmd(const char *in, char *out, size_t outsz) {
     return sz-1;
 }
 
-
-FILE *util_fopen(const char *filename, const char *mode)
-{
-#ifdef _MSC_VER
-    FILE *out;
-    if (fopen_s(&out, filename, mode) != 0)
-        return NULL;
-    return out;
-#else
-    return fopen(filename, mode);
-#endif
-}
-
+/* TODO: rewrite ... when I redo the ve cleanup */
 void _util_vec_grow(void **a, size_t i, size_t s) {
-    size_t m = *a ? 2*_vec_beg(*a)+i : i+1;
-    void  *p = mem_r((*a ? _vec_raw(*a) : NULL), s * m + sizeof(size_t)*2);
+    vector_t *d = vec_meta(*a);
+    size_t    m = *a ? 2 * d->allocated +i : i+1;
+    void     *p = mem_r((*a ? d : NULL), s * m + sizeof(vector_t));
+
     if (!*a)
-        ((size_t*)p)[1] = 0;
-    *a = (void*)((size_t*)p + 2);
-    _vec_beg(*a) = m;
+        ((vector_t*)p)->used = 0;
+    *a = (vector_t*)p + 1;
+
+    vec_meta(*a)->allocated = m;
 }
 
 /*
@@ -525,61 +388,11 @@ typedef struct hash_node_t {
     struct hash_node_t *next;  /* next node (linked list)        */
 } hash_node_t;
 
-/*
- * x86 and x86_64 optimized murmur hash functions for the hashtable
- * we have individual implementations for optimal performance.
- *
- * Forced inlined as we wrap these up in the actual utility function
- * below.  These should be autovectorized by gcc.
- */
-#ifdef __x86_64__
-GMQCC_INLINE uint32_t util_hthashfunc(hash_table_t *ht, const char *key, register size_t seed) {
-    const uint64_t       mix   = 0xC6A4A7935BD1E995UL;
-    const int            rot   = 47;
-    size_t               size  = strlen(key);
-    uint64_t             hash  = seed ^ (size - mix);
-    uint64_t             alias = 0;
-    const uint64_t      *beg   = (const uint64_t*)key;
-    const uint64_t      *end   = beg + (size / 8);
-    const unsigned char *final = NULL;
-
-    while (beg != end) {
-        alias = *beg++;
-
-        alias *= mix;
-        alias ^= alias >> rot;
-        alias *= mix;
-
-        hash  ^= alias;
-        hash  *= mix;
-    }
-
-    final = (const unsigned char *)beg;
-
-    switch (size & 7) {
-        case 7: hash ^= (uint64_t)(final[6]) << 48;
-        case 6: hash ^= (uint64_t)(final[5]) << 40;
-        case 5: hash ^= (uint64_t)(final[4]) << 32;
-        case 4: hash ^= (uint64_t)(final[3]) << 24;
-        case 3: hash ^= (uint64_t)(final[2]) << 16;
-        case 2: hash ^= (uint64_t)(final[1]) << 8;
-        case 1: hash ^= (uint64_t)(final[0]);
-                hash *= mix;
-    }
-
-    hash ^= hash >> rot;
-    hash *= mix;
-    hash ^= hash >> rot;
-
-    return (uint32_t)(hash % ht->size);
-}
-
-#else
-GMQCC_INLINE uint32_t util_hthashfunc(hash_table_t *ht, const char *key, register size_t seed) {
+GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) {
     const uint32_t       mix   = 0x5BD1E995;
     const uint32_t       rot   = 24;
     size_t               size  = strlen(key);
-    uint32_t             hash  = seed ^ size;
+    uint32_t             hash  = 0x1EF0 /* LICRC TAB */  ^ size;
     uint32_t             alias = 0;
     const unsigned char *data  = (const unsigned char*)key;
 
@@ -608,25 +421,12 @@ GMQCC_INLINE uint32_t util_hthashfunc(hash_table_t *ht, const char *key, registe
     hash *= mix;
     hash ^= hash >> 15;
 
-    return hash % ht->size;
-}
-#endif
-
-/* we use the crc table as seeds for the murmur hash :P */
-size_t util_hthash(hash_table_t *ht, const char *key) {
-    static   size_t seed = 0;
-    register size_t hash = util_hthashfunc(ht, key, util_crc32_table[seed]);
-
-    /* reset seed */
-    if (seed >= sizeof(util_crc32_table) / sizeof(*util_crc32_table))
-        seed  = 0;
-
-    return hash;
+    return (size_t) (hash % ht->size);
 }
 
 hash_node_t *_util_htnewpair(const char *key, void *value) {
     hash_node_t *node;
-    if (!(node = mem_a(sizeof(hash_node_t))))
+    if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t))))
         return NULL;
 
     if (!(node->key = util_strdup(key))) {
@@ -652,10 +452,10 @@ hash_table_t *util_htnew(size_t size) {
     if (size < 1)
         return NULL;
 
-    if (!(hashtable = mem_a(sizeof(hash_table_t))))
+    if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t))))
         return NULL;
 
-    if (!(hashtable->table = mem_a(sizeof(hash_node_t*) * size))) {
+    if (!(hashtable->table = (hash_node_t**)mem_a(sizeof(hash_node_t*) * size))) {
         mem_d(hashtable);
         return NULL;
     }