blob: 93ae3ab665ef471100f6d40e8b6c4aad1069e2fe [file] [log] [blame]
Damien429d7192013-10-04 19:53:11 +01001#include <assert.h>
2#include <string.h>
3
4#include "misc.h"
Damien Georgeeb7bfcb2014-01-04 15:57:35 +00005#include "mpqstr.h"
Damien429d7192013-10-04 19:53:11 +01006
Damien Georgeeb7bfcb2014-01-04 15:57:35 +00007// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
8// ultimately we will replace this with a static hash table of some kind
9// also probably need to include the length in the string data, to allow null bytes in the string
10
11#if 0 // print debugging info
12#include <stdio.h>
13#define DEBUG_printf(args...) printf(args)
14#else // don't print debugging info
15#define DEBUG_printf(args...) (void)0
16#endif
17
18typedef struct _qstr_pool_t {
19 struct _qstr_pool_t *prev;
20 uint total_prev_len;
21 uint alloc;
22 uint len;
23 const char *qstrs[];
24} qstr_pool_t;
25
26const static qstr_pool_t const_pool = {
27 NULL, // no previous pool
28 0, // no previous pool
29 10, // set so that the first dynamically allocated pool is twice this size; must be <= the len (just below)
30 MP_QSTR_number_of, // corresponds to number of strings in array just below
31 {
32 "nil", // must be first, since 0 qstr is nil
33#define Q(id) #id,
34#include "mpqstrraw.h"
35#undef Q
36 },
37};
38
Dave Hylandsd986b582014-01-05 11:55:23 -080039static qstr_pool_t *last_pool;
Damien429d7192013-10-04 19:53:11 +010040
Damien8b3a7c22013-10-23 20:20:17 +010041void qstr_init(void) {
Dave Hylandsd986b582014-01-05 11:55:23 -080042 last_pool = (qstr_pool_t*)&const_pool; // we won't modify the const_pool since it has no allocated room left
Damien429d7192013-10-04 19:53:11 +010043}
44
45static qstr qstr_add(const char *str) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +000046 DEBUG_printf("QSTR: add %s\n", str);
47
48 // make sure we have room in the pool for a new qstr
49 if (last_pool->len >= last_pool->alloc) {
50 qstr_pool_t *pool = m_new_obj_var(qstr_pool_t, const char*, last_pool->alloc * 2);
51 pool->prev = last_pool;
52 pool->total_prev_len = last_pool->total_prev_len + last_pool->len;
53 pool->alloc = last_pool->alloc * 2;
54 pool->len = 0;
55 last_pool = pool;
56 DEBUG_printf("QSTR: allocate new pool of size %d\n", last_pool->alloc);
Damien429d7192013-10-04 19:53:11 +010057 }
Damien Georgeeb7bfcb2014-01-04 15:57:35 +000058
59 // add the new qstr
60 last_pool->qstrs[last_pool->len++] = str;
61
62 // return id for the newly-added qstr
63 return last_pool->total_prev_len + last_pool->len - 1;
Damien429d7192013-10-04 19:53:11 +010064}
65
66qstr qstr_from_str_static(const char *str) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +000067 for (qstr_pool_t *pool = last_pool; pool != NULL; pool = pool->prev) {
68 for (const char **qstr = pool->qstrs, **qstr_top = pool->qstrs + pool->len; qstr < qstr_top; qstr++) {
69 if (strcmp(*qstr, str) == 0) {
70 return pool->total_prev_len + (qstr - pool->qstrs);
71 }
Damien429d7192013-10-04 19:53:11 +010072 }
73 }
74 return qstr_add(str);
75}
76
Damien732407f2013-12-29 19:33:23 +000077qstr qstr_from_str_take(char *str, int alloc_len) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +000078 for (qstr_pool_t *pool = last_pool; pool != NULL; pool = pool->prev) {
79 for (const char **qstr = pool->qstrs, **qstr_top = pool->qstrs + pool->len; qstr < qstr_top; qstr++) {
80 if (strcmp(*qstr, str) == 0) {
81 m_del(char, str, alloc_len);
82 return pool->total_prev_len + (qstr - pool->qstrs);
83 }
Damien429d7192013-10-04 19:53:11 +010084 }
85 }
86 return qstr_add(str);
87}
88
89qstr qstr_from_strn_copy(const char *str, int len) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +000090 for (qstr_pool_t *pool = last_pool; pool != NULL; pool = pool->prev) {
91 for (const char **qstr = pool->qstrs, **qstr_top = pool->qstrs + pool->len; qstr < qstr_top; qstr++) {
92 if (strncmp(*qstr, str, len) == 0 && (*qstr)[len] == '\0') {
93 return pool->total_prev_len + (qstr - pool->qstrs);
94 }
Damien429d7192013-10-04 19:53:11 +010095 }
96 }
97 return qstr_add(strndup(str, len));
98}
99
Damien Georgeeb7bfcb2014-01-04 15:57:35 +0000100// convert qstr id to pointer to its string
Damien429d7192013-10-04 19:53:11 +0100101const char *qstr_str(qstr qstr) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +0000102 // search
103 for (qstr_pool_t *pool = last_pool; pool != NULL; pool = pool->prev) {
104 if (qstr >= pool->total_prev_len) {
105 return pool->qstrs[qstr - pool->total_prev_len];
106 }
107 }
108
109 // not found, return nil
110 return const_pool.qstrs[0];
Damien429d7192013-10-04 19:53:11 +0100111}