Skip to content

Commit

Permalink
feature request akheron#595 coded
Browse files Browse the repository at this point in the history
  • Loading branch information
bstarynk committed Oct 13, 2021
1 parent eb81670 commit 6ff908f
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 6 deletions.
215 changes: 211 additions & 4 deletions src/dump.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2021 Petri Lehtinen <[email protected]>
* and Basile Starynkevitch <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
Expand Down Expand Up @@ -35,6 +36,207 @@ struct buffer {
char *data;
};


struct attribute_flag_entry {
const char* attr_key;
size_t attr_flags;
};

struct attribute_flag_table_st {
unsigned atflag_size; /* allocated size of atflag_entries */
unsigned atflag_count; /* counting number of used entries */
struct attribute_flag_entry atflag_entries[]; /* flexible array member */
};

static struct attribute_flag_table_st* attribute_flag_hashtable;

static unsigned atflag_hash(const char*atkey)
{
/* NB: most of the decimal integer constants here are prime numbers. */
unsigned kl = (unsigned)strlen(atkey);
unsigned h1 = 17*kl+3;
unsigned h2 = 0;
unsigned h = 0;
for (unsigned i=0; i<kl; i++) {
if (i%2 == 0) {
unsigned nh1 = (h1*31 + i) ^ (atkey[i]*1471 + h2);
unsigned nh2 = h2*11 + (h1&0xfff) - atkey[i]*13;
h1 = nh1;
h2 = nh2;
}
else {
unsigned nh1 = (h1*53 - i) ^ (atkey[i]*1181 + 7*h2);
unsigned nh2 = h2*89 - (h1&0xffff) + atkey[i]*67;
h1 = nh1;
h2 = nh2;
}
};
h = h1 ^ h2;
if (h==0) {
h = h1?h1:11;
}
/* h is never 0 */
return h;
}

static struct attribute_flag_entry*
attr_flag_find(const char*atkey)
{
unsigned h=0, hsiz=0;
if (!atkey || !atkey[0])
return NULL;
if (!attribute_flag_hashtable)
return NULL;
h = atflag_hash(atkey);
hsiz = attribute_flag_hashtable->atflag_size;
for (unsigned ix = h % hsiz; ix < hsiz; ix++)
{
struct attribute_flag_entry*curent
= attribute_flag_hashtable->atflag_entries + ix;
if (!curent->attr_key)
return NULL;
if (!strcmp(curent->attr_key, atkey))
return curent;
};
for (int ix = (int)h % hsiz; ix >= 0; ix--)
{
struct attribute_flag_entry*curent
= attribute_flag_hashtable->atflag_entries + ix;
if (!curent->attr_key)
return NULL;
if (!strcmp(curent->attr_key, atkey))
return curent;
};
return NULL;
}


static struct attribute_flag_entry*
attr_flag_really_put(const char*atkey, size_t atflags)
{
unsigned h = 0, hsiz = 0;
if (!atkey || !atkey[0]) return NULL;
if (!attribute_flag_hashtable)
return NULL;
h = atflag_hash(atkey);
hsiz = attribute_flag_hashtable->atflag_size;
for (unsigned ix = h % hsiz; ix < hsiz; ix++)
{
struct attribute_flag_entry*curent
= attribute_flag_hashtable->atflag_entries + ix;
if (!curent->attr_key) {
curent->attr_key = atkey;
curent->attr_flags = atflags;
attribute_flag_hashtable->atflag_count++;
return curent;
}
if (!strcmp(curent->attr_key, atkey)) {
curent->attr_key = atkey;
curent->attr_flags = atflags;
return curent;
}
};
for (int ix = (int)h % hsiz; ix >= 0; ix--)
{
struct attribute_flag_entry*curent
= attribute_flag_hashtable->atflag_entries + ix;
if (!curent->attr_key) {
curent->attr_key = atkey;
curent->attr_flags = atflags;
attribute_flag_hashtable->atflag_count++;
return curent;
}
if (!strcmp(curent->attr_key, atkey)) {
curent->attr_key = atkey;
curent->attr_flags = atflags;
return curent;
}
};
return NULL;
}

// an array of primes, gotten with something similar to
// /usr/games/primes 3 | awk '($1>p+p/9){print $1, ","; p=$1}'
static const unsigned primes_array[] = {
29, 37, 43, 53, 59, 67, 79, 89, 101, 113,
127, 149, 167, 191, 223, 251, 281, 313, 349, 389, 433, 487, 547, 613,
683, 761, 853, 953, 1061, 1181, 1319, 1471, 1637, 1823, 2027, 2267,
2521, 2803, 3119, 3467, 3853, 4283, 4759, 5297, 5897, 6553, 7283, 8093,
8999, 10007, 11119, 12373, 13751, 15287, 16987, 18899, 21001, 23339,
25933, 28817, 32027, 35591, 39551, 43951, 48847, 54277, 60317, 67021,
74471, 82757, 91957, 102181, 113537, 126173, 140197, 155777, 173087,
192319, 213713, 237467, 263863, 293201, 325781, 361979, 402221, 446921,
496579, 551767, 613097, 681221, 756919, 841063, 934517, 1038383, 1153759,
1281961, 1424407, 1582697, 1758553, 1953949, 2171077, 2412323, 2680367,
2978189, 3309107, 3676789, 4085339, 4539277, 5043653, 5604073, 6226757,
6918619, 7687387, 8541551, 9490631, 10545167, 11716879, 13018757,
14465291, 16072547, 17858389, 19842659, 22047401, 24497113, 27219019,
30243359, 33603743, 37337497, 41486111, 46095719, 51217477, 56908337,
63231499, 70257241, 78063641, 86737379, 96374881, 107083213, 118981367,
132201521, 146890631, 163211821, 181346479, 201496157, 223884629,
248760703, 276400823, 307112027, 341235667, 379150777, 421278643,
468087391, 520097111, 577885681, 642095213, 713439127, 792710159,
880789067, 978654533, 1087393949, 1208215531, 1342461719, 1491624137,
1657360153, 1841511311, 2046123679, 2273470799, 2526078691, 2806754123,
0
};

/* feature request #595 : https://github.com/akheron/jansson/issues/595 */
void
json_register_dump_attribute_flag(const char*attrname, size_t attrflags)
{
unsigned ix;
if (!attrname || !attrname[0])
return;
if (!attribute_flag_hashtable) {
unsigned initsiz = 29;
size_t bytsiz = sizeof(struct attribute_flag_table_st) + initsiz * sizeof(struct attribute_flag_entry);
void *ptr = jsonp_malloc(bytsiz);
if (!ptr)
return;
memset (ptr, 0, bytsiz);
attribute_flag_hashtable = ptr;
attribute_flag_hashtable->atflag_size = initsiz;
}
else if (attribute_flag_hashtable->atflag_size * 4 < attribute_flag_hashtable->atflag_count * 3) {
struct attribute_flag_table_st*oldtable = attribute_flag_hashtable;
unsigned newsiz = 4 * attribute_flag_hashtable->atflag_count / 3 + 17;
unsigned lowix = 0;
unsigned highix = sizeof(primes_array)/sizeof(primes_array[0]) - 1;
size_t bytsiz=0;
unsigned oldsiz=0;
void*ptr = NULL;
while (lowix + 4 < highix) {
unsigned midix = (lowix+highix)/2;
if (primes_array[midix] < lowix)
lowix = midix;
else highix = midix;
};
for (ix = lowix; ix<highix; ix++)
if (primes_array[ix] >= newsiz) {
newsiz = primes_array[ix];
break;
};
ptr = jsonp_malloc(bytsiz);
if (!ptr)
return;
memset (ptr, 0, bytsiz);
attribute_flag_hashtable = ptr;
attribute_flag_hashtable->atflag_size = newsiz;
oldsiz = oldtable->atflag_size;
for (unsigned oldix = 0; oldix < oldsiz; oldix++) {
struct attribute_flag_entry*oldent
= oldtable->atflag_entries + oldix;
if (oldent->attr_key)
attr_flag_really_put(oldent->attr_key, oldent->attr_flags);
};
jsonp_free(oldtable);
};
attr_flag_really_put(attrname, attrflags);
}



static int dump_to_strbuffer(const char *buffer, size_t size, void *data) {
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
}
Expand Down Expand Up @@ -359,12 +561,15 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
for (i = 0; i < size; i++) {
const struct key_len *key;
json_t *value;

struct attribute_flag_entry*atent=NULL;
key = &keys[i];
value = json_object_getn(json, key->key, key->len);
assert(value);

assert(key->key[key->len]==(char)0);
atent= attr_flag_find(key->key);
dump_string(key->key, key->len, dump, data, flags);
if (atent)
flags |= atent->attr_flags;
if (dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, parents, dump, data)) {
jsonp_free(keys);
Expand Down Expand Up @@ -393,8 +598,10 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
void *next = json_object_iter_next((json_t *)json, iter);
const char *key = json_object_iter_key(iter);
const size_t key_len = json_object_iter_key_len(iter);

struct attribute_flag_entry*atent= attr_flag_find(key);
dump_string(key, key_len, dump, data, flags);
if (atent)
flags |= atent->attr_flags;
if (dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
dump, data))
Expand Down
8 changes: 6 additions & 2 deletions src/jansson.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ extern "C" {
/* version */

#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 14
#define JANSSON_MINOR_VERSION 15
#define JANSSON_MICRO_VERSION 0

/* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.14"
#define JANSSON_VERSION "2.15"

/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
Expand Down Expand Up @@ -407,6 +407,10 @@ typedef void (*json_free_t)(void *);
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn);
void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn);


/* feature request #595 : https://github.com/akheron/jansson/issues/595 */
void json_register_dump_attribute_flag(const char*attrname, size_t attrflags);

/* runtime version checking */

const char *jansson_version_str(void);
Expand Down

0 comments on commit 6ff908f

Please sign in to comment.