summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xs.h250
-rw-r--r--xs_version.h2
2 files changed, 168 insertions, 84 deletions
diff --git a/xs.h b/xs.h
index 4da0d6f..f479108 100644
--- a/xs.h
+++ b/xs.h
@@ -1040,12 +1040,29 @@ xs_keyval *xs_keyval_make(xs_keyval *keyval, const xs_str *key, const xs_val *va
1040 1040
1041/** dicts **/ 1041/** dicts **/
1042 1042
1043typedef struct {
1044 int value_offset; /* offset to value (from dict start) */
1045 int next; /* next node in sequential search */
1046 int child[4]; /* child nodes in hashed search */
1047 char key[]; /* C string key */
1048} ditem_hdr;
1049
1050typedef struct {
1051 int size; /* size of full dict (_XS_TYPE_SIZE) */
1052 int first; /* first node for sequential search */
1053 int root; /* root node for hashed search */
1054 ditem_hdr ditems[]; /* the ditems */
1055} dict_hdr;
1056
1057
1043xs_dict *xs_dict_new(void) 1058xs_dict *xs_dict_new(void)
1044/* creates a new dict */ 1059/* creates a new dict */
1045{ 1060{
1046 int sz = 1 + _XS_TYPE_SIZE + 1; 1061 /* size of dict */
1062 int sz = 1 + sizeof(dict_hdr);
1063
1047 xs_dict *d = xs_realloc(NULL, sz); 1064 xs_dict *d = xs_realloc(NULL, sz);
1048 memset(d, XSTYPE_EOM, sz); 1065 memset(d, '\0', sz);
1049 1066
1050 d[0] = XSTYPE_DICT; 1067 d[0] = XSTYPE_DICT;
1051 _xs_put_size(d, sz); 1068 _xs_put_size(d, sz);
@@ -1053,140 +1070,207 @@ xs_dict *xs_dict_new(void)
1053 return d; 1070 return d;
1054} 1071}
1055 1072
1056 1073static int *_xs_dict_locate(const xs_dict *dict, const char *key)
1057xs_dict *_xs_dict_write_keyval(xs_dict *dict, int offset, const xs_str *key, const xs_val *value) 1074/* locates a ditem */
1058/* adds a new keyval to the dict */
1059{ 1075{
1060 XS_ASSERT_TYPE(dict, XSTYPE_DICT); 1076 unsigned int h = xs_hash_func(key, strlen(key));
1061 XS_ASSERT_TYPE(key, XSTYPE_STRING);
1062 1077
1063 if (value == NULL) 1078 /* start from the root */
1064 value = xs_stock(XSTYPE_NULL); 1079 dict_hdr *dh = (dict_hdr *)(dict + 1);
1080 int *off = &dh->root;
1065 1081
1066 dict = xs_expand(dict, offset, xs_keyval_size(key, value)); 1082 while (*off) {
1083 /* pointer to ditem */
1084 ditem_hdr *di = (ditem_hdr *)(dict + *off);
1067 1085
1068 xs_keyval_make(&dict[offset], key, value); 1086 /* pointer to the key */
1087 const char *d_key = di->key;
1069 1088
1070 return dict; 1089 if (strcmp(key, d_key) == 0)
1071} 1090 break;
1072 1091
1092 off = &di->child[h >> 30];
1093 h <<= 2;
1094 }
1073 1095
1074xs_dict *xs_dict_append(xs_dict *dict, const xs_str *key, const xs_val *value) 1096 return off;
1075/* appends a memory block to the dict */
1076{
1077 return _xs_dict_write_keyval(dict, xs_size(dict) - 1, key, value);
1078} 1097}
1079 1098
1080 1099
1081xs_dict *xs_dict_prepend(xs_dict *dict, const xs_str *key, const xs_val *value) 1100xs_dict *xs_dict_set(xs_dict *dict, const xs_str *key, const xs_val *value)
1082/* prepends a memory block to the dict */ 1101/* sets a key/value pair */
1083{ 1102{
1084 return _xs_dict_write_keyval(dict, 1 + _XS_TYPE_SIZE, key, value); 1103 if (value == NULL)
1085} 1104 value = xs_stock(XSTYPE_NULL);
1086 1105
1106 if (xs_type(dict) == XSTYPE_DICT) {
1107 int *o = _xs_dict_locate(dict, key);
1108 int end = xs_size(dict);
1087 1109
1088int xs_dict_next(const xs_dict *dict, const xs_str **key, const xs_val **value, int *ctxt) 1110 if (!*o) {
1089/* iterates a dict, with context */ 1111 /* ditem does not exist yet: append to the end */
1090{ 1112 *o = end;
1091 if (xs_type(dict) != XSTYPE_DICT)
1092 return 0;
1093 1113
1094 int goon = 1; 1114 int ksz = xs_size(key);
1115 int vsz = xs_size(value);
1116 int dsz = sizeof(ditem_hdr) + ksz + vsz;
1095 1117
1096 char *p = (char *)dict; 1118 /* open room in the dict for the full ditem */
1119 dict = xs_expand(dict, end, dsz);
1097 1120
1098 /* skip the start of the list */ 1121 dict_hdr *dh = (dict_hdr *)(dict + 1);
1099 if (*ctxt == 0)
1100 *ctxt = 1 + _XS_TYPE_SIZE;
1101 1122
1102 p += *ctxt; 1123 /* build the ditem */
1124 ditem_hdr *di = (ditem_hdr *)(dict + end);
1125 memset(di, '\0', dsz);
1103 1126
1104 /* an element? */ 1127 /* set the offset to the value */
1105 if (xs_type(p) == XSTYPE_KEYVAL) { 1128 di->value_offset = end + sizeof(ditem_hdr) + ksz;
1106 p++;
1107 1129
1108 *key = p; 1130 /* copy the key */
1109 p += xs_size(*key); 1131 memcpy(di->key, key, ksz);
1110 1132
1111 *value = p; 1133 /* copy the value */
1112 p += xs_size(*value); 1134 memcpy(dict + di->value_offset, value, vsz);
1113 } 1135
1114 else { 1136 /* chain to the sequential list */
1115 /* end of list */ 1137 di->next = dh->first;
1116 goon = 0; 1138 dh->first = end;
1139 }
1140 else {
1141 /* ditem already exists */
1142 ditem_hdr *di = (ditem_hdr *)(dict + *o);
1143
1144 /* get pointer to the value offset */
1145 int *i = &di->value_offset;
1146
1147 /* deleted? recover offset */
1148 if (*i < 0)
1149 *i *= -1;
1150
1151 /* get old value */
1152 xs_val *o_value = dict + *i;
1153
1154 /* will new value fit over the old one? */
1155 if (xs_size(value) <= xs_size(o_value)) {
1156 /* just overwrite */
1157 /* (difference is leaked inside the dict) */
1158 memcpy(o_value, value, xs_size(value));
1159 }
1160 else {
1161 /* not enough room: new value will live at the end of the dict */
1162 /* (old value is leaked inside the dict) */
1163 *i = end;
1164
1165 dict = xs_insert(dict, end, value);
1166 }
1167 }
1117 } 1168 }
1118 1169
1119 /* store back the pointer */ 1170 return dict;
1120 *ctxt = p - dict; 1171}
1121 1172
1122 return goon; 1173
1174xs_dict *xs_dict_append(xs_dict *dict, const xs_str *key, const xs_val *value)
1175/* just an alias (for this implementation it's the same) */
1176{
1177 return xs_dict_set(dict, key, value);
1123} 1178}
1124 1179
1125 1180
1126const xs_val *xs_dict_get_def(const xs_dict *dict, const xs_str *key, const xs_val *def) 1181xs_dict *xs_dict_prepend(xs_dict *dict, const xs_str *key, const xs_val *value)
1127/* returns the value directed by key, or the default value */ 1182/* just an alias (for this implementation it's the same) */
1128{ 1183{
1129 XS_ASSERT_TYPE(dict, XSTYPE_DICT); 1184 return xs_dict_set(dict, key, value);
1130 XS_ASSERT_TYPE(key, XSTYPE_STRING); 1185}
1131 1186
1132 const xs_str *k;
1133 const xs_val *v;
1134 int c = 0;
1135 1187
1136 while (xs_dict_next(dict, &k, &v, &c)) { 1188xs_dict *xs_dict_del(xs_dict *dict, const xs_str *key)
1137 if (strcmp(k, key) == 0) 1189/* deletes a key/value pair */
1138 return v; 1190{
1191 if (xs_type(dict) == XSTYPE_DICT) {
1192 int *o = _xs_dict_locate(dict, key);
1193
1194 if (*o) {
1195 /* found ditem */
1196 ditem_hdr *di = (ditem_hdr *)(dict + *o);
1197
1198 /* deleted ditems have a negative value offset */
1199 di->value_offset *= -1;
1200 }
1139 } 1201 }
1140 1202
1141 return (xs_val *)def; 1203 return dict;
1142} 1204}
1143 1205
1144 1206
1145xs_dict *xs_dict_del(xs_dict *dict, const xs_str *key) 1207const xs_val *xs_dict_get_def(const xs_dict *dict, const xs_str *key, const xs_str *def)
1146/* deletes a key */ 1208/* gets a value by key, or returns def */
1147{ 1209{
1148 XS_ASSERT_TYPE(dict, XSTYPE_DICT); 1210 if (xs_type(dict) == XSTYPE_DICT) {
1149 XS_ASSERT_TYPE(key, XSTYPE_STRING); 1211 int *o = _xs_dict_locate(dict, key);
1150
1151 const xs_str *k;
1152 const xs_val *v;
1153 int c = 0;
1154 1212
1155 while (xs_dict_next(dict, &k, &v, &c)) { 1213 if (*o) {
1156 if (strcmp(k, key) == 0) { 1214 /* found ditem */
1157 /* the address of the item is just behind the key */ 1215 ditem_hdr *di = (ditem_hdr *)(dict + *o);
1158 char *i = (char *)k - 1;
1159 1216
1160 dict = xs_collapse(dict, i - dict, xs_size(i)); 1217 if (di->value_offset > 0)
1161 break; 1218 return dict + di->value_offset;
1162 } 1219 }
1163 } 1220 }
1164 1221
1165 return dict; 1222 return def;
1166} 1223}
1167 1224
1168 1225
1169xs_dict *xs_dict_set(xs_dict *dict, const xs_str *key, const xs_val *data) 1226int xs_dict_next(const xs_dict *dict, const xs_str **key, const xs_val **value, int *ctxt)
1170/* sets (replaces) a key */ 1227/* dict iterator, with context */
1171{ 1228{
1172 XS_ASSERT_TYPE(dict, XSTYPE_DICT); 1229 if (xs_type(dict) != XSTYPE_DICT)
1173 XS_ASSERT_TYPE(key, XSTYPE_STRING); 1230 return 0;
1174 1231
1175 /* delete the possibly existing key */ 1232 if (*ctxt == 0) {
1176 dict = xs_dict_del(dict, key); 1233 /* at the beginning: get the first sequential item */
1234 const dict_hdr *dh = (dict_hdr *)(dict + 1);
1235 *ctxt = dh->first;
1236 }
1177 1237
1178 /* add the data */ 1238 *value = NULL;
1179 dict = xs_dict_append(dict, key, data);
1180 1239
1181 return dict; 1240 while (*value == NULL && *ctxt > 0) {
1241 const ditem_hdr *di = (ditem_hdr *)(dict + *ctxt);
1242
1243 /* get value */
1244 if (di->value_offset > 0) {
1245 *value = (xs_val *)(dict + di->value_offset);
1246
1247 /* get key */
1248 *key = (xs_str *)&di->key;
1249 }
1250
1251 /* get offset to next ditem */
1252 *ctxt = di->next ? di->next : -1;
1253 }
1254
1255 return *value != NULL;
1182} 1256}
1183 1257
1184 1258
1185xs_dict *xs_dict_gc(xs_dict *dict) 1259xs_dict *xs_dict_gc(xs_dict *dict)
1186/* collects garbage (leaked values) inside a dict */ 1260/* collects garbage (leaked values) inside a dict */
1187{ 1261{
1188 /* this kind of dicts does not get garbage */ 1262 xs_dict *nd = xs_dict_new();
1189 return dict; 1263 const xs_str *k;
1264 const xs_val *v;
1265 int c = 0;
1266
1267 /* shamelessly create a new dict with the same content */
1268 while (xs_dict_next(dict, &k, &v, &c))
1269 nd = xs_dict_set(nd, k, v);
1270
1271 xs_free(dict);
1272
1273 return nd;
1190} 1274}
1191 1275
1192 1276
diff --git a/xs_version.h b/xs_version.h
index 62f2aca..d647240 100644
--- a/xs_version.h
+++ b/xs_version.h
@@ -1 +1 @@
/* efb85fa3768a86f1609c520f0c86e8f87239b695 2024-05-27T08:24:40+02:00 */ /* 4595e864ae31bc59cca0fff38bd2bac798c2b038 2024-06-08T19:50:32+02:00 */