Browse Source

Changes to the hash table so add works (kinda not-really)

pull/715/head
HexTheDragon 4 years ago
parent
commit
f230b25586
5 changed files with 169 additions and 35 deletions
  1. +34
    -31
      json_object.c
  2. +3
    -0
      json_object_private.h
  3. +48
    -3
      linkhash.c
  4. +71
    -1
      linkhash.h
  5. +13
    -0
      math_compat.h

+ 34
- 31
json_object.c View File

@@ -39,18 +39,6 @@
#error "The long long type isn't 64-bits"
#endif

#ifndef SSIZE_T_MAX
#if SIZEOF_SSIZE_T == SIZEOF_INT
#define SSIZE_T_MAX INT_MAX
#elif SIZEOF_SSIZE_T == SIZEOF_LONG
#define SSIZE_T_MAX LONG_MAX
#elif SIZEOF_SSIZE_T == SIZEOF_LONG_LONG
#define SSIZE_T_MAX LLONG_MAX
#else
#error Unable to determine size of ssize_t
#endif
#endif

// Don't define this. It's not thread-safe.
/* #define REFCOUNT_DEBUG 1 */

@@ -589,38 +577,53 @@ int json_object_object_add_ex(struct json_object *jso, const char *const key,
int json_object_object_add_ex_len(struct json_object *jso, const char *const key, const int len,
struct json_object *const val, const unsigned opts)
{
struct json_object *existing_value = NULL;
struct json_object *existing_value;
struct lh_entry *existing_entry;
unsigned long hash;
/** Required due to the `lh_get_hash` function wanting a `const struct lh_string *` */
const struct lh_string hashable = {.length = len, .str = {.pdata = key}};

assert(json_object_get_type(jso) == json_type_object);

// The caller must avoid creating loops in the object tree, but do a
// quick check anyway to make sure we're not creating a trivial loop.
if (jso == val)
{
return -1;
}

// We lookup the entry and replace the value, rather than just deleting
// and re-adding it, so the existing key remains valid.
hash = lh_get_hash(JC_OBJECT(jso)->c_object, (const void *)key);
hash = lh_get_hash(JC_OBJECT(jso)->c_object, (const void *)&hashable);
existing_entry =
(opts & JSON_C_OBJECT_ADD_KEY_IS_NEW)
? NULL
: lh_table_lookup_entry_w_hash(JC_OBJECT(jso)->c_object, (const void *)key, hash);

// The caller must avoid creating loops in the object tree, but do a
// quick check anyway to make sure we're not creating a trivial loop.
if (jso == val)
return -1;

if (!existing_entry)
if (existing_entry == NULL)
{
const void *const k =
(opts & JSON_C_OBJECT_KEY_IS_CONSTANT) ? (const void *)key : strdup(key);
const struct lh_string *k = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT)
? lh_string_new_ptr(len, key)
: lh_string_new_imm(len, key);
if (k == NULL)
{
return -1;
return lh_table_insert_w_hash(JC_OBJECT(jso)->c_object, k, val, hash, opts);
}
return lh_table_insert_w_hash(JC_OBJECT(jso)->c_object, k, val, hash,
opts & ~JSON_C_OBJECT_KEY_IS_CONSTANT);
// `struct lh_string` always needs to be freed,
// so JSON_C_OBJECT_KEY_IS_CONSTANT cannot be set
}
else
{
existing_value = (json_object *)lh_entry_v(existing_entry);
if (existing_value)
{
json_object_put(existing_value);
}
existing_entry->v = val;
return 0;
}
existing_value = (json_object *)lh_entry_v(existing_entry);
if (existing_value)
json_object_put(existing_value);
existing_entry->v = val;
return 0;
}

int json_object_object_add(struct json_object *jso, const char *key, struct json_object *val)
@@ -761,7 +764,7 @@ struct json_object *json_object_new_int(int32_t i)

int32_t json_object_get_int(const struct json_object *jso)
{
int64_t cint64=0;
int64_t cint64 = 0;
double cdouble;
enum json_type o_type;

@@ -1751,8 +1754,8 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_
/* This handles the `json_type_null` case */
if (!iter.val)
jso = NULL;
else if (json_object_deep_copy_recursive(iter.val, src, iter.key, UINT_MAX, &jso,
shallow_copy) < 0)
else if (json_object_deep_copy_recursive(iter.val, src, iter.key, UINT_MAX,
&jso, shallow_copy) < 0)
{
json_object_put(jso);
return -1;


+ 3
- 0
json_object_private.h View File

@@ -98,6 +98,9 @@ struct json_object_string

void _json_c_set_last_err(const char *err_fmt, ...);

/**
* The characters that can make up hexadecimal numbers
*/
extern const char *json_hex_chars;

#ifdef __cplusplus


+ 48
- 3
linkhash.c View File

@@ -30,6 +30,7 @@
#endif

#include "linkhash.h"
#include "math_compat.h"
#include "random_seed.h"

/* hash functions */
@@ -485,13 +486,57 @@ static unsigned long lh_char_hash(const void *k)
random_seed = seed; /* potentially racy */
#endif
}
return hashlittle((const char *)k, strlen((const char *)k), random_seed);
return hashlittle(lh_string_data((const struct lh_string *)k),
lh_string_size((const struct lh_string *)k), random_seed);
}

int lh_char_equal(const void *k1, const void *k2)
{
return (strcmp((const char *)k1, (const char *)k2) == 0);
return lh_string_size(k1) == lh_string_size(k2) &&
memcmp(lh_string_data(k1), lh_string_data(k2), lh_string_size(k1)) == 0;
}

const char *lh_string_data(const struct lh_string *str)
{
return (str->length > 0) ? str->str.pdata : str->str.idata;
}

size_t lh_string_size(const struct lh_string *str)
{
return (str->length > 0) ? (size_t)str->length : (size_t)(-(str->length));
}

const struct lh_string *lh_string_new_ptr(const size_t length, const char *data)
{
struct lh_string *result = malloc(sizeof(struct lh_string));
if (result == NULL)
{
return NULL;
}
result->length = length;
result->str.pdata = data;
return result;
}

const struct lh_string *lh_string_new_imm(const size_t length, const char *data)
{
struct lh_string *result;
if (length >
SSIZE_T_MAX - (sizeof(struct lh_string) - sizeof(((struct lh_string *)NULL)->str)) - 1)
{
return NULL;
}
result =
malloc(sizeof(struct lh_string) - sizeof(((struct lh_string *)NULL)->str) + length + 1);
if (result == NULL)
{
return NULL;
}
result->length = -length;
char *unconst = _LH_UNCONST(result->str.idata);
memcpy(unconst, data, length);
unconst = '\0';
return result;
}

struct lh_table *lh_table_new(int size, lh_entry_free_fn *free_fn, lh_hash_fn *hash_fn,


+ 71
- 1
linkhash.h View File

@@ -79,6 +79,34 @@ typedef unsigned long(lh_hash_fn)(const void *k);
*/
typedef int(lh_equal_fn)(const void *k1, const void *k2);

/**
* @brief A buffer of characters that may contain null charaters in the middle
*
* A buffer of data that can hold a normal null-terminated string
* (in which case `length` should just be equal to `strlen`)
* or a string with embedded null characters (in which case `length` reflects
* all the characters that make up the "string").
* Either way, this struct can be treated as if it contains null characters,
* since the `length` member should always be equal to the proper size of the
* buffer and the terminating null character wouldn't be included
* (it wouldn't be counted by strlen).
*/
struct lh_string
{
/**
* @brief Stores the length of the buffer
*
* If the length is positive, then `pdata` should be used.
* Otherwise, idata should be used.
*/
ssize_t length;
union
{
const char *pdata;
const char idata[0];
} str;
};

/**
* An entry in the hash table
*/
@@ -137,7 +165,14 @@ struct lh_table
* A pointer onto the function responsible for freeing an entry.
*/
lh_entry_free_fn *free_fn;
/**
* A function that is capable of hashing entries in this table
*/
lh_hash_fn *hash_fn;
/**
* A function that is capable of determining if entries in this table
* are equal
*/
lh_equal_fn *equal_fn;
};
typedef struct lh_table lh_table;
@@ -157,6 +192,41 @@ typedef struct lh_table lh_table;
#define lh_foreach_safe(table, entry, tmp) \
for (entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp)

/**
* @brief Get the data from a `struct lh_string *`
*
* @param str value to retrieve the data from
*/
extern const char *lh_string_data(const struct lh_string *str);

/**
* @brief Get the length of the data stored in a `struct lh_string *`
*
* @param str value to retrieve the length of
*/
extern size_t lh_string_size(const struct lh_string *str);

/**
* @brief Creates a new `struct lh_string` using the `pdata` field.
*
* This avoids unneeded copying, for cases wher ethe key is in an area of
* memory that will not be modified or freed until after this object is freed.
*
* @param length The length of the data located at @p data
* @param data The data to include
* @return `NULL` on error
*/
extern const struct lh_string *lh_string_new_ptr(const size_t length, const char *data);

/**
* @brief Creates a new `struct lh_string` using the `idata` field.
*
* @param length The length of the data to copy into the returned value
* @param data The data to include and copy into the returned value
* @return `NULL` on error
*/
extern const struct lh_string *lh_string_new_imm(const size_t length, const char *data);

/**
* Create a new linkhash table.
*
@@ -311,7 +381,7 @@ int lh_table_resize(struct lh_table *t, int new_size);
/**
* @deprecated Don't use this outside of linkhash.h:
*/
#if (defined(AIX_CC) || (defined(_MSC_VER) && (_MSC_VER <= 1800)) )
#if (defined(AIX_CC) || (defined(_MSC_VER) && (_MSC_VER <= 1800)))
/* VS2010 can't handle inline funcs, so skip it there */
#define _LH_INLINE
#else


+ 13
- 0
math_compat.h View File

@@ -40,4 +40,17 @@
#define HAVE_DECL_NAN
#endif

#include <limits.h>
#ifndef SSIZE_T_MAX
#if SIZEOF_SSIZE_T == SIZEOF_INT
#define SSIZE_T_MAX INT_MAX
#elif SIZEOF_SSIZE_T == SIZEOF_LONG
#define SSIZE_T_MAX LONG_MAX
#elif SIZEOF_SSIZE_T == SIZEOF_LONG_LONG
#define SSIZE_T_MAX LLONG_MAX
#else
#error Unable to determine size of ssize_t
#endif
#endif

#endif

Loading…
Cancel
Save