mirror of
https://github.com/rizinorg/rizin
synced 2026-08-22 20:26:16 -04:00
refactor: SwissTable implementation for ht (#5860)
* Add ht benchmarks * Initial implementation * Finalize native per-group lookup support * Lookup SSE2 implementation * Improve hashing * Add support for custom elem_size * Avoid double h2 hashing when reserving slot * Make custom elem_size support conditional * Fix issues with bitwise and default lookup implementations * Implement deletion trick optimization * Track growth_size instead of deleted_slots * Refactor SDB to access ht via API instead of internals * Modify SDB tests which rely on hashtable order * Fix SDB build warnings * Fix bug with finding next power of two * foreach_kv to return a bool result * Change SDB diff order expected by serialize_analysis unit test * Fix bug in the bitwise lookup implementation * Remove second call to rz_core_init() which causes memory leaks * Update some regression tests to accept reordered output * Adapt ht clear to new implementation * Use fini_kv_pair and fix 1 potential leak on malloc failure * Fix cmd/types test after merge * Avoid second call to calsize_key and avoid iter leaks on malloc failure * Improve hash distribution * Extend benchmark suite * Fix bug with string hashing * Branchless write to mirrored ctrl bytes * Simplify string hash and remove potential UB * Move RZ_PREFETCH macro to rz_types.h * Add SSE2 discovery in Meson * Forward SDB string hash function to ht string hash * Try to revert test_cpu_profiles() to avoid relying on a baked SDB file * Revert SDB/CDB hash function change * Fix SDB reference to HT hash function instead of CDB hash * Change calloc to malloc * Avoid storing/checking key_len and key_value if they are ut64 * Improve string hash function * Rename default hash functions * Improve bench code * linter.yml: set clang-path to point to llvm-18
This commit is contained in:
parent
492addb3a1
commit
95f94ae258
36 changed files with 1617 additions and 554 deletions
4
.github/workflows/linter.yml
vendored
4
.github/workflows/linter.yml
vendored
|
|
@ -89,7 +89,7 @@ jobs:
|
|||
run: |
|
||||
sudo pip install meson ninja
|
||||
sudo apt update
|
||||
sudo apt install libclang-14-dev
|
||||
sudo apt install libclang-18-dev
|
||||
- name: Build rizin
|
||||
working-directory: rizin
|
||||
run: |
|
||||
|
|
@ -98,7 +98,7 @@ jobs:
|
|||
- name: Run rz-bindgen linter
|
||||
run: |
|
||||
python3 rz-bindgen/src/lint.py \
|
||||
--clang-path "/usr/lib/llvm-14/lib" \
|
||||
--clang-path "/usr/lib/llvm-18/lib" \
|
||||
--clang-args "-resource-dir=$(clang -print-resource-dir) " \
|
||||
--rizin-path rizin
|
||||
|
||||
|
|
|
|||
|
|
@ -611,6 +611,18 @@ typedef enum {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define RZ_PREFETCH(addr) __builtin_prefetch((addr), 0, 3)
|
||||
#elif defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
/**
|
||||
* \def Prefetch data from a certain memory address to memory cache
|
||||
*/
|
||||
#define RZ_PREFETCH(addr) _mm_prefetch((const char *)(addr), _MM_HINT_T0)
|
||||
#else
|
||||
#define RZ_PREFETCH(addr) ((void)0)
|
||||
#endif
|
||||
|
||||
static inline void rz_run_call1(void *fcn, void *arg1) {
|
||||
((void (*)(void *))(fcn))(arg1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
#define HAVE___BUILTIN_CTZLL @HAVE___BUILTIN_CTZLL@
|
||||
#define HAVE_POSIX_MEMALIGN @HAVE_POSIX_MEMALIGN@
|
||||
#define HAVE__ALIGNED_MALLOC @HAVE__ALIGNED_MALLOC@
|
||||
#define HAVE_SSE2 @HAVE_SSE2@
|
||||
|
||||
#define HAVE_HEADER_LINUX_ASHMEM_H @HAVE_HEADER_LINUX_ASHMEM_H@
|
||||
#define HAVE_HEADER_SYS_SHM_H @HAVE_HEADER_SYS_SHM_H@
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-FileCopyrightText: 2016-2018 pancake <pancake@nopcode.org>
|
||||
// SPDX-FileCopyrightText: 2016-2018 ret2libc <sirmy15@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2024 pelijah
|
||||
// SPDX-FileCopyrightText: 2026 Anton Angelov <anton.angelov@protonmail.com>
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <rz_util/rz_iterator.h>
|
||||
|
|
@ -17,70 +18,154 @@
|
|||
#undef VALUE_TYPE
|
||||
#undef KEY_TO_HASH
|
||||
#undef HT_NULL_VALUE
|
||||
#undef VARIABLE_KEY_LEN
|
||||
#undef VARIABLE_VALUE_LEN
|
||||
|
||||
#if HT_TYPE == 1
|
||||
// Hash table HtPP that has void* as key and void* as value
|
||||
#define HtName_(name) name##PP
|
||||
#define Ht_(name) ht_pp_##name
|
||||
#define HT_(name) HtPP##name
|
||||
#define KEY_TYPE void *
|
||||
#define VALUE_TYPE void *
|
||||
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
|
||||
#define HT_NULL_VALUE NULL
|
||||
#define HtName_(name) name##PP
|
||||
#define Ht_(name) ht_pp_##name
|
||||
#define HT_(name) HtPP##name
|
||||
#define KEY_TYPE void *
|
||||
#define VALUE_TYPE void *
|
||||
#define KEY_TO_HASH(key, key_size) (ht_default_hash_ut64((uintptr_t)(key)))
|
||||
#define HT_NULL_VALUE NULL
|
||||
#define VARIABLE_KEY_LEN
|
||||
#define VARIABLE_VALUE_LEN
|
||||
#elif HT_TYPE == 2
|
||||
// Hash table HtPU that has void* as key and ut64 as value
|
||||
#define HtName_(name) name##UP
|
||||
#define Ht_(name) ht_up_##name
|
||||
#define HT_(name) HtUP##name
|
||||
#define KEY_TYPE ut64
|
||||
#define VALUE_TYPE void *
|
||||
#define KEY_TO_HASH(x) ((ut32)(x))
|
||||
#define HT_NULL_VALUE 0
|
||||
// Hash table HtUP that has void* as key and ut64 as value
|
||||
#define HtName_(name) name##UP
|
||||
#define Ht_(name) ht_up_##name
|
||||
#define HT_(name) HtUP##name
|
||||
#define KEY_TYPE ut64
|
||||
#define VALUE_TYPE void *
|
||||
#define KEY_TO_HASH(key, key_size) (ht_default_hash_ut64((ut64)(key)))
|
||||
#define HT_NULL_VALUE 0
|
||||
#define VARIABLE_VALUE_LEN
|
||||
#elif HT_TYPE == 3
|
||||
// Hash table HtUU that has ut64 as key and ut64 as value
|
||||
#define HtName_(name) name##UU
|
||||
#define Ht_(name) ht_uu_##name
|
||||
#define HT_(name) HtUU##name
|
||||
#define KEY_TYPE ut64
|
||||
#define VALUE_TYPE ut64
|
||||
#define KEY_TO_HASH(x) ((ut32)(x))
|
||||
#define HT_NULL_VALUE 0
|
||||
#define HtName_(name) name##UU
|
||||
#define Ht_(name) ht_uu_##name
|
||||
#define HT_(name) HtUU##name
|
||||
#define KEY_TYPE ut64
|
||||
#define VALUE_TYPE ut64
|
||||
#define KEY_TO_HASH(key, key_size) (ht_default_hash_ut64((ut64)(key)))
|
||||
#define HT_NULL_VALUE 0
|
||||
#elif HT_TYPE == 4
|
||||
// Hash table HtPU that has void* as key and ut64 as value
|
||||
#define HtName_(name) name##PU
|
||||
#define Ht_(name) ht_pu_##name
|
||||
#define HT_(name) HtPU##name
|
||||
#define KEY_TYPE void *
|
||||
#define VALUE_TYPE ut64
|
||||
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
|
||||
#define HT_NULL_VALUE 0
|
||||
#define HtName_(name) name##PU
|
||||
#define Ht_(name) ht_pu_##name
|
||||
#define HT_(name) HtPU##name
|
||||
#define KEY_TYPE void *
|
||||
#define VALUE_TYPE ut64
|
||||
#define KEY_TO_HASH(key, key_size) (ht_default_hash_ut64((uintptr_t)(key)))
|
||||
#define HT_NULL_VALUE 0
|
||||
#define VARIABLE_KEY_LEN
|
||||
#elif HT_TYPE == 5
|
||||
// Hash table HtSP that has C-string as key and void* as value
|
||||
#define HtName_(name) name##SP
|
||||
#define Ht_(name) ht_sp_##name
|
||||
#define HT_(name) HtSP##name
|
||||
#define KEY_TYPE char *
|
||||
#define VALUE_TYPE void *
|
||||
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
|
||||
#define HT_NULL_VALUE NULL
|
||||
#define HtName_(name) name##SP
|
||||
#define Ht_(name) ht_sp_##name
|
||||
#define HT_(name) HtSP##name
|
||||
#define KEY_TYPE char *
|
||||
#define VALUE_TYPE void *
|
||||
#define KEY_TO_HASH(key, key_size) (ht_default_hash_string(key, key_size))
|
||||
#define HT_NULL_VALUE NULL
|
||||
#define VARIABLE_KEY_LEN
|
||||
#define VARIABLE_VALUE_LEN
|
||||
#elif HT_TYPE == 6
|
||||
// Hash table HtSS that has C-string as key and C-string as value
|
||||
#define HtName_(name) name##SS
|
||||
#define Ht_(name) ht_ss_##name
|
||||
#define HT_(name) HtSS##name
|
||||
#define KEY_TYPE char *
|
||||
#define VALUE_TYPE char *
|
||||
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
|
||||
#define HT_NULL_VALUE NULL
|
||||
#define HtName_(name) name##SS
|
||||
#define Ht_(name) ht_ss_##name
|
||||
#define HT_(name) HtSS##name
|
||||
#define KEY_TYPE char *
|
||||
#define VALUE_TYPE char *
|
||||
#define KEY_TO_HASH(key, key_size) (ht_default_hash_string(key, key_size))
|
||||
#define HT_NULL_VALUE NULL
|
||||
#define VARIABLE_KEY_LEN
|
||||
#define VARIABLE_VALUE_LEN
|
||||
#elif HT_TYPE == 7
|
||||
// Hash table HtSU that has C-string as key and ut64 as value
|
||||
#define HtName_(name) name##SU
|
||||
#define Ht_(name) ht_su_##name
|
||||
#define HT_(name) HtSU##name
|
||||
#define KEY_TYPE char *
|
||||
#define VALUE_TYPE ut64
|
||||
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
|
||||
#define HT_NULL_VALUE 0
|
||||
#define HtName_(name) name##SU
|
||||
#define Ht_(name) ht_su_##name
|
||||
#define HT_(name) HtSU##name
|
||||
#define KEY_TYPE char *
|
||||
#define VALUE_TYPE ut64
|
||||
#define KEY_TO_HASH(key, key_size) (ht_default_hash_string(key, key_size))
|
||||
#define HT_NULL_VALUE 0
|
||||
#define VARIABLE_KEY_LEN
|
||||
#endif
|
||||
|
||||
// Uncomment to enable support for custom element size (opt.elem_size != sizeof(VALUE_TYPE)). This could
|
||||
// slow down lookup/insert/iteration with about 5-10%.
|
||||
// #ifndef HT_ENABLE_CUSTOM_ELEM_SIZE
|
||||
// #define HT_ENABLE_CUSTOM_ELEM_SIZE
|
||||
// #endif
|
||||
|
||||
#ifndef HT_HASH_FUNCTIONS
|
||||
#define HT_HASH_FUNCTIONS
|
||||
|
||||
/**
|
||||
* \brief A Murmur3-like hash function which reduces a 64-bit key to a 32-bit non-cryptographic hash.
|
||||
*
|
||||
* It's simpler than MurmurHash3 which makes it run faster at the cost of slightly worse hash distribution.
|
||||
* This hash function is used for HtPX and HtUX, if no custom hash function is specified.
|
||||
*/
|
||||
static inline ut32 ht_default_hash_ut64(ut64 key) {
|
||||
key ^= key >> 33;
|
||||
key *= 0xff51afd7ed558ccdULL;
|
||||
key ^= key >> 33;
|
||||
return (uint32_t)(key ^ (key >> 32));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Computes 32-bit hash for a byte buffer (string).
|
||||
*
|
||||
* The function uses Murmur3 mixing constants and tries to process the buffer in 16, 8 or 4-byte blocks when possible.
|
||||
* This hash function is used for HtSX, if no custom hash function is specified.
|
||||
*/
|
||||
static inline ut32 ht_default_hash_string(const char *key, ut32 len) {
|
||||
const uint64_t prime1 = 0xff51afd7ed558ccdULL; /* Murmur3 consts */
|
||||
const uint64_t prime2 = 0xc4ceb9fe1a85ec53ULL;
|
||||
ut64 result = 0xff51afd7ed558ccdULL;
|
||||
|
||||
while (len >= 16) {
|
||||
ut64 blocks[2];
|
||||
memcpy(blocks, key, sizeof(ut64) * 2);
|
||||
result += (result << 5) ^ (blocks[0] * prime1);
|
||||
result += (result << 5) ^ (blocks[1] * prime1);
|
||||
len -= 16;
|
||||
key += 16;
|
||||
}
|
||||
|
||||
while (len >= 8) {
|
||||
ut64 block = 0;
|
||||
memcpy(&block, key, sizeof(ut64));
|
||||
result += (result << 5) ^ (block * prime1);
|
||||
len -= 8;
|
||||
key += 8;
|
||||
}
|
||||
|
||||
while (len >= 4) {
|
||||
ut32 block = 0;
|
||||
memcpy(&block, key, sizeof(ut32));
|
||||
result += (result << 5) ^ (block * prime1);
|
||||
len -= 4;
|
||||
key += 4;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
result += (result << 5) ^ (*key * prime1);
|
||||
len -= 1;
|
||||
key += 1;
|
||||
}
|
||||
|
||||
// Finalize
|
||||
result ^= result >> 33;
|
||||
result *= prime2;
|
||||
|
||||
// Fold the result
|
||||
return (ut32)(result ^ (result >> 32));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HT_ENUM_DEFINED
|
||||
|
|
@ -107,12 +192,18 @@ typedef enum {
|
|||
|
||||
#include <rz_types.h>
|
||||
|
||||
/* Kv represents a single key/value element in the hashtable */
|
||||
/**
|
||||
* \brief Kv represents a single key/value element in the hashtable
|
||||
*/
|
||||
typedef struct Ht_(kv) {
|
||||
KEY_TYPE key;
|
||||
VALUE_TYPE value;
|
||||
ut32 key_len;
|
||||
ut32 value_len;
|
||||
#ifdef VARIABLE_KEY_LEN
|
||||
ut32 key_len; ///< Size of the key. Used only for pointer or string keys.
|
||||
#endif
|
||||
#ifdef VARIABLE_VALUE_LEN
|
||||
ut32 value_len; ///< Size of the value. Used only for pointer or string values.
|
||||
#endif
|
||||
} HT_(Kv);
|
||||
|
||||
typedef void (*HT_(FiniKv))(HT_(Kv) *kv, void *user);
|
||||
|
|
@ -124,50 +215,48 @@ typedef ut32 (*HT_(CalcSizeV))(const VALUE_TYPE);
|
|||
typedef ut32 (*HT_(HashFunction))(const KEY_TYPE);
|
||||
typedef int (*HT_(Comparator))(const KEY_TYPE, const KEY_TYPE);
|
||||
typedef bool (*HT_(ForeachCallback))(void *user, const KEY_TYPE, const VALUE_TYPE);
|
||||
|
||||
typedef struct Ht_(bucket_t) {
|
||||
HT_(Kv) *arr;
|
||||
ut32 count;
|
||||
} HT_(Bucket);
|
||||
typedef bool (*HT_(ForeachKvCallback))(void *user, const HT_(Kv) *kv);
|
||||
|
||||
/**
|
||||
* Options contain all the settings of the hashtable.
|
||||
*/
|
||||
typedef struct Ht_(options_t) {
|
||||
size_t elem_size; ///< Size of each HtKv element (useful for subclassing like SdbKv).
|
||||
///< Zero value means to use default size of HtKv.
|
||||
HT_(Comparator) cmp; ///< RZ_NULLABLE. Function for comparing keys.
|
||||
///< Returns 0 if keys are equal.
|
||||
///< Function is invoked only if == operator applied to keys returns false.
|
||||
HT_(HashFunction) hashfn; ///< RZ_NULLABLE. Function for hashing items in the hash table.
|
||||
///< If NULL KEY_TO_HASH macro is used.
|
||||
HT_(DupKey) dupkey; ///< RZ_NULLABLE. Function for making a copy of key.
|
||||
///< If NULL simple assignment operator is used.
|
||||
HT_(DupValue) dupvalue; ///< RZ_NULLABLE. Function for making a copy of value.
|
||||
///< If NULL simple assignment operator is used.
|
||||
HT_(CalcSizeK) calcsizeK; ///< RZ_NULLABLE. Function to determine the key's size.
|
||||
///< If NULL zero value is used as a size.
|
||||
///< Key sizes are checked on equality during keys comparsion as a pre-check.
|
||||
HT_(CalcSizeV) calcsizeV; ///< RZ_NULLABLE. Function to determine the value's size.
|
||||
///< If NULL zero value is used as a size.
|
||||
///< Not required for common scenarios. Could be used in subclasses.
|
||||
HT_(DupKey) dupkey; ///< RZ_NULLABLE. Function for making a copy of key.
|
||||
///< If NULL simple assignment operator is used.
|
||||
HT_(DupValue) dupvalue; ///< RZ_NULLABLE. Function for making a copy of value.
|
||||
///< If NULL simple assignment operator is used.
|
||||
HT_(FiniKv) finiKV; ///< RZ_NULLABLE. Function to clean up the key-value store.
|
||||
void *finiKV_user; ///< RZ_NULLABLE. User data which is passed into finiKV.
|
||||
size_t elem_size; ///< Size of each HtKv element (useful for subclassing like SdbKv).
|
||||
///< Zero value means to use default size of HtKv.
|
||||
} HT_(Options);
|
||||
|
||||
/* Ht is the hashtable structure */
|
||||
typedef struct Ht_(t) {
|
||||
ut32 size; ///< Size of the hash table in buckets.
|
||||
ut32 count; ///< Number of stored elements.
|
||||
HT_(Bucket) *table; ///< Actual table.
|
||||
ut32 prime_idx;
|
||||
HT_(Options) opt;
|
||||
ut32 capacity; ///< Capacity of the main array.
|
||||
ut32 capacity_mask; ///< Set to `capacity - 1` and used for bucket/index modulo.
|
||||
ut32 size; ///< Number of stored elements.
|
||||
ut32 growth_left; ///< Number of empty slots.
|
||||
RZ_BORROW ut8 *ctrl; ///< Control bytes (metadata) - point to the beginning of the `data` pointer.
|
||||
RZ_BORROW HT_(Kv) *slots; ///< Main array (no buckets) - points to an offset after the `data` pointer.
|
||||
HT_(Options) opt; ///< Methods
|
||||
ut8 *data; ///< Single allocation for `ctrl` and `slots` arrays.
|
||||
} HtName_(Ht);
|
||||
|
||||
typedef struct Ht_(iter_mut_t) {
|
||||
HtName_(Ht) *ht; ///< The hash table to iterate over.
|
||||
ut32 ti; ///< Table index
|
||||
ut32 bi; ///< Bucket index
|
||||
HT_(Kv) *kv; ///< Current Key-Value-pair.
|
||||
} HT_(IterMutState);
|
||||
|
||||
|
|
@ -202,6 +291,7 @@ RZ_API VALUE_TYPE Ht_(find)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, RZ_N
|
|||
// cb should not modify the hashtable.
|
||||
// NOTE: cb can delete the current element, but it should be avoided
|
||||
RZ_API void Ht_(foreach)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(ForeachCallback) cb, RZ_NULLABLE void *user);
|
||||
RZ_API bool Ht_(foreach_kv)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(ForeachKvCallback) cb, RZ_NULLABLE void *user);
|
||||
|
||||
RZ_API ut32 Ht_(size)(const RZ_NONNULL HtName_(Ht) *ht);
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -33,7 +33,7 @@ static void fini_kv_val(HT_(Kv) *kv, void *user) {
|
|||
RZ_API RZ_OWN HtName_(Ht) *Ht_(new)(HtStrOption key_opt, RZ_NULLABLE HT_(DupValue) dup_val, RZ_NULLABLE HT_(FreeValue) free_val) {
|
||||
HT_(Options) opt = {
|
||||
.cmp = (HT_(Comparator))strcmp,
|
||||
.hashfn = (HT_(HashFunction))sdb_hash,
|
||||
.hashfn = NULL,
|
||||
.dupkey = key_opt == HT_STR_DUP ? (HT_(DupKey))rz_str_dup : NULL,
|
||||
.dupvalue = dup_val,
|
||||
.calcsizeK = (HT_(CalcSizeK))strlen,
|
||||
|
|
@ -42,5 +42,5 @@ RZ_API RZ_OWN HtName_(Ht) *Ht_(new)(HtStrOption key_opt, RZ_NULLABLE HT_(DupValu
|
|||
.finiKV_user = (void *)free_val,
|
||||
.elem_size = 0,
|
||||
};
|
||||
return internal_ht_new(ht_primes_sizes[0], 0, &opt);
|
||||
return internal_ht_new(0, &opt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ static void fini_kv_val(HT_(Kv) *kv, void *user) {
|
|||
RZ_API RZ_OWN HtName_(Ht) *Ht_(new)(HtStrOption key_opt, HtStrOption val_opt) {
|
||||
HT_(Options) opt = {
|
||||
.cmp = (HT_(Comparator))strcmp,
|
||||
.hashfn = (HT_(HashFunction))sdb_hash,
|
||||
.hashfn = NULL,
|
||||
.dupkey = key_opt == HT_STR_DUP ? (HT_(DupKey))rz_str_dup : NULL,
|
||||
.dupvalue = val_opt == HT_STR_DUP ? (HT_(DupValue))rz_str_dup : NULL,
|
||||
.calcsizeK = (HT_(CalcSizeK))strlen,
|
||||
|
|
@ -41,5 +41,5 @@ RZ_API RZ_OWN HtName_(Ht) *Ht_(new)(HtStrOption key_opt, HtStrOption val_opt) {
|
|||
.finiKV_user = val_opt == HT_STR_CONST ? NULL : (HT_(FreeValue))free,
|
||||
.elem_size = 0,
|
||||
};
|
||||
return internal_ht_new(ht_primes_sizes[0], 0, &opt);
|
||||
return internal_ht_new(0, &opt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ static void fini_kv_key(HT_(Kv) *kv, RZ_UNUSED void *user) {
|
|||
RZ_API RZ_OWN HtName_(Ht) *Ht_(new)(HtStrOption key_opt) {
|
||||
HT_(Options) opt = {
|
||||
.cmp = (HT_(Comparator))strcmp,
|
||||
.hashfn = (HT_(HashFunction))sdb_hash,
|
||||
.hashfn = NULL,
|
||||
.dupkey = key_opt == HT_STR_DUP ? (HT_(DupKey))rz_str_dup : NULL,
|
||||
.dupvalue = NULL,
|
||||
.calcsizeK = (HT_(CalcSizeK))strlen,
|
||||
|
|
@ -29,5 +29,5 @@ RZ_API RZ_OWN HtName_(Ht) *Ht_(new)(HtStrOption key_opt) {
|
|||
.finiKV_user = NULL,
|
||||
.elem_size = 0,
|
||||
};
|
||||
return internal_ht_new(ht_primes_sizes[0], 0, &opt);
|
||||
return internal_ht_new(0, &opt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ static void init_options(HT_(Options) *opt, HT_(DupValue) valdup, HT_(FreeValue)
|
|||
RZ_API RZ_OWN HtName_(Ht) *Ht_(new)(RZ_NULLABLE HT_(DupValue) valdup, RZ_NULLABLE HT_(FreeValue) valfree) {
|
||||
HT_(Options) opt;
|
||||
init_options(&opt, valdup, valfree);
|
||||
return internal_ht_new(ht_primes_sizes[0], 0, &opt);
|
||||
return internal_ht_new(0, &opt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,19 +12,6 @@
|
|||
#include "sdb.h"
|
||||
#include "sdb_private.h"
|
||||
|
||||
static inline SdbKv *next_kv(HtSS *ht, SdbKv *kv) {
|
||||
return (SdbKv *)((char *)kv + ht->opt.elem_size);
|
||||
}
|
||||
|
||||
#define BUCKET_FOREACH(ht, bt, j, kv) \
|
||||
for ((j) = 0, (kv) = (SdbKv *)(bt)->arr; j < (bt)->count; (j)++, (kv) = next_kv(ht, kv))
|
||||
|
||||
#define BUCKET_FOREACH_SAFE(ht, bt, j, count, kv) \
|
||||
if ((bt)->arr) \
|
||||
for ((j) = 0, (kv) = (SdbKv *)(bt)->arr, (count) = (ht)->count; \
|
||||
(j) < (bt)->count; \
|
||||
(j) = (count) == (ht)->count ? j + 1 : j, (kv) = (count) == (ht)->count ? next_kv(ht, kv) : kv, (count) = (ht)->count)
|
||||
|
||||
// TODO: use mmap instead of read.. much faster!
|
||||
RZ_API RZ_OWN Sdb *sdb_new0(void) {
|
||||
return sdb_new(NULL, NULL, 0);
|
||||
|
|
@ -146,7 +133,7 @@ RZ_API bool sdb_isempty(Sdb *s) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (s->ht && s->ht->count > 0) {
|
||||
if (s->ht && ht_ss_size(s->ht) > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -164,7 +151,7 @@ RZ_API int sdb_count(Sdb *s) {
|
|||
}
|
||||
}
|
||||
if (s->ht) {
|
||||
count += s->ht->count;
|
||||
count += ht_ss_size(s->ht);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
|
@ -241,7 +228,7 @@ RZ_API const char *sdb_const_get_len(Sdb *s, const char *key, int *vlen) {
|
|||
return NULL;
|
||||
}
|
||||
(void)cdb_findstart(&s->db);
|
||||
if (cdb_findnext(&s->db, s->ht->opt.hashfn(key), key, keylen) < 1) {
|
||||
if (cdb_findnext(&s->db, sdb_hash(key), key, keylen) < 1) {
|
||||
return NULL;
|
||||
}
|
||||
len = cdb_datalen(&s->db);
|
||||
|
|
@ -752,19 +739,8 @@ RZ_API bool sdb_foreach(RZ_NONNULL Sdb *s, RZ_NONNULL SdbForeachCallback cb, RZ_
|
|||
if (!result) {
|
||||
return sdb_foreach_end(s, false);
|
||||
}
|
||||
|
||||
for (ut32 i = 0; i < s->ht->size; ++i) {
|
||||
HtSSBucket *bt = &s->ht->table[i];
|
||||
SdbKv *kv;
|
||||
ut32 j, count;
|
||||
|
||||
BUCKET_FOREACH_SAFE(s->ht, bt, j, count, kv) {
|
||||
if (kv && sdbkv_value(kv) && *sdbkv_value(kv)) {
|
||||
if (!cb(user, kv)) {
|
||||
return sdb_foreach_end(s, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sdb_ht_foreach_kv(s->ht, cb, user)) {
|
||||
return sdb_foreach_end(s, false);
|
||||
}
|
||||
return sdb_foreach_end(s, true);
|
||||
}
|
||||
|
|
@ -778,9 +754,18 @@ static bool _insert_into_disk(void *user, const SdbKv *kv) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool sdb_sync_foreach_cb(void *user, const SdbKv *kv) {
|
||||
Sdb *s = user;
|
||||
|
||||
if (sdb_disk_insert(s, sdbkv_key(kv), sdbkv_value(kv))) {
|
||||
sdb_remove(s, sdbkv_key(kv));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_API bool sdb_sync(Sdb *s) {
|
||||
bool result;
|
||||
ut32 i;
|
||||
|
||||
if (!s || !sdb_disk_create(s)) {
|
||||
return false;
|
||||
|
|
@ -789,21 +774,7 @@ RZ_API bool sdb_sync(Sdb *s) {
|
|||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* append new keyvalues */
|
||||
for (i = 0; i < s->ht->size; ++i) {
|
||||
HtSSBucket *bt = &s->ht->table[i];
|
||||
SdbKv *kv;
|
||||
ut32 j, count;
|
||||
|
||||
BUCKET_FOREACH_SAFE(s->ht, bt, j, count, kv) {
|
||||
if (sdbkv_key(kv) && sdbkv_value(kv) && *sdbkv_value(kv)) {
|
||||
if (sdb_disk_insert(s, sdbkv_key(kv), sdbkv_value(kv))) {
|
||||
sdb_remove(s, sdbkv_key(kv));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sdb_ht_foreach_kv(s->ht, sdb_sync_foreach_cb, s);
|
||||
sdb_disk_finish(s);
|
||||
// TODO: sdb_reset memory state?
|
||||
return true;
|
||||
|
|
@ -842,7 +813,7 @@ RZ_API bool sdb_stats(Sdb *s, ut32 *disk, ut32 *mem) {
|
|||
*disk = count;
|
||||
}
|
||||
if (mem) {
|
||||
*mem = s->ht->count;
|
||||
*mem = ht_ss_size(s->ht);
|
||||
}
|
||||
return disk || mem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ RZ_API void sdb_copy(Sdb *src, Sdb *dst);
|
|||
|
||||
RZ_API bool sdb_stats(Sdb *s, ut32 *disk, ut32 *mem);
|
||||
|
||||
typedef bool (*SdbForeachCallback)(void *user, const SdbKv *kv);
|
||||
typedef SdbHtForeachCallback SdbForeachCallback;
|
||||
RZ_API bool sdb_foreach(RZ_NONNULL Sdb *s, RZ_NONNULL SdbForeachCallback cb, RZ_NULLABLE void *user);
|
||||
RZ_API RZ_OWN RzPVector /*<SdbKv *>*/ *sdb_get_items(RZ_NONNULL Sdb *s, bool sorted);
|
||||
RZ_API RZ_OWN RzPVector /*<SdbKv *>*/ *sdb_get_items_filter(RZ_NONNULL Sdb *s, RZ_NONNULL SdbForeachCallback filter, RZ_NULLABLE void *user, bool sorted);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,14 @@
|
|||
|
||||
#include "sdbht.h"
|
||||
|
||||
/**
|
||||
* \brief A helper struct used for forwarding iteration (foreach) callbacks between `ht_` and the `sdb_` APIs.
|
||||
*/
|
||||
typedef struct {
|
||||
SdbHtForeachCallback cb;
|
||||
void *user;
|
||||
} HtSSForeachKvCallbackRedirect;
|
||||
|
||||
RZ_API HtSS *sdb_ht_new(void) {
|
||||
HtSS *ht = ht_ss_new(HT_STR_DUP, HT_STR_DUP);
|
||||
if (ht) {
|
||||
|
|
@ -61,3 +69,28 @@ RZ_API void sdb_ht_free(HtSS *ht) {
|
|||
RZ_API bool sdb_ht_delete(HtSS *ht, const char *key) {
|
||||
return ht_ss_delete(ht, key);
|
||||
}
|
||||
|
||||
static bool sdb_ht_foreach_kv_filter(void *user, const HtSSKv *kv) {
|
||||
SdbKv *sdb_kv = (SdbKv *)kv;
|
||||
if (sdbkv_key(sdb_kv) && sdbkv_value(sdb_kv) && *sdbkv_value(sdb_kv)) {
|
||||
HtSSForeachKvCallbackRedirect *redirect = user;
|
||||
return redirect->cb(redirect->user, (SdbKv *)kv);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Iterates all elements of a `HtSS` hash table.
|
||||
*
|
||||
* \param ht The hash table.
|
||||
* \param cb A callback to be invoked for each element.
|
||||
* \param user Pointer to user data to be passed to the callback for each element.
|
||||
* \return true if all elements were iterated, false if the iteration was cancelled by the user callback
|
||||
*/
|
||||
RZ_API bool sdb_ht_foreach_kv(RZ_NONNULL HtSS *ht, RZ_NONNULL SdbHtForeachCallback cb, RZ_NULLABLE void *user) {
|
||||
HtSSForeachKvCallbackRedirect redirect = {
|
||||
.cb = cb,
|
||||
.user = user
|
||||
};
|
||||
return ht_ss_foreach_kv(ht, sdb_ht_foreach_kv_filter, &redirect);
|
||||
}
|
||||
|
|
@ -16,6 +16,8 @@ typedef struct sdb_kv {
|
|||
HtSSKv base;
|
||||
} SdbKv;
|
||||
|
||||
typedef bool (*SdbHtForeachCallback)(void *user, const SdbKv *kv);
|
||||
|
||||
static inline const char *sdbkv_key(const SdbKv *kv) {
|
||||
return kv->base.key;
|
||||
}
|
||||
|
|
@ -54,6 +56,8 @@ RZ_API bool sdb_ht_delete(HtSS *ht, const char *key);
|
|||
RZ_API char *sdb_ht_find(HtSS *ht, const char *key, bool *found);
|
||||
// Find the KeyValuePair corresponding to the matching key.
|
||||
RZ_API SdbKv *sdb_ht_find_kvp(HtSS *ht, const char *key, bool *found);
|
||||
// Iterate the hash table.
|
||||
RZ_API bool sdb_ht_foreach_kv(RZ_NONNULL HtSS *ht, RZ_NONNULL SdbHtForeachCallback cb, RZ_NULLABLE void *user);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -519,6 +519,13 @@ foreach it : ccs
|
|||
it_userconf.set10('HAVE_@0@'.format(func.to_upper()), ok)
|
||||
endforeach
|
||||
|
||||
# Try to compile a basic SSE2 code snippet to discover if SSE2 is supported for the target arch
|
||||
sse2_code = '''#include <emmintrin.h>
|
||||
int main (int argc, char *argv[]) { __m128i v = _mm_set_epi32(2, 3, 0, 1); return 0; }
|
||||
'''
|
||||
has_sse2 = it_cc.compiles(sse2_code, args : '-msse2', name: 'SSE2 code snippet')
|
||||
it_userconf.set10('HAVE_SSE2', has_sse2)
|
||||
|
||||
foreach item : [
|
||||
['linux/ashmem.h', '', []],
|
||||
['sys/shm.h', '', []],
|
||||
|
|
|
|||
443
test/bench/bench_ht.c
Normal file
443
test/bench/bench_ht.c
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
// SPDX-FileCopyrightText: 2026 Anton Angelov <anton.angelov@protonmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include "bench_utils.h"
|
||||
#include <rz_util/ht_pu.h>
|
||||
#include <rz_util/ht_su.h>
|
||||
#include <rz_util/ht_uu.h>
|
||||
|
||||
/**
|
||||
* \file bench_ht.c
|
||||
* \brief Benchmark for hash table functions (`ht_*`)
|
||||
*/
|
||||
|
||||
#define ITERATION_COUNT 2000000
|
||||
#define SHUFFLE_MULTIPLIER 1037
|
||||
|
||||
static bool ht_pu_foreach_cb(RZ_UNUSED ut64 *i, RZ_UNUSED const void *key, RZ_UNUSED const ut64 value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for generating a pseudo-random value based on iteration number (for randomizing HtUU keys)
|
||||
*/
|
||||
static inline ut64 splitmix64(ut64 v) {
|
||||
uint64_t z = (v + 0x9E3779B97F4A7C15ULL);
|
||||
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL;
|
||||
z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL;
|
||||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sample object to be used as a key for a HtPU hash table
|
||||
*/
|
||||
typedef struct {
|
||||
ut32 a;
|
||||
ut32 b;
|
||||
} PUKey;
|
||||
|
||||
static inline PUKey make_pu_key(ut64 iteration) {
|
||||
PUKey result;
|
||||
result.a = iteration * 1000;
|
||||
result.b = splitmix64(iteration);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reshuffles a key in order to do the following (in a deterministic way):
|
||||
* - avoid sequential key insert/lookup
|
||||
* - create 87.5% chance of lookup hit vs 12.5% chance of miss
|
||||
* - make 10% of the elements (hot zone) to be requested 75.5% of the time
|
||||
*/
|
||||
static ut64 reshuffle_key(ut64 index, ut64 max_value, ut64 unexistent_key) {
|
||||
const ut64 hot_zone_denom = 10; // 10% of the hash table elements are considered in the hot zone
|
||||
ut64 hot_zone_size = max_value / hot_zone_denom;
|
||||
|
||||
switch (index % 8) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
// 75.5% hot zone (6/8)
|
||||
return (index * SHUFFLE_MULTIPLIER) % hot_zone_size * hot_zone_denom;
|
||||
case 6:
|
||||
// 12.5% cold zone (1/8)
|
||||
return (index * SHUFFLE_MULTIPLIER) % max_value;
|
||||
case 7:
|
||||
// 12.5% miss rate (1/8)
|
||||
return unexistent_key;
|
||||
default:
|
||||
rz_warn_if_reached();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static ut32 pu_key_hash(void *p) {
|
||||
PUKey *key = p;
|
||||
return key->a ^ key->b;
|
||||
}
|
||||
|
||||
static int pu_key_cmp(void *p1, void *p2) {
|
||||
PUKey *key1 = p1;
|
||||
PUKey *key2 = p2;
|
||||
|
||||
if (key1->a < key2->a) {
|
||||
return -1;
|
||||
}
|
||||
if (key1->a > key2->a) {
|
||||
return 1;
|
||||
}
|
||||
if (key1->b < key2->b) {
|
||||
return -1;
|
||||
}
|
||||
if (key1->b > key2->b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bench_rz_ht_pu_combined(RzTable *t_out) {
|
||||
ut64 temp = 0;
|
||||
HtPUOptions pu_opt = { 0 };
|
||||
pu_opt.hashfn = (HtPUHashFunction)pu_key_hash;
|
||||
pu_opt.cmp = (HtPUComparator)pu_key_cmp;
|
||||
PUKey *keys = malloc(sizeof(PUKey) * ITERATION_COUNT);
|
||||
|
||||
// Generate keys
|
||||
for (ut64 i = 0; i < ITERATION_COUNT; i++) {
|
||||
keys[i] = make_pu_key(i);
|
||||
}
|
||||
|
||||
// Insert
|
||||
{
|
||||
HtPU *ht = ht_pu_new_opt(&pu_opt);
|
||||
RZ_BENCH_RUN_I("[HtPU] insert", i, t_out, ITERATION_COUNT, {
|
||||
ht_pu_insert(ht, &keys[i], i);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtPU] delete", i, t_out, ITERATION_COUNT, {
|
||||
ht_pu_delete(ht, &keys[i]);
|
||||
});
|
||||
ht_pu_free(ht);
|
||||
}
|
||||
|
||||
// Lookup (small, medium, large hash tables) and iterate
|
||||
{
|
||||
HtPU *ht_100 = ht_pu_new_opt(&pu_opt);
|
||||
HtPU *ht_1k = ht_pu_new_opt(&pu_opt);
|
||||
HtPU *ht_10k = ht_pu_new_opt(&pu_opt);
|
||||
HtPU *ht_100k = ht_pu_new_opt(&pu_opt);
|
||||
HtPU *ht_1m = ht_pu_new_opt(&pu_opt);
|
||||
|
||||
for (ut64 i = 0; i < 1000000; i++) {
|
||||
PUKey *key = &keys[i];
|
||||
if (i < 100) {
|
||||
ht_pu_insert(ht_100, key, i);
|
||||
}
|
||||
if (i < 1000) {
|
||||
ht_pu_insert(ht_1k, key, i);
|
||||
}
|
||||
if (i < 10000) {
|
||||
ht_pu_insert(ht_10k, key, i);
|
||||
}
|
||||
if (i < 100000) {
|
||||
ht_pu_insert(ht_100k, key, i);
|
||||
}
|
||||
ht_pu_insert(ht_1m, key, i);
|
||||
}
|
||||
|
||||
RZ_BENCH_RUN("[HtPU] iterate (100 elements)", t_out, ITERATION_COUNT, {
|
||||
ht_pu_foreach(ht_100, (HtPUForeachCallback)ht_pu_foreach_cb, &temp);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtPU] lookup (100 elements)", i, t_out, ITERATION_COUNT, {
|
||||
PUKey temp_key = make_pu_key(reshuffle_key(i, 100, UT64_MAX));
|
||||
ut64 result = ht_pu_find(ht_100, &temp_key, NULL);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtPU] lookup (1k elements)", i, t_out, ITERATION_COUNT, {
|
||||
PUKey temp_key = make_pu_key(reshuffle_key(i, 1000, UT64_MAX));
|
||||
ut64 result = ht_pu_find(ht_1k, &temp_key, NULL);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtPU] lookup (10k elements)", i, t_out, ITERATION_COUNT, {
|
||||
PUKey temp_key = make_pu_key(reshuffle_key(i, 10000, UT64_MAX));
|
||||
ut64 result = ht_pu_find(ht_10k, &temp_key, NULL);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtPU] lookup (100k elements)", i, t_out, ITERATION_COUNT, {
|
||||
PUKey temp_key = make_pu_key(reshuffle_key(i, 100000, UT64_MAX));
|
||||
ut64 result = ht_pu_find(ht_100k, &temp_key, NULL);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtPU] lookup (1M elements)", i, t_out, ITERATION_COUNT, {
|
||||
PUKey temp_key = make_pu_key(reshuffle_key(i, 1000000, UT64_MAX));
|
||||
ut64 result = ht_pu_find(ht_1m, &temp_key, NULL);
|
||||
});
|
||||
|
||||
ht_pu_free(ht_100);
|
||||
ht_pu_free(ht_1k);
|
||||
ht_pu_free(ht_10k);
|
||||
ht_pu_free(ht_100k);
|
||||
ht_pu_free(ht_1m);
|
||||
}
|
||||
|
||||
free(keys);
|
||||
}
|
||||
|
||||
static char *generate_su_key(ut64 index) {
|
||||
char buffer[UT8_MAX];
|
||||
|
||||
// Try to mimic real world string keys
|
||||
switch (index % 8) {
|
||||
case 0:
|
||||
snprintf(buffer, UT8_MAX, "user_%" PRIx64, index); // user id
|
||||
break;
|
||||
case 1:
|
||||
snprintf(buffer, UT8_MAX, "session_%" PRIx64 "%" PRIx64, index, index * 7919); // session token
|
||||
break;
|
||||
case 2: {
|
||||
const char *sections[] = { "analysis", "asm", "scr", "graph", "str" };
|
||||
const char *keys[] = { "flags", "prefix", "editor", "times", "server" };
|
||||
snprintf(buffer, UT8_MAX, "config.%s.%s", sections[index % 5], keys[(index / 5) % 5]); // config keys
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
const char *headers[] = { "content-type", "content-length", "authorization", "user-agent", "accept", "accept-encoding",
|
||||
"cache-control", "connection", "host", "cookie", "referer", "accept-language",
|
||||
"x-forwarded-for", "x-request-id", "etag" };
|
||||
snprintf(buffer, UT8_MAX, "%s-%" PRIx64, headers[index % 15], index / 15); // http header
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
const char *dirs[] = { "/home/user/documents", "/var/log", "/etc/config", "/usr/local/bin", "/tmp/cache" };
|
||||
snprintf(buffer, UT8_MAX, "%s/file %" PRIx64 ".txt", dirs[index % 5], index);
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
const char *domains[] = { "example.com", "test.org", "mail.net", "company.io" };
|
||||
snprintf(buffer, UT8_MAX, "user%" PRIx64 "@%s", index, domains[index % 4]); // email
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
snprintf(buffer, UT8_MAX, "%08" PRIx64 "-%04" PRIx64 "-%04" PRIx64 "-%04" PRIx64 "-%012" PRIx64,
|
||||
index,
|
||||
(index >> 16) & 0xFFFF,
|
||||
(index >> 8) & 0xFFFF,
|
||||
(index >> 4) & 0xFFFF,
|
||||
(index * 2654435761u)); // GUID
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
// alphanumeric code with length of 2 to 64 characters
|
||||
const char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
int len = 2 + (index % 62);
|
||||
|
||||
for (ut64 i = 0; i < len && i < UT8_MAX - 1; i++) {
|
||||
buffer[i] = chars[(index + i * 7) % 36];
|
||||
}
|
||||
buffer[len] = '\0';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rz_warn_if_reached();
|
||||
}
|
||||
|
||||
return strdup(buffer);
|
||||
}
|
||||
|
||||
static bool ht_su_foreach_cb(RZ_UNUSED ut64 *i, RZ_UNUSED const char *key, RZ_UNUSED const ut64 value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bench_rz_ht_su_combined(RzTable *t_out) {
|
||||
char **precomputed_keys = malloc((ITERATION_COUNT + 1) * sizeof(char *));
|
||||
|
||||
// Generate test keys
|
||||
for (ut64 i = 0; i < ITERATION_COUNT; i++) {
|
||||
precomputed_keys[i] = generate_su_key(i);
|
||||
}
|
||||
precomputed_keys[ITERATION_COUNT] = "non-existent";
|
||||
|
||||
// Insert
|
||||
{
|
||||
HtSU *ht = ht_su_new(HT_STR_CONST);
|
||||
RZ_BENCH_RUN_I("[HtSU] insert", i, t_out, ITERATION_COUNT, {
|
||||
ht_su_insert(ht, precomputed_keys[i], i);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtSU] delete", i, t_out, ITERATION_COUNT, {
|
||||
ht_su_delete(ht, precomputed_keys[i]);
|
||||
});
|
||||
ht_su_free(ht);
|
||||
}
|
||||
|
||||
// Lookup (small, medium, large hash tables) and iterate
|
||||
{
|
||||
HtSU *ht_100 = ht_su_new(HT_STR_CONST);
|
||||
HtSU *ht_1k = ht_su_new(HT_STR_CONST);
|
||||
HtSU *ht_10k = ht_su_new(HT_STR_CONST);
|
||||
HtSU *ht_100k = ht_su_new(HT_STR_CONST);
|
||||
HtSU *ht_1m = ht_su_new(HT_STR_CONST);
|
||||
|
||||
for (ut64 i = 0; i < 1000000; i++) {
|
||||
if (i < 100) {
|
||||
ht_su_insert(ht_100, precomputed_keys[i], i);
|
||||
}
|
||||
if (i < 1000) {
|
||||
ht_su_insert(ht_1k, precomputed_keys[i], i);
|
||||
}
|
||||
if (i < 10000) {
|
||||
ht_su_insert(ht_10k, precomputed_keys[i], i);
|
||||
}
|
||||
if (i < 100000) {
|
||||
ht_su_insert(ht_100k, precomputed_keys[i], i);
|
||||
}
|
||||
ht_su_insert(ht_1m, precomputed_keys[i], i);
|
||||
}
|
||||
|
||||
RZ_BENCH_RUN("[HtSU] iterate (100 elements)", t_out, ITERATION_COUNT, {
|
||||
ht_su_foreach(ht_100, (HtSUForeachCallback)ht_su_foreach_cb, NULL);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtSU] lookup (100 elements)", i, t_out, ITERATION_COUNT, {
|
||||
const char *key = precomputed_keys[reshuffle_key(i, 100, ITERATION_COUNT)];
|
||||
ut64 result = ht_su_find(ht_100, key, NULL);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtSU] lookup (1k elements)", i, t_out, ITERATION_COUNT, {
|
||||
const char *key = precomputed_keys[reshuffle_key(i, 1000, ITERATION_COUNT)];
|
||||
ut64 result = ht_su_find(ht_1k, key, NULL);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtSU] lookup (10k elements)", i, t_out, ITERATION_COUNT, {
|
||||
const char *key = precomputed_keys[reshuffle_key(i, 10000, ITERATION_COUNT)];
|
||||
ut64 result = ht_su_find(ht_10k, key, NULL);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtSU] lookup (100k elements)", i, t_out, ITERATION_COUNT, {
|
||||
const char *key = precomputed_keys[reshuffle_key(i, 100000, ITERATION_COUNT)];
|
||||
ut64 result = ht_su_find(ht_100k, key, NULL);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtSU] lookup (1M elements)", i, t_out, ITERATION_COUNT, {
|
||||
const char *key = precomputed_keys[reshuffle_key(i, 1000000, ITERATION_COUNT)];
|
||||
ut64 result = ht_su_find(ht_1m, key, NULL);
|
||||
});
|
||||
|
||||
ht_su_free(ht_100);
|
||||
ht_su_free(ht_1k);
|
||||
ht_su_free(ht_10k);
|
||||
ht_su_free(ht_100k);
|
||||
ht_su_free(ht_1m);
|
||||
}
|
||||
|
||||
// Free precomputed keys
|
||||
for (ut64 i = 0; i < ITERATION_COUNT; i++) {
|
||||
free(precomputed_keys[i]);
|
||||
}
|
||||
free(precomputed_keys);
|
||||
}
|
||||
|
||||
static bool ht_uu_foreach_cb(RZ_UNUSED ut64 *i, RZ_UNUSED const ut64 key, RZ_UNUSED const ut64 value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bench_rz_ht_uu_combined(RzTable *t_out) {
|
||||
HtUU *ht = NULL;
|
||||
|
||||
// Insert
|
||||
{
|
||||
ht = ht_uu_new();
|
||||
RZ_BENCH_RUN_I("[HtUU] insert", i, t_out, ITERATION_COUNT, {
|
||||
ht_uu_insert(ht, splitmix64(i), i);
|
||||
});
|
||||
RZ_BENCH_RUN_I("[HtUU] delete", i, t_out, ITERATION_COUNT, {
|
||||
ht_uu_delete(ht, splitmix64(i)); // reshuffle keys
|
||||
});
|
||||
ht_uu_free(ht);
|
||||
}
|
||||
|
||||
// Lookup 100 elements (and iterate)
|
||||
{
|
||||
const ut64 size = 100;
|
||||
ht = ht_uu_new();
|
||||
for (ut64 i = 0; i < size; i++) {
|
||||
ht_uu_insert(ht, splitmix64(i), i);
|
||||
}
|
||||
|
||||
RZ_BENCH_RUN("[HtUU] iterate (100 elements)", t_out, ITERATION_COUNT, {
|
||||
ht_uu_foreach(ht, (HtUUForeachCallback)ht_uu_foreach_cb, NULL);
|
||||
});
|
||||
|
||||
RZ_BENCH_RUN_I("[HtUU] lookup (100 elements)", i, t_out, ITERATION_COUNT, {
|
||||
ht_uu_find(ht, splitmix64(reshuffle_key(i, size, size)), NULL);
|
||||
});
|
||||
|
||||
ht_uu_free(ht);
|
||||
}
|
||||
|
||||
// Lookup 1k
|
||||
{
|
||||
const ut64 size = 1000;
|
||||
ht = ht_uu_new();
|
||||
for (ut64 i = 0; i < size; i++) {
|
||||
ht_uu_insert(ht, splitmix64(i), i);
|
||||
}
|
||||
|
||||
RZ_BENCH_RUN_I("[HtUU] lookup (1k elements)", i, t_out, ITERATION_COUNT, {
|
||||
ht_uu_find(ht, splitmix64(reshuffle_key(i, size, size)), NULL);
|
||||
});
|
||||
|
||||
ht_uu_free(ht);
|
||||
}
|
||||
|
||||
// Lookup 10k
|
||||
{
|
||||
const ut64 size = 10000;
|
||||
ht = ht_uu_new();
|
||||
for (ut64 i = 0; i < size; i++) {
|
||||
ht_uu_insert(ht, splitmix64(i), i);
|
||||
}
|
||||
|
||||
RZ_BENCH_RUN_I("[HtUU] lookup (10k elements)", i, t_out, ITERATION_COUNT, {
|
||||
ht_uu_find(ht, splitmix64(reshuffle_key(i, size, size)), NULL);
|
||||
});
|
||||
|
||||
ht_uu_free(ht);
|
||||
}
|
||||
|
||||
// Lookup 100k
|
||||
{
|
||||
const ut64 size = 100000;
|
||||
ht = ht_uu_new();
|
||||
for (ut64 i = 0; i < size; i++) {
|
||||
ht_uu_insert(ht, splitmix64(i), i);
|
||||
}
|
||||
|
||||
RZ_BENCH_RUN_I("[HtUU] lookup (100k elements)", i, t_out, ITERATION_COUNT, {
|
||||
ht_uu_find(ht, splitmix64(reshuffle_key(i, size, size)), NULL);
|
||||
});
|
||||
|
||||
ht_uu_free(ht);
|
||||
}
|
||||
|
||||
// Lookup large
|
||||
{
|
||||
const ut64 size = 1000000;
|
||||
ht = ht_uu_new();
|
||||
for (ut64 i = 0; i < size; i++) {
|
||||
ht_uu_insert(ht, splitmix64(i), i);
|
||||
}
|
||||
|
||||
RZ_BENCH_RUN_I("[HtUU] lookup (1M elements)", i, t_out, ITERATION_COUNT, {
|
||||
ht_uu_find(ht, splitmix64(reshuffle_key(i, size, size)), NULL);
|
||||
});
|
||||
|
||||
ht_uu_free(ht);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
RzTable *t = rz_table_new();
|
||||
RZ_BENCH_TABLE_INIT(t);
|
||||
|
||||
// Micro benchmarks
|
||||
bench_rz_ht_pu_combined(t);
|
||||
bench_rz_ht_su_combined(t);
|
||||
bench_rz_ht_uu_combined(t);
|
||||
|
||||
// Print results
|
||||
RZ_BENCH_TABLE_PRINT_AND_FREE(t);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -44,6 +44,18 @@ RZ_API void rz_bench_report(RZ_NONNULL RzBenchCtx *ctx, RZ_NONNULL RzTable *t);
|
|||
rz_bench_report(&ctx, table); \
|
||||
} while (0)
|
||||
|
||||
#define RZ_BENCH_RUN_I(name, i, table, iterations, code) \
|
||||
do { \
|
||||
RzBenchCtx ctx; \
|
||||
rz_bench_init(&ctx, name, iterations); \
|
||||
rz_bench_start(&ctx); \
|
||||
for (ut64(i) = 0; (i) < iterations; (i)++) { \
|
||||
code; \
|
||||
} \
|
||||
rz_bench_end(&ctx); \
|
||||
rz_bench_report(&ctx, table); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \brief Initializes the RzTable \p T used for storing results of microbenchmarks.
|
||||
* \param T table to initialize.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ if get_option('enable_benchmarks')
|
|||
benchmarks = [
|
||||
'bitvector',
|
||||
'il',
|
||||
'ht'
|
||||
]
|
||||
|
||||
# Create benchmark executables
|
||||
|
|
|
|||
|
|
@ -4240,10 +4240,10 @@ arg int64_t arg2 @ rsi
|
|||
void fcn.00010270(int64_t arg1, int64_t arg2, const char **s, int64_t arg4, int64_t arg5);
|
||||
var const char *s2 @ stack - 0xc8
|
||||
var void *s1 @ stack - 0xc0
|
||||
var unsigned long long var_b8h @ stack - 0xb8
|
||||
var unsigned long var_b8h @ stack - 0xb8
|
||||
var int64_t var_b0h @ stack - 0xb0
|
||||
var int64_t var_a8h @ stack - 0xa8
|
||||
var unsigned long long var_98h @ stack - 0x98
|
||||
var unsigned long var_98h @ stack - 0x98
|
||||
var int64_t var_94h @ stack - 0x94
|
||||
var int64_t var_90h @ stack - 0x90
|
||||
var int64_t var_88h @ stack - 0x88
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ EXPECT=<<EOF
|
|||
| ; var char **arg1 @ rdi
|
||||
| ; var const char *arg2 @ rsi
|
||||
| ; var int64_t arg7 @ xmm0
|
||||
| ; var unsigned long long arg3 @ rdx
|
||||
| ; var unsigned long arg3 @ rdx
|
||||
| ; var some_t *arg4 @ rcx
|
||||
| ; arg int a @ stack - 0x10
|
||||
| ; arg char *g @ stack - 0x18
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ aaa
|
|||
aclj
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
[{"name":"B","bases":[{"id":"0","name":"A","offset":0}],"vtables":[{"id":"0","addr":4197640,"offset":0}],"methods":[{"name":"B","addr":4197198,"type":"CONSTRUCTOR"},{"name":"printValue","addr":4197250,"type":"VIRTUAL","vtable_offset":8},{"name":"method.A.greet","addr":4197064,"type":"VIRTUAL","vtable_offset":0}]},{"name":"std::basic_ostream_char__std::char_traits_char____std","bases":[],"vtables":[],"methods":[{"name":"operator<<<std::char_traits<char>>","addr":4196496,"type":"DEFAULT"},{"name":"endl<char, std::char_traits<char>>","addr":4196528,"type":"DEFAULT"}]},{"name":"std::ios_base::Init","bases":[],"vtables":[],"methods":[{"name":"Init","addr":4196432,"type":"DEFAULT"},{"name":"~Init","addr":4196480,"type":"DEFAULT"}]},{"name":"std","bases":[],"vtables":[],"methods":[]},{"name":"std::ostream","bases":[],"vtables":[],"methods":[{"name":"operator<<","addr":4196400,"type":"DEFAULT"},{"name":"operator<<","addr":4196512,"type":"DEFAULT"}]},{"name":"A","bases":[],"vtables":[{"id":"0","addr":4197672,"offset":0}],"methods":[{"name":"greet","addr":4197064,"type":"VIRTUAL","vtable_offset":0},{"name":"printValue","addr":4197108,"type":"VIRTUAL","vtable_offset":8},{"name":"A","addr":4197174,"type":"CONSTRUCTOR"}]},{"name":"C","bases":[{"id":"0","name":"A","offset":0}],"vtables":[{"id":"0","addr":4197608,"offset":0}],"methods":[{"name":"C","addr":4197316,"type":"CONSTRUCTOR"},{"name":"printValue","addr":4197368,"type":"VIRTUAL","vtable_offset":8},{"name":"method.A.greet","addr":4197064,"type":"VIRTUAL","vtable_offset":0}]}]
|
||||
[{"name":"std::ios_base::Init","bases":[],"vtables":[],"methods":[{"name":"Init","addr":4196432,"type":"DEFAULT"},{"name":"~Init","addr":4196480,"type":"DEFAULT"}]},{"name":"std::ostream","bases":[],"vtables":[],"methods":[{"name":"operator<<","addr":4196400,"type":"DEFAULT"},{"name":"operator<<","addr":4196512,"type":"DEFAULT"}]},{"name":"std","bases":[],"vtables":[],"methods":[]},{"name":"C","bases":[{"id":"0","name":"A","offset":0}],"vtables":[{"id":"0","addr":4197608,"offset":0}],"methods":[{"name":"C","addr":4197316,"type":"CONSTRUCTOR"},{"name":"printValue","addr":4197368,"type":"VIRTUAL","vtable_offset":8},{"name":"method.A.greet","addr":4197064,"type":"VIRTUAL","vtable_offset":0}]},{"name":"std::basic_ostream_char__std::char_traits_char____std","bases":[],"vtables":[],"methods":[{"name":"operator<<<std::char_traits<char>>","addr":4196496,"type":"DEFAULT"},{"name":"endl<char, std::char_traits<char>>","addr":4196528,"type":"DEFAULT"}]},{"name":"A","bases":[],"vtables":[{"id":"0","addr":4197672,"offset":0}],"methods":[{"name":"greet","addr":4197064,"type":"VIRTUAL","vtable_offset":0},{"name":"printValue","addr":4197108,"type":"VIRTUAL","vtable_offset":8},{"name":"A","addr":4197174,"type":"CONSTRUCTOR"}]},{"name":"B","bases":[{"id":"0","name":"A","offset":0}],"vtables":[{"id":"0","addr":4197640,"offset":0}],"methods":[{"name":"B","addr":4197198,"type":"CONSTRUCTOR"},{"name":"printValue","addr":4197250,"type":"VIRTUAL","vtable_offset":8},{"name":"method.A.greet","addr":4197064,"type":"VIRTUAL","vtable_offset":0}]}]
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
@ -568,7 +568,7 @@ aaa
|
|||
aclj
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
[{"name":"InAbsentia","bases":[{"id":"0","name":"Album","offset":0}],"vtables":[{"id":"0","addr":4268452,"offset":0}],"methods":[{"name":"virtual_0","addr":4198536,"type":"VIRTUAL","vtable_offset":0},{"name":"virtual_4","addr":4198579,"type":"VIRTUAL","vtable_offset":4}]},{"name":"type_info","bases":[],"vtables":[{"id":"0","addr":4268540,"offset":0}],"methods":[{"name":"virtual_0","addr":4198710,"type":"VIRTUAL","vtable_offset":0}]},{"name":"Album","bases":[],"vtables":[{"id":"0","addr":4268388,"offset":0}],"methods":[{"name":"virtual_0","addr":4198493,"type":"VIRTUAL","vtable_offset":0},{"name":"virtual_4","addr":4198567,"type":"VIRTUAL","vtable_offset":4}]}]
|
||||
[{"name":"Album","bases":[],"vtables":[{"id":"0","addr":4268388,"offset":0}],"methods":[{"name":"virtual_0","addr":4198493,"type":"VIRTUAL","vtable_offset":0},{"name":"virtual_4","addr":4198567,"type":"VIRTUAL","vtable_offset":4}]},{"name":"InAbsentia","bases":[{"id":"0","name":"Album","offset":0}],"vtables":[{"id":"0","addr":4268452,"offset":0}],"methods":[{"name":"virtual_0","addr":4198536,"type":"VIRTUAL","vtable_offset":0},{"name":"virtual_4","addr":4198579,"type":"VIRTUAL","vtable_offset":4}]},{"name":"type_info","bases":[],"vtables":[{"id":"0","addr":4268540,"offset":0}],"methods":[{"name":"virtual_0","addr":4198710,"type":"VIRTUAL","vtable_offset":0}]}]
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ EXPECT=<<EOF
|
|||
| | 0x00400bef mov rdx, qword [rax]
|
||||
| | 0x00400bf2 mov rax, qword [var_20h.var_20h]
|
||||
| | 0x00400bf6 mov rdi, rax
|
||||
| | 0x00400bf9 call rdx ; Virtual Call : method.Dog.run / method.Cat.run / method.Human.run
|
||||
| | 0x00400bf9 call rdx ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|
||||
| ,==< 0x00400bfb jmp 0x400c8c
|
||||
| |`-> 0x00400c00 mov ecx, dword [var_24h]
|
||||
| | 0x00400c03 movsxd rax, ecx
|
||||
|
|
@ -212,7 +212,7 @@ EXPECT=<<EOF
|
|||
| || 0x00400c4e mov rdx, qword [rax]
|
||||
| || 0x00400c51 mov rax, qword [var_20h.var_20h]
|
||||
| || 0x00400c55 mov rdi, rax
|
||||
| || 0x00400c58 call rdx ; Virtual Call : method.Dog.run / method.Cat.run / method.Human.run
|
||||
| || 0x00400c58 call rdx ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|
||||
| ,===< 0x00400c5a jmp 0x400c8c
|
||||
| ||`-> 0x00400c5c mov edi, 0x08
|
||||
| || 0x00400c61 call sym.imp.operator_new_unsigned_long
|
||||
|
|
@ -226,7 +226,7 @@ EXPECT=<<EOF
|
|||
| || 0x00400c80 mov rdx, qword [rax]
|
||||
| || 0x00400c83 mov rax, qword [var_20h.var_20h]
|
||||
| || 0x00400c87 mov rdi, rax
|
||||
| || 0x00400c8a call rdx ; Virtual Call : method.Dog.run / method.Cat.run / method.Human.run
|
||||
| || 0x00400c8a call rdx ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|
||||
| || ; CODE XREFS from main @ 0x400bfb, 0x400c5a
|
||||
| ``--> 0x00400c8c mov rax, qword [var_20h.var_20h]
|
||||
| 0x00400c90 mov rax, qword [rax]
|
||||
|
|
@ -234,7 +234,7 @@ EXPECT=<<EOF
|
|||
| 0x00400c97 mov rdx, qword [rax]
|
||||
| 0x00400c9a mov rax, qword [var_20h.var_20h]
|
||||
| 0x00400c9e mov rdi, rax
|
||||
| 0x00400ca1 call rdx ; Virtual Call : method.Dog.walk / method.Cat.walk / method.Human.walk
|
||||
| 0x00400ca1 call rdx ; Virtual Call : method.Dog.walk / method.Human.walk / method.Cat.walk
|
||||
| 0x00400ca3 mov rax, qword [var_20h.var_20h]
|
||||
| 0x00400ca7 test rax, rax
|
||||
| ,=< 0x00400caa jz 0x400cbb
|
||||
|
|
@ -242,7 +242,7 @@ EXPECT=<<EOF
|
|||
| | 0x00400caf add rdx, 0x08
|
||||
| | 0x00400cb3 mov rdx, qword [rdx]
|
||||
| | 0x00400cb6 mov rdi, rax
|
||||
| | 0x00400cb9 call rdx ; Virtual Call : sym.Human::_Human_0x401090 / sym.Dog::_Dog_0x400f9a / sym.Cat::_Cat_0x400ea4
|
||||
| | 0x00400cb9 call rdx ; Virtual Call : sym.Cat::_Cat_0x400ea4 / sym.Human::_Human_0x401090 / sym.Dog::_Dog_0x400f9a
|
||||
| `-> 0x00400cbb mov eax, 0x00
|
||||
| ,=< 0x00400cc0 jmp 0x400d13
|
||||
..
|
||||
|
|
@ -481,7 +481,7 @@ EXPECT=<<EOF
|
|||
| | 0x100002890 ldur x0, [var_20h.var_20h]
|
||||
| | 0x100002894 ldr x8, [x0]
|
||||
| | 0x100002898 ldr x8, [x8, 0x10] ; [0x10:4]=-1 ; 16
|
||||
| | 0x10000289c blr x8 ; Virtual Call : method.Dog.run / method.Cat.run / method.Human.run
|
||||
| | 0x10000289c blr x8 ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|
||||
| ,==< 0x1000028a0 b 0x100002980
|
||||
..
|
||||
| ||`-> 0x1000028c0 ldur w8, [var_24h]
|
||||
|
|
@ -505,7 +505,7 @@ EXPECT=<<EOF
|
|||
| ||| 0x100002900 ldur x0, [var_20h.var_20h]
|
||||
| ||| 0x100002904 ldr x8, [x0]
|
||||
| ||| 0x100002908 ldr x8, [x8, 0x10] ; [0x10:4]=-1 ; 16
|
||||
| ||| 0x10000290c blr x8 ; Virtual Call : method.Dog.run / method.Cat.run / method.Human.run
|
||||
| ||| 0x10000290c blr x8 ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|
||||
| ,====< 0x100002910 b 0x10000297c
|
||||
..
|
||||
| ||||`-> 0x100002930 mov x0, 8
|
||||
|
|
@ -519,7 +519,7 @@ EXPECT=<<EOF
|
|||
| |||| 0x10000294c ldur x0, [var_20h.var_20h]
|
||||
| |||| 0x100002950 ldr x8, [x0]
|
||||
| |||| 0x100002954 ldr x8, [x8, 0x10] ; [0x10:4]=-1 ; 16
|
||||
| |||| 0x100002958 blr x8 ; Virtual Call : method.Dog.run / method.Cat.run / method.Human.run
|
||||
| |||| 0x100002958 blr x8 ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|
||||
| ||||,=< 0x10000295c b 0x10000297c
|
||||
..
|
||||
| |||||| ; CODE XREFS from entry0 @ 0x100002910, 0x10000295c
|
||||
|
|
@ -528,7 +528,7 @@ EXPECT=<<EOF
|
|||
| `----`--> 0x100002980 ldur x0, [var_20h.var_20h]
|
||||
| || | 0x100002984 ldr x8, [x0]
|
||||
| || | 0x100002988 ldr x8, [x8, 0x18] ; [0x18:4]=-1 ; 24
|
||||
| || | 0x10000298c blr x8 ; Virtual Call : method.Dog.walk / method.Cat.walk / method.Human.walk
|
||||
| || | 0x10000298c blr x8 ; Virtual Call : method.Dog.walk / method.Human.walk / method.Cat.walk
|
||||
| || | 0x100002990 ldur x8, [var_20h.var_20h]
|
||||
| || | 0x100002994 str x8, [var_58h]
|
||||
| || | 0x100002998 subs x8, x8, 0
|
||||
|
|
@ -716,7 +716,7 @@ EXPECT=<<EOF
|
|||
| `--> 0x100002cd4 ldr x0, [sp]
|
||||
| | 0x100002cd8 ldr x8, [x0]
|
||||
| | 0x100002cdc ldr x8, [x8, 8] ; [0x8:4]=-1 ; 8
|
||||
| | 0x100002ce0 blr x8 ; Virtual Call : sym.Dog::_Dog_0x100002fbc / sym.non_virtual_thunk_to_Dog::_Dog_0x100003068
|
||||
| | 0x100002ce0 blr x8 ; Virtual Call : sym.non_virtual_thunk_to_Dog::_Dog_0x100003068 / sym.Dog::_Dog_0x100002fbc
|
||||
| ,==< 0x100002ce4 b 0x100002ce8
|
||||
| || ; CODE XREF from entry0 @ 0x100002ce4
|
||||
| ``-> 0x100002ce8 ldur w0, [var_14h]
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ avx method.Dog.run
|
|||
EOF
|
||||
EXPECT=<<EOF
|
||||
Virtual xrefs to method.Dog.run
|
||||
C 0x100002958 blr x8
|
||||
C 0x10000289c blr x8
|
||||
C 0x100002958 blr x8
|
||||
C 0x10000290c blr x8
|
||||
EOF
|
||||
RUN
|
||||
|
|
@ -37,8 +37,8 @@ EOF
|
|||
EXPECT=<<EOF
|
||||
from
|
||||
------------
|
||||
0x100002958
|
||||
0x10000289c
|
||||
0x100002958
|
||||
0x10000290c
|
||||
EOF
|
||||
RUN
|
||||
|
|
@ -53,12 +53,12 @@ avxt method_Employee_sayHello
|
|||
EOF
|
||||
EXPECT=<<EOF
|
||||
Virtual xrefs to method_Employee_sayHello
|
||||
C 0x100001914 call qword [reloc.objc_msgSend]
|
||||
C 0x100001937 call qword [reloc.objc_msgSend]
|
||||
C 0x100001914 call qword [reloc.objc_msgSend]
|
||||
from
|
||||
------------
|
||||
0x100001914
|
||||
0x100001937
|
||||
0x100001914
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ axtl @ sym.mf_write
|
|||
EOF
|
||||
EXPECT=<<EOF
|
||||
;------------------------------------------
|
||||
void sym.mf_release(unsigned long long arg1, int64_t arg2, int64_t arg_28h, int64_t arg_20h, int64_t arg_30h, int64_t arg_498h, int64_t arg_38h, int64_t arg_48h, int64_t arg_40h, int64_t arg_10h);
|
||||
void sym.mf_release(unsigned long arg1, int64_t arg2, int64_t arg_28h, int64_t arg_20h, int64_t arg_30h, int64_t arg_498h, int64_t arg_38h, int64_t arg_48h, int64_t arg_40h, int64_t arg_10h);
|
||||
; Xref from: sym.mf_release @ 0x00219836
|
||||
| : 0x00219830 mov rsi, rbx ; int64_t arg2
|
||||
| : 0x00219833 mov rdi, rbp ; int64_t arg1
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ e asm.os=linux
|
|||
gl
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
shc exec : execute cmd=/bin/sh suid=false
|
||||
enc xor : xor encoder for shellcode
|
||||
shc exec : execute cmd=/bin/sh suid=false
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
|
|
@ -541,41 +541,41 @@ ftll
|
|||
ftn bla
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
fs
|
||||
env
|
||||
string
|
||||
network
|
||||
dylib
|
||||
threads
|
||||
alloc
|
||||
time
|
||||
process
|
||||
fs
|
||||
stdout
|
||||
["fs":[],"env":[],"string":[],"network":[],"dylib":[],"threads":[],"alloc":[],"time":[],"process":[],"stdout":[]]
|
||||
string
|
||||
process
|
||||
alloc
|
||||
network
|
||||
env
|
||||
threads
|
||||
dylib
|
||||
["time":[],"fs":[],"stdout":[],"string":[],"process":[],"alloc":[],"network":[],"env":[],"threads":[],"dylib":[]]
|
||||
time:
|
||||
fs:
|
||||
env:
|
||||
stdout:
|
||||
string:
|
||||
process:
|
||||
alloc:
|
||||
network:
|
||||
dylib:
|
||||
env:
|
||||
threads:
|
||||
alloc:
|
||||
time:
|
||||
process:
|
||||
stdout:
|
||||
bla
|
||||
fs:
|
||||
dylib:
|
||||
process:
|
||||
stdout:
|
||||
network:
|
||||
alloc:
|
||||
env:
|
||||
string:
|
||||
bla
|
||||
time:
|
||||
fs:
|
||||
stdout:
|
||||
string:
|
||||
process:
|
||||
alloc:
|
||||
network:
|
||||
env:
|
||||
bla:
|
||||
0x00400410 foo
|
||||
0x00400506 goo
|
||||
threads:
|
||||
dylib:
|
||||
0x00400410 foo
|
||||
0x00400506 goo
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -264,11 +264,11 @@ age title3 title1
|
|||
agg *
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
agn "title3" base64:dGhpcyBpcyBteSBib2R5CndpdGggbmV3bGluZXM=
|
||||
agn "title2" base64:Ym9keTI=
|
||||
agn "title1" base64:Ym9keTE=
|
||||
age "title3" "title1"
|
||||
agn "title2" base64:Ym9keTI=
|
||||
agn "title3" base64:dGhpcyBpcyBteSBib2R5CndpdGggbmV3bGluZXM=
|
||||
age "title1" "title2"
|
||||
age "title3" "title1"
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
|
|
@ -64,15 +64,15 @@ Lct
|
|||
Lcq
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
java: Suite of java commands, type `java` for more info (Made by deroad, v1.0, LGPL-3.0-only)
|
||||
dex: Suite of dex commands, type `dex` for more info (Made by deroad, v1.0, LGPL-3.0-only)
|
||||
[{"name":"java","description":"Suite of java commands, type `java` for more info","author":"deroad","version":"1.0","license":"LGPL-3.0-only"},{"name":"dex","description":"Suite of dex commands, type `dex` for more info","author":"deroad","version":"1.0","license":"LGPL-3.0-only"}]
|
||||
java: Suite of java commands, type `java` for more info (Made by deroad, v1.0, LGPL-3.0-only)
|
||||
[{"name":"dex","description":"Suite of dex commands, type `dex` for more info","author":"deroad","version":"1.0","license":"LGPL-3.0-only"},{"name":"java","description":"Suite of java commands, type `java` for more info","author":"deroad","version":"1.0","license":"LGPL-3.0-only"}]
|
||||
name license author version description
|
||||
------------------------------------------------------------------------------------
|
||||
java LGPL-3.0-only deroad 1.0 Suite of java commands, type `java` for more info
|
||||
dex LGPL-3.0-only deroad 1.0 Suite of dex commands, type `dex` for more info
|
||||
java
|
||||
java LGPL-3.0-only deroad 1.0 Suite of java commands, type `java` for more info
|
||||
dex
|
||||
java
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
|
|
@ -1621,8 +1621,8 @@ ar bp=0x98
|
|||
afvd var_70h
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
var unsigned long long var_80h @ stack - 0x80
|
||||
var unsigned long long var_71h @ stack - 0x71
|
||||
var unsigned long var_80h @ stack - 0x80
|
||||
var unsigned long var_71h @ stack - 0x71
|
||||
var int64_t var_70h @ stack - 0x70
|
||||
var char *var_60h @ stack - 0x60
|
||||
var int64_t var_58h @ stack - 0x58
|
||||
|
|
@ -1635,8 +1635,8 @@ var int64_t var_40h @ stack - 0x40
|
|||
arg int64_t arg_5h @ stack + 0x5
|
||||
arg int argc @ rdi
|
||||
arg char **argv @ rsi
|
||||
var unsigned long long var_80h @ stack - 0x80
|
||||
var unsigned long long var_71h @ stack - 0x71
|
||||
var unsigned long var_80h @ stack - 0x80
|
||||
var unsigned long var_71h @ stack - 0x71
|
||||
var char [20] var_70h @ stack - 0x70
|
||||
var int64_t var_58h @ stack - 0x58
|
||||
var int64_t var_56h @ stack - 0x56
|
||||
|
|
@ -1796,10 +1796,10 @@ s sym.funcarg
|
|||
pd 1
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
sym.funcarg(const char *arg1, unsigned long long arg2);
|
||||
sym.funcarg(const char *arg1, unsigned long arg2);
|
||||
; arg const char *arg1 @ rdi
|
||||
; arg unsigned long long arg2 @ rsi
|
||||
; var unsigned long long var_14h @ stack - 0x14
|
||||
; arg unsigned long arg2 @ rsi
|
||||
; var unsigned long var_14h @ stack - 0x14
|
||||
; var const char *var_10h @ stack - 0x10
|
||||
0x0000068a 55 push rbp
|
||||
EOF
|
||||
|
|
@ -1817,10 +1817,10 @@ s sym.funcarg
|
|||
pd 1
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
sym.funcarg(const char *arg_4h, size_t arg_8h);
|
||||
sym.funcarg(const char *arg_4h, unsigned long arg_8h);
|
||||
; var int32_t var_8h @ stack - 0x8
|
||||
; arg const char *arg_4h @ stack + 0x4
|
||||
; arg size_t arg_8h @ stack + 0x8
|
||||
; arg unsigned long arg_8h @ stack + 0x8
|
||||
0x0000054d 55 push ebp
|
||||
EOF
|
||||
RUN
|
||||
|
|
@ -1887,7 +1887,7 @@ EOF
|
|||
EXPECT=<<EOF
|
||||
var int var_3ch @ stack - 0x3c
|
||||
var int64_t var_38h @ stack - 0x38
|
||||
var unsigned long long var_30h @ stack - 0x30
|
||||
var unsigned long var_30h @ stack - 0x30
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
@ -1901,7 +1901,7 @@ afvl
|
|||
EOF
|
||||
EXPECT=<<EOF
|
||||
var void *va_args @ stack - 0x3c
|
||||
var unsigned long long var_34h @ stack - 0x34
|
||||
var unsigned long var_34h @ stack - 0x34
|
||||
var FILE *stream @ stack - 0x30
|
||||
var const char *s @ stack - 0x28
|
||||
var const char *var_20h @ stack - 0x20
|
||||
|
|
@ -1940,9 +1940,9 @@ var int *wstatus @ stack - 0x14d4
|
|||
var int64_t var_14cch @ stack - 0x14cc
|
||||
var int64_t var_14c8h @ stack - 0x14c8
|
||||
var int64_t var_14c4h @ stack - 0x14c4
|
||||
var unsigned long long pid @ stack - 0x14c0
|
||||
var unsigned long long var_14bch @ stack - 0x14bc
|
||||
var unsigned long long var_14b8h @ stack - 0x14b8
|
||||
var unsigned long pid @ stack - 0x14c0
|
||||
var unsigned long var_14bch @ stack - 0x14bc
|
||||
var unsigned long var_14b8h @ stack - 0x14b8
|
||||
var int64_t var_14b4h @ stack - 0x14b4
|
||||
var const char *var_14b0h @ stack - 0x14b0
|
||||
var const char *s @ stack - 0x14a8
|
||||
|
|
@ -1958,9 +1958,9 @@ var int64_t var_20h @ stack - 0x20
|
|||
arg int argc @ rdi
|
||||
arg char **argv @ rsi
|
||||
var char *str @ stack - 0xb8
|
||||
var long long signed int var_ach @ stack - 0xac
|
||||
var int_fast64_t var_ach @ stack - 0xac
|
||||
var int64_t var_a8h @ stack - 0xa8
|
||||
var unsigned long long var_a4h @ stack - 0xa4
|
||||
var unsigned long var_a4h @ stack - 0xa4
|
||||
var int var_a0h @ stack - 0xa0
|
||||
var int var_9ch @ stack - 0x9c
|
||||
var int var_98h @ stack - 0x98
|
||||
|
|
@ -1979,14 +1979,14 @@ var char *var_68h @ stack - 0x68
|
|||
var char *var_60h @ stack - 0x60
|
||||
var char *var_58h @ stack - 0x58
|
||||
var char *var_50h @ stack - 0x50
|
||||
var unsigned long long var_48h @ stack - 0x48
|
||||
var unsigned long var_48h @ stack - 0x48
|
||||
var const char *s1 @ stack - 0x40
|
||||
var const char *s @ stack - 0x38
|
||||
var const char *var_30h @ stack - 0x30
|
||||
var const char *var_28h @ stack - 0x28
|
||||
var int64_t var_20h @ stack - 0x20
|
||||
var int64_t var_10h @ stack - 0x10
|
||||
arg long long signed int arg1 @ rdi
|
||||
arg int_fast64_t arg1 @ rdi
|
||||
arg char *arg2 @ rsi
|
||||
EOF
|
||||
RUN
|
||||
|
|
@ -2245,18 +2245,18 @@ tn-*
|
|||
tn
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
ExitThread
|
||||
FreeLibraryAndExitThread
|
||||
RaiseException
|
||||
RtlRaiseException
|
||||
ExitProcess
|
||||
FatalExit
|
||||
ExitProcess
|
||||
ExitThread
|
||||
RtlRaiseException
|
||||
RaiseException
|
||||
---
|
||||
FreeLibraryAndExitThread
|
||||
ExitProcess
|
||||
ExitThread
|
||||
RtlRaiseException
|
||||
FreeLibraryAndExitThread
|
||||
RaiseException
|
||||
RtlRaiseException
|
||||
ExitProcess
|
||||
---
|
||||
EOF
|
||||
RUN
|
||||
|
|
@ -2323,13 +2323,13 @@ EOF
|
|||
EXPECT=<<EOF
|
||||
int64_t
|
||||
const char *
|
||||
unsigned long long
|
||||
unsigned long
|
||||
int
|
||||
char **
|
||||
=
|
||||
int64_t
|
||||
const char *
|
||||
unsigned long long
|
||||
unsigned long
|
||||
const void *
|
||||
size_t
|
||||
mbstate_t *
|
||||
|
|
@ -8283,9 +8283,9 @@ tn
|
|||
tnj
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
fun1
|
||||
fun2
|
||||
["fun1","fun2"]
|
||||
fun1
|
||||
["fun2","fun1"]
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
|
|
@ -590,6 +590,7 @@ le:
|
|||
stack_size: 0x1000
|
||||
|
||||
EOF
|
||||
BROKEN=1
|
||||
RUN
|
||||
|
||||
NAME=hellolx.dll unpack iterated page
|
||||
|
|
|
|||
|
|
@ -1419,13 +1419,13 @@ CMDS=il
|
|||
EXPECT=<<EOF
|
||||
library
|
||||
-------------
|
||||
user32.dll
|
||||
kernel32.dll
|
||||
pstorec.dll
|
||||
shell32.dll
|
||||
crypt32.dll
|
||||
oleaut32.dll
|
||||
advapi32.dll
|
||||
shell32.dll
|
||||
user32.dll
|
||||
oleaut32.dll
|
||||
crypt32.dll
|
||||
pstorec.dll
|
||||
ole32.dll
|
||||
rasapi32.dll
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -285,27 +285,27 @@ ____h_ temperature LGPL3 Seva Binary temperatu
|
|||
____h_ xor16 LGPL3 deroad XOR-16 checksum
|
||||
____h_ xor8 LGPL3 deroad XOR-8 checksum
|
||||
____h_ xxhash32 LGPL3 deroad xxHash32 non-cryptographic hash
|
||||
ED____ rc4 LGPL-3 pancake RC4 symmetric-key block cipher
|
||||
ED____ rc6 LGPL-3 rakholiyajenish.07 RC6 symmetric-key block cipher
|
||||
_D____ ror LGPL-3 pancake Rotate Right symmetric-key block cipher
|
||||
__ed__ base64 LGPL-3 rakholiyajenish.07 Base64 encoder/decoder
|
||||
__ed__ base32 LGPL-3 Ahmed Ibrahim Base32 encoder/decoder
|
||||
ED____ rc2 LGPL-3 lionaneesh RC2 symmetric-key block cipher
|
||||
ED____ xor LGPL-3 pancake XOR symmetric-key block cipher
|
||||
ED____ cps2 LGPL-3 pancake,esanfelix,pof Capcom Play System 2 (CPS-2) symmetric-key block cipher
|
||||
ED____ rot LGPL-3 pancake Caesar symmetric-key cipher
|
||||
__ed__ punycode LGPL-3 pancake Punycode encoder/decoder
|
||||
ED____ serpent-ecb LGPL-3 NicsTr Serpent symmetric-key block cipher (ECB block mode)
|
||||
ED____ sm4-ecb LGPL-3 0xSh4dy ShangMi 4 symmetric-key block cipher (ECB block mode)
|
||||
__ed__ base36 LGPL-3 abcSup Base36 encoder/decoder
|
||||
__ed__ base85 LGPL-3 Ahmed Ibrahim Base85 encoder/decoder
|
||||
ED____ aes-cbc LGPL-3 rakholiyajenish.07 AES symmetric-key block cipher (CBC block mode)
|
||||
E_____ rol LGPL-3 pancake Rotate Left symmetric-key block cipher
|
||||
ED____ aes-ecb LGPL3 Nettle project,pancake AES symmetric-key block cipher (ECB block mode)
|
||||
__ed__ base16 LGPL-3 Ahmed Ibrahim Base16 encoder/decoder
|
||||
__ed__ base36 LGPL-3 abcSup Base36 encoder/decoder
|
||||
__ed__ base64 LGPL-3 rakholiyajenish.07 Base64 encoder/decoder
|
||||
ED____ des-ecb LGPL-3 deroad DES symmetric-key block cipher (ECB block mode)
|
||||
ED____ blowfish LGPL3 kishorbhat Blowfish symmetric-key block cipher
|
||||
ED____ sm4-ecb LGPL-3 0xSh4dy ShangMi 4 symmetric-key block cipher (ECB block mode)
|
||||
ED____ xor LGPL-3 pancake XOR symmetric-key block cipher
|
||||
__ed__ punycode LGPL-3 pancake Punycode encoder/decoder
|
||||
__ed__ base16 LGPL-3 Ahmed Ibrahim Base16 encoder/decoder
|
||||
ED____ rc4 LGPL-3 pancake RC4 symmetric-key block cipher
|
||||
__ed__ base91 LGPL-3 rakholiyajenish.07 Base91 encoder/decoder
|
||||
ED____ blowfish LGPL3 kishorbhat Blowfish symmetric-key block cipher
|
||||
ED____ aes-cbc LGPL-3 rakholiyajenish.07 AES symmetric-key block cipher (CBC block mode)
|
||||
ED____ rc6 LGPL-3 rakholiyajenish.07 RC6 symmetric-key block cipher
|
||||
ED____ cps2 LGPL-3 pancake,esanfelix,pof Capcom Play System 2 (CPS-2) symmetric-key block cipher
|
||||
ED____ rc2 LGPL-3 lionaneesh RC2 symmetric-key block cipher
|
||||
ED____ serpent-ecb LGPL-3 NicsTr Serpent symmetric-key block cipher (ECB block mode)
|
||||
ED____ aes-ecb LGPL3 Nettle project,pancake AES symmetric-key block cipher (ECB block mode)
|
||||
ED____ rot LGPL-3 pancake Caesar symmetric-key cipher
|
||||
__ed__ base32 LGPL-3 Ahmed Ibrahim Base32 encoder/decoder
|
||||
|
||||
flags legenda:
|
||||
E = encryption, D = decryption
|
||||
|
|
|
|||
|
|
@ -371,8 +371,8 @@ static bool test_rz_core_annotated_code_print(void) {
|
|||
static bool test_rz_core_annotated_code_print_comment_cmds(void) {
|
||||
RzAnnotatedCode *code = get_hello_world();
|
||||
char *actual;
|
||||
char *expected = "CCu base64:c3ltLmltcC5wdXRzKCJIZWxsbywgV29ybGQhIik= @ 0x1158\n"
|
||||
"CCu base64:cmV0dXJu @ 0x115f\n";
|
||||
char *expected = "CCu base64:cmV0dXJu @ 0x115f\n"
|
||||
"CCu base64:c3ltLmltcC5wdXRzKCJIZWxsbywgV29ybGQhIik= @ 0x1158\n";
|
||||
rz_cons_new();
|
||||
rz_cons_push();
|
||||
rz_core_annotated_code_print_comment_cmds(code);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,34 @@ bool test_ht_insert_lookup(void) {
|
|||
mu_assert_streq(sdb_ht_find(ht, "CCCC", NULL), "vCCCC", "CCCC value wrong");
|
||||
|
||||
sdb_ht_free(ht);
|
||||
|
||||
#ifdef HT_ENABLE_CUSTOM_ELEM_SIZE
|
||||
typedef struct {
|
||||
HtUUKv base;
|
||||
ut64 extra;
|
||||
} CustomKv;
|
||||
|
||||
HtUUOptions opt = { 0 };
|
||||
opt.elem_size = sizeof(CustomKv);
|
||||
HtUU *ht_u = ht_uu_new_opt(&opt);
|
||||
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
CustomKv *tmp = NULL;
|
||||
CustomKv kv = { 0 };
|
||||
|
||||
kv.base.key = 4 * i;
|
||||
kv.base.value = i + 200;
|
||||
kv.extra = i + 300;
|
||||
|
||||
ht_uu_insert_kv_ex(ht_u, (HtUUKv *)&kv, false, (HtUUKv **)&tmp);
|
||||
mu_assert_notnull(tmp, "KV is set after rehashing");
|
||||
mu_assert_eq(tmp->base.value, i + 200, "KV is valid after rehashing");
|
||||
mu_assert_eq(tmp->extra, i + 300, "KV extra value is valid after rehashing");
|
||||
}
|
||||
|
||||
ht_uu_free(ht_u);
|
||||
#endif
|
||||
|
||||
mu_end;
|
||||
}
|
||||
|
||||
|
|
@ -297,6 +325,71 @@ bool test_delete(void) {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rehash_on_delete(void) {
|
||||
HtUU *ht = ht_uu_new();
|
||||
ht->opt.hashfn = (HtUUHashFunction)create_collision;
|
||||
|
||||
for (ut32 i = 0; i < 56; i++) {
|
||||
mu_assert_true(ht_uu_insert(ht, i, i * 100), "failed to insert element");
|
||||
}
|
||||
|
||||
for (ut32 i = 0; i < 56; i++) {
|
||||
mu_assert_true(ht_uu_delete(ht, i), "failed to delete element");
|
||||
}
|
||||
|
||||
for (ut32 i = 0; i < 56; i++) {
|
||||
mu_assert_true(ht_uu_insert(ht, i, i * 100), "failed to insert element");
|
||||
}
|
||||
|
||||
for (ut32 i = 0; i < 56; i++) {
|
||||
mu_assert_true(ht_uu_update_key(ht, i, i + 1000), "failed to update element key");
|
||||
}
|
||||
|
||||
mu_assert_eq(ht_uu_size(ht), 56, "invalid table size");
|
||||
ht_uu_free(ht);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_ht_delete_optimized(void) {
|
||||
// Test case for the "deletion trick" optimization. If the optimized implementation places
|
||||
// incorrect "empty" slot, this would corrupt the hashtable and make some keys unreachable
|
||||
bool found = false;
|
||||
|
||||
for (ut32 size = 1; size <= 32; size++) {
|
||||
for (ut32 delete_key = 0; delete_key < size; delete_key++) {
|
||||
HtUU *ht = ht_uu_new();
|
||||
ht->opt.hashfn = (HtUUHashFunction)create_collision;
|
||||
|
||||
// Insert all
|
||||
for (ut32 i = 0; i < size; i++) {
|
||||
ht_uu_insert(ht, i, i * 100);
|
||||
}
|
||||
|
||||
// Delete 1
|
||||
ht_uu_delete(ht, delete_key);
|
||||
|
||||
// Confirm
|
||||
for (ut32 i = 0; i < size; i++) {
|
||||
HtUUKv *kv = ht_uu_find_kv(ht, i, &found);
|
||||
|
||||
if (i == delete_key) {
|
||||
mu_assert_null(kv, "element expected to be deleted");
|
||||
mu_assert_false(found, "element expected to be deleted");
|
||||
} else {
|
||||
mu_assert_notnull(kv, "key not found");
|
||||
mu_assert_true(found, "key not found");
|
||||
mu_assert_eq(kv->value, i * 100, "incorrect value");
|
||||
}
|
||||
}
|
||||
|
||||
mu_assert_eq(ht_uu_size(ht), size - 1, "invalid table size");
|
||||
ht_uu_free(ht);
|
||||
}
|
||||
}
|
||||
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_clear(void) {
|
||||
HtSS *ht = ht_ss_new(HT_STR_DUP, HT_STR_DUP);
|
||||
|
||||
|
|
@ -870,6 +963,8 @@ int all_tests() {
|
|||
mu_run_test(test_ht_insert_lookup);
|
||||
mu_run_test(test_ht_update_lookup);
|
||||
mu_run_test(test_ht_delete);
|
||||
mu_run_test(test_ht_delete_optimized);
|
||||
mu_run_test(test_rehash_on_delete);
|
||||
mu_run_test(test_ht_insert_kvp);
|
||||
mu_run_test(test_ht_insert_collision);
|
||||
mu_run_test(test_ht_grow);
|
||||
|
|
|
|||
|
|
@ -128,12 +128,12 @@ bool test_sdb_diff_ns() {
|
|||
mu_assert_streq(diff,
|
||||
"-NS test\n"
|
||||
"-NS test/subspace\n"
|
||||
"- test/subspace/here=lol\n"
|
||||
"- test/subspace/some=values\n"
|
||||
"- test/subspace/are=saved\n"
|
||||
"- test/subspace/some=values\n"
|
||||
"- test/subspace/here=lol\n"
|
||||
"- test/b=test\n"
|
||||
"- test/a=123\n"
|
||||
"- test/c=hello\n"
|
||||
"- test/b=test\n",
|
||||
"- test/c=hello\n",
|
||||
"ns removed diff");
|
||||
free(diff);
|
||||
|
||||
|
|
@ -142,12 +142,12 @@ bool test_sdb_diff_ns() {
|
|||
mu_assert_streq(diff,
|
||||
"+NS test\n"
|
||||
"+NS test/subspace\n"
|
||||
"+ test/subspace/here=lol\n"
|
||||
"+ test/subspace/some=values\n"
|
||||
"+ test/subspace/are=saved\n"
|
||||
"+ test/subspace/some=values\n"
|
||||
"+ test/subspace/here=lol\n"
|
||||
"+ test/b=test\n"
|
||||
"+ test/a=123\n"
|
||||
"+ test/c=hello\n"
|
||||
"+ test/b=test\n",
|
||||
"+ test/c=hello\n",
|
||||
"ns added diff");
|
||||
free(diff);
|
||||
|
||||
|
|
@ -166,9 +166,9 @@ bool test_sdb_diff_ns_sub() {
|
|||
mu_assert("sub ns removed (diff)", !diff_str(a, b, &diff));
|
||||
mu_assert_streq(diff,
|
||||
"-NS test/subspace\n"
|
||||
"- test/subspace/here=lol\n"
|
||||
"- test/subspace/are=saved\n"
|
||||
"- test/subspace/some=values\n"
|
||||
"- test/subspace/are=saved\n",
|
||||
"- test/subspace/here=lol\n",
|
||||
"sub ns removed diff");
|
||||
free(diff);
|
||||
|
||||
|
|
@ -176,9 +176,9 @@ bool test_sdb_diff_ns_sub() {
|
|||
mu_assert("sub ns added (diff)", !diff_str(b, a, &diff));
|
||||
mu_assert_streq(diff,
|
||||
"+NS test/subspace\n"
|
||||
"+ test/subspace/here=lol\n"
|
||||
"+ test/subspace/are=saved\n"
|
||||
"+ test/subspace/some=values\n"
|
||||
"+ test/subspace/are=saved\n",
|
||||
"+ test/subspace/here=lol\n",
|
||||
"sub ns added diff");
|
||||
free(diff);
|
||||
|
||||
|
|
|
|||
|
|
@ -275,8 +275,8 @@ static const char *text_ref_simple_unsorted =
|
|||
"bbb=other stuff\n"
|
||||
"\n"
|
||||
"/subnamespace\n"
|
||||
"key in sub=value in sub\n"
|
||||
"\\/more stuff=in sub\n"
|
||||
"key in sub=value in sub\n"
|
||||
"\n"
|
||||
"/subnamespace/subsub\n"
|
||||
"some stuff=also down here\n";
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ Sdb *functions_ref_db() {
|
|||
Sdb *db = sdb_new0();
|
||||
sdb_set(db, "0x4d2", "{\"name\":\"effekt\",\"type\":1,\"stack\":0,\"maxstack\":0,\"ninstr\":0,\"bp_frame\":true,\"pure\":true,\"bbs\":[1337]}");
|
||||
sdb_set(db, "0xbeef", "{\"name\":\"eskapist\",\"bits\":32,\"type\":16,\"stack\":0,\"maxstack\":0,\"ninstr\":0,\"bp_frame\":true,\"bbs\":[]}");
|
||||
sdb_set(db, "0x539", "{\"name\":\"hirsch\",\"bits\":16,\"type\":0,\"cc\":\"fancycall\",\"stack\":42,\"maxstack\":123,\"ninstr\":13,\"bp_frame\":true,\"bp_off\":4,\"bbs\":[1337,1234],\"imports\":[\"earth\",\"rise\"],\"labels\":{\"beach\":1400,\"another\":1450,\"year\":1440}}");
|
||||
sdb_set(db, "0x539", "{\"name\":\"hirsch\",\"bits\":16,\"type\":0,\"cc\":\"fancycall\",\"stack\":42,\"maxstack\":123,\"ninstr\":13,\"bp_frame\":true,\"bp_off\":4,\"bbs\":[1337,1234],\"imports\":[\"earth\",\"rise\"],\"labels\":{\"year\":1440,\"another\":1450,\"beach\":1400}}");
|
||||
sdb_set(db, "0xdead", "{\"name\":\"agnosie\",\"bits\":32,\"type\":8,\"stack\":0,\"maxstack\":0,\"ninstr\":0,\"bp_frame\":true,\"bbs\":[]}");
|
||||
sdb_set(db, "0xc0ffee", "{\"name\":\"lifnej\",\"bits\":32,\"type\":32,\"stack\":0,\"maxstack\":0,\"ninstr\":0,\"bp_frame\":true,\"bbs\":[]}");
|
||||
sdb_set(db, "0x1092", "{\"name\":\"hiberno\",\"bits\":32,\"type\":2,\"stack\":0,\"maxstack\":0,\"ninstr\":0,\"bbs\":[]}");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue