redefined hash functions
This commit is contained in:
parent
ad985e3862
commit
fd99432186
10
lib/dic.c
10
lib/dic.c
@ -81,7 +81,7 @@ static hcl_oop_oop_t expand_bucket (hcl_t* hcl, hcl_oop_oop_t oldbuc)
|
|||||||
HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass));
|
HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass));
|
||||||
key = (hcl_oop_char_t)ass->car;
|
key = (hcl_oop_char_t)ass->car;
|
||||||
HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key));
|
HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key));
|
||||||
index = hcl_hashoochars(key->slot, HCL_OBJ_GET_SIZE(key)) % newsz;
|
index = hcl_hash_oochars(key->slot, HCL_OBJ_GET_SIZE(key)) % newsz;
|
||||||
#else
|
#else
|
||||||
int n;
|
int n;
|
||||||
HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass));
|
HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass));
|
||||||
@ -113,7 +113,7 @@ static hcl_oop_cons_t find_or_upsert (hcl_t* hcl, hcl_oop_dic_t dic, hcl_oop_t k
|
|||||||
HCL_ASSERT (hcl, HCL_IS_ARRAY(hcl,dic->bucket));
|
HCL_ASSERT (hcl, HCL_IS_ARRAY(hcl,dic->bucket));
|
||||||
|
|
||||||
#if defined(SYMBOL_ONLY_KEY)
|
#if defined(SYMBOL_ONLY_KEY)
|
||||||
index = hcl_hashoochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_SIZE(key)) % HCL_OBJ_GET_SIZE(dic->bucket);
|
index = hcl_hash_oochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_SIZE(key)) % HCL_OBJ_GET_SIZE(dic->bucket);
|
||||||
#else
|
#else
|
||||||
if (hcl_hashobj(hcl, key, &index) <= -1) return HCL_NULL;
|
if (hcl_hashobj(hcl, key, &index) <= -1) return HCL_NULL;
|
||||||
index %= HCL_OBJ_GET_SIZE(dic->bucket);
|
index %= HCL_OBJ_GET_SIZE(dic->bucket);
|
||||||
@ -199,7 +199,7 @@ static hcl_oop_cons_t find_or_upsert (hcl_t* hcl, hcl_oop_dic_t dic, hcl_oop_t k
|
|||||||
|
|
||||||
#if defined(SYMBOL_ONLY_KEY)
|
#if defined(SYMBOL_ONLY_KEY)
|
||||||
/* recalculate the index for the expanded bucket */
|
/* recalculate the index for the expanded bucket */
|
||||||
index = hcl_hashoochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_SIZE(key)) % HCL_OBJ_GET_SIZE(dic->bucket);
|
index = hcl_hash_oochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_SIZE(key)) % HCL_OBJ_GET_SIZE(dic->bucket);
|
||||||
#else
|
#else
|
||||||
hcl_hashobj(hcl, key, &index); /* this must succeed as i know 'key' is hashable */
|
hcl_hashobj(hcl, key, &index); /* this must succeed as i know 'key' is hashable */
|
||||||
index %= HCL_OBJ_GET_SIZE(dic->bucket);
|
index %= HCL_OBJ_GET_SIZE(dic->bucket);
|
||||||
@ -286,7 +286,7 @@ int hcl_zapatdic (hcl_t* hcl, hcl_oop_dic_t dic, hcl_oop_t key)
|
|||||||
HCL_ASSERT (hcl, HCL_IS_ARRAY(hcl,dic->bucket));
|
HCL_ASSERT (hcl, HCL_IS_ARRAY(hcl,dic->bucket));
|
||||||
|
|
||||||
#if defined(SYMBOL_ONLY_KEY)
|
#if defined(SYMBOL_ONLY_KEY)
|
||||||
index = hcl_hashoochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_SIZE(key)) % bs;
|
index = hcl_hash_oochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_SIZE(key)) % bs;
|
||||||
#else
|
#else
|
||||||
if (hcl_hashobj(hcl, key, &index) <= -1) return -1;
|
if (hcl_hashobj(hcl, key, &index) <= -1) return -1;
|
||||||
index %= bs;
|
index %= bs;
|
||||||
@ -336,7 +336,7 @@ found:
|
|||||||
#if defined(SYMBOL_ONLY_KEY)
|
#if defined(SYMBOL_ONLY_KEY)
|
||||||
/* get the natural hash index for the data in the slot at
|
/* get the natural hash index for the data in the slot at
|
||||||
* the current hash index */
|
* the current hash index */
|
||||||
z = hcl_hashoochars(HCL_OBJ_GET_CHAR_SLOT(ass->car), HCL_OBJ_GET_SIZE(ass->car)) % bs;
|
z = hcl_hash_oochars(HCL_OBJ_GET_CHAR_SLOT(ass->car), HCL_OBJ_GET_SIZE(ass->car)) % bs;
|
||||||
#else
|
#else
|
||||||
if (hcl_hashobj(hcl, ass->car, &z) <= -1) return -1;
|
if (hcl_hashobj(hcl, ass->car, &z) <= -1) return -1;
|
||||||
z %= bs;
|
z %= bs;
|
||||||
|
2
lib/gc.c
2
lib/gc.c
@ -96,7 +96,7 @@ static void compact_symbol_table (hcl_t* hcl, hcl_oop_t _nil)
|
|||||||
|
|
||||||
HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl, symbol));
|
HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl, symbol));
|
||||||
|
|
||||||
z = hcl_hashoochars(symbol->slot, HCL_OBJ_GET_SIZE(symbol)) % bucket_size;
|
z = hcl_hash_oochars(symbol->slot, HCL_OBJ_GET_SIZE(symbol)) % bucket_size;
|
||||||
|
|
||||||
/* move an element if necessary */
|
/* move an element if necessary */
|
||||||
if ((y > x && (z <= x || z > y)) ||
|
if ((y > x && (z <= x || z > y)) ||
|
||||||
|
@ -348,6 +348,105 @@ typedef struct hcl_bcs_t hcl_bcs_t;
|
|||||||
/* the maximum number of bch charaters to represent a single uch character */
|
/* the maximum number of bch charaters to represent a single uch character */
|
||||||
#define HCL_BCSIZE_MAX 6
|
#define HCL_BCSIZE_MAX 6
|
||||||
|
|
||||||
|
/* =========================================================================
|
||||||
|
* BASIC OOP ENCODING
|
||||||
|
* ========================================================================= */
|
||||||
|
|
||||||
|
/* actual structure defined in hcl.h */
|
||||||
|
typedef struct hcl_obj_t hcl_obj_t;
|
||||||
|
typedef struct hcl_obj_t* hcl_oop_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An object pointer(OOP) is an ordinary pointer value to an object.
|
||||||
|
* but some simple numeric values are also encoded into OOP using a simple
|
||||||
|
* bit-shifting and masking.
|
||||||
|
*
|
||||||
|
* A real OOP is stored without any bit-shifting while a non-pointer value encoded
|
||||||
|
* in an OOP is bit-shifted to the left by 2 and the 2 least-significant bits
|
||||||
|
* are set to 1 or 2.
|
||||||
|
*
|
||||||
|
* This scheme works because the object allocators aligns the object size to
|
||||||
|
* a multiple of sizeof(hcl_oop_t). This way, the 2 least-significant bits
|
||||||
|
* of a real OOP are always 0s.
|
||||||
|
*
|
||||||
|
* With 2 bits, i can encode only 3 special types except object pointers.
|
||||||
|
* Since I need more than 3 special types, I extend the tag bits up to 4 bits
|
||||||
|
* to represent a special data type that doesn't require a range as wide
|
||||||
|
* as a small integer. A unicode character, for instance, only requires 21
|
||||||
|
* bits at most. An error doesn't need to be as diverse as a small integer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HCL_OOP_TAG_BITS_LO 2
|
||||||
|
#define HCL_OOP_TAG_BITS_HI 2
|
||||||
|
|
||||||
|
#define HCL_OOP_TAG_SMOOI 1 /* 01 */
|
||||||
|
#define HCL_OOP_TAG_SMPTR 2 /* 10 */
|
||||||
|
#define HCL_OOP_TAG_EXTENDED 3 /* 11 - internal use only */
|
||||||
|
#define HCL_OOP_TAG_CHAR 3 /* 0011 */
|
||||||
|
#define HCL_OOP_TAG_ERROR 7 /* 0111 */
|
||||||
|
#define HCL_OOP_TAG_RESERVED0 11 /* 1011 */
|
||||||
|
#define HCL_OOP_TAG_RESERVED1 15 /* 1111 */
|
||||||
|
|
||||||
|
#define HCL_OOP_GET_TAG_LO(oop) (((hcl_oow_t)oop) & HCL_LBMASK(hcl_oow_t, HCL_OOP_TAG_BITS_LO))
|
||||||
|
#define HCL_OOP_GET_TAG_LOHI(oop) (((hcl_oow_t)oop) & HCL_LBMASK(hcl_oow_t, HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_HI))
|
||||||
|
#define HCL_OOP_GET_TAG(oop) (HCL_OOP_GET_TAG_LO(oop) == HCL_OOP_TAG_EXTENDED? HCL_OOP_GET_TAG_LOHI(oop): HCL_OOP_GET_TAG_LO(oop))
|
||||||
|
|
||||||
|
#define HCL_OOP_IS_NUMERIC(oop) (HCL_OOP_GET_TAG_LO(oop) != 0)
|
||||||
|
#define HCL_OOP_IS_POINTER(oop) (HCL_OOP_GET_TAG_LO(oop) == 0)
|
||||||
|
|
||||||
|
#define HCL_OOP_IS_SMOOI(oop) (HCL_OOP_GET_TAG_LO(oop) == HCL_OOP_TAG_SMOOI)
|
||||||
|
#define HCL_OOP_IS_SMPTR(oop) (HCL_OOP_GET_TAG_LO(oop) == HCL_OOP_TAG_SMPTR)
|
||||||
|
|
||||||
|
#define HCL_SMOOI_TO_OOP(num) ((hcl_oop_t)((((hcl_oow_t)(hcl_ooi_t)(num)) << HCL_OOP_TAG_BITS_LO) | HCL_OOP_TAG_SMOOI))
|
||||||
|
#define HCL_OOP_TO_SMOOI(oop) (((hcl_ooi_t)oop) >> HCL_OOP_TAG_BITS_LO)
|
||||||
|
/*
|
||||||
|
#define HCL_SMPTR_TO_OOP(ptr) ((hcl_oop_t)((((hcl_oow_t)(ptr)) << HCL_OOP_TAG_BITS_LO) | HCL_OOP_TAG_SMPTR))
|
||||||
|
#define HCL_OOP_TO_SMPTR(oop) (((hcl_ooi_t)oop) >> HCL_OOP_TAG_BITS_LO)
|
||||||
|
*/
|
||||||
|
#define HCL_SMPTR_TO_OOP(ptr) ((hcl_oop_t)(((hcl_oow_t)ptr) | HCL_OOP_TAG_SMPTR))
|
||||||
|
#define HCL_OOP_TO_SMPTR(oop) ((void*)(((hcl_oow_t)oop) & ~HCL_LBMASK(hcl_oow_t, HCL_OOP_TAG_BITS_LO)))
|
||||||
|
|
||||||
|
#define HCL_OOP_IS_CHAR(oop) (HCL_OOP_GET_TAG(oop) == HCL_OOP_TAG_CHAR)
|
||||||
|
#define HCL_OOP_IS_ERROR(oop) (HCL_OOP_GET_TAG(oop) == HCL_OOP_TAG_ERROR)
|
||||||
|
|
||||||
|
#define HCL_OOP_TO_CHAR(oop) (((hcl_oow_t)oop) >> (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_LO))
|
||||||
|
#define HCL_CHAR_TO_OOP(num) ((hcl_oop_t)((((hcl_oow_t)(num)) << (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_LO)) | HCL_OOP_TAG_CHAR))
|
||||||
|
#define HCL_OOP_TO_ERROR(oop) (((hcl_oow_t)oop) >> (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_LO))
|
||||||
|
#define HCL_ERROR_TO_OOP(num) ((hcl_oop_t)((((hcl_oow_t)(num)) << (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_LO)) | HCL_OOP_TAG_ERROR))
|
||||||
|
|
||||||
|
/* SMOOI takes up 62 bit on a 64-bit architecture and 30 bits
|
||||||
|
* on a 32-bit architecture. The absolute value takes up 61 bits and 29 bits
|
||||||
|
* respectively for the 1 sign bit. */
|
||||||
|
#define HCL_SMOOI_BITS (HCL_OOI_BITS - HCL_OOP_TAG_BITS_LO)
|
||||||
|
#define HCL_SMOOI_ABS_BITS (HCL_SMOOI_BITS - 1)
|
||||||
|
#define HCL_SMOOI_MAX ((hcl_ooi_t)(~((hcl_oow_t)0) >> (HCL_OOP_TAG_BITS_LO + 1)))
|
||||||
|
/* Sacrificing 1 bit pattern for a negative SMOOI makes
|
||||||
|
* implementation a lot eaisier in many respect. */
|
||||||
|
/*#define HCL_SMOOI_MIN (-HCL_SMOOI_MAX - 1)*/
|
||||||
|
#define HCL_SMOOI_MIN (-HCL_SMOOI_MAX)
|
||||||
|
#define HCL_IN_SMOOI_RANGE(ooi) ((ooi) >= HCL_SMOOI_MIN && (ooi) <= HCL_SMOOI_MAX)
|
||||||
|
|
||||||
|
|
||||||
|
/* SMPTR is a special value which has been devised to encode an address value
|
||||||
|
* whose low HCL_OOP_TAG_BITS_LO bits are 0. its class is SmallPointer. A pointer
|
||||||
|
* returned by most of system functions would be aligned to the pointer size.
|
||||||
|
* you can use the followings macros when converting such a pointer without loss. */
|
||||||
|
#define HCL_IN_SMPTR_RANGE(ptr) ((((hcl_oow_t)ptr) & HCL_LBMASK(hcl_oow_t, HCL_OOP_TAG_BITS_LO)) == 0)
|
||||||
|
|
||||||
|
#define HCL_CHAR_BITS (HCL_OOI_BITS - HCL_OOP_TAG_BITS_LO - HCL_OOP_TAG_BITS_HI)
|
||||||
|
#define HCL_CHAR_MIN 0
|
||||||
|
#define HCL_CHAR_MAX (~((hcl_oow_t)0) >> (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_HI))
|
||||||
|
|
||||||
|
#define HCL_ERROR_BITS (HCL_OOI_BITS - HCL_OOP_TAG_BITS_LO - HCL_OOP_TAG_BITS_HI)
|
||||||
|
#define HCL_ERROR_MIN 0
|
||||||
|
#define HCL_ERROR_MAX (~((hcl_oow_t)0) >> (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_HI))
|
||||||
|
|
||||||
|
/* TODO: There are untested code where smint is converted to hcl_oow_t.
|
||||||
|
* for example, the spec making macro treats the number as hcl_oow_t instead of hcl_ooi_t.
|
||||||
|
* as of this writing, i skip testing that part with the spec value exceeding HCL_SMOOI_MAX.
|
||||||
|
* later, please verify it works, probably by limiting the value ranges in such macros
|
||||||
|
*/
|
||||||
|
|
||||||
/* =========================================================================
|
/* =========================================================================
|
||||||
* TIME-RELATED TYPES
|
* TIME-RELATED TYPES
|
||||||
* =========================================================================*/
|
* =========================================================================*/
|
||||||
|
102
lib/hcl-utl.h
102
lib/hcl-utl.h
@ -116,46 +116,126 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if (HCL_SIZEOF_SIZE_T == 4)
|
||||||
|
# define HCL_HASH_FNV_MAGIC_INIT (0x811c9dc5)
|
||||||
|
# define HCL_HASH_FNV_MAGIC_PRIME (0x01000193)
|
||||||
|
#elif (HCL_SIZEOF_SIZE_T == 8)
|
||||||
|
|
||||||
|
# define HCL_HASH_FNV_MAGIC_INIT (0xCBF29CE484222325)
|
||||||
|
# define HCL_HASH_FNV_MAGIC_PRIME (0x100000001B3l)
|
||||||
|
|
||||||
|
#elif (HCL_SIZEOF_SIZE_T == 16)
|
||||||
|
# define HCL_HASH_FNV_MAGIC_INIT (0x6C62272E07BB014262B821756295C58D)
|
||||||
|
# define HCL_HASH_FNV_MAGIC_PRIME (0x1000000000000000000013B)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HCL_HASH_FNV_MAGIC_INIT)
|
||||||
|
/* FNV-1 hash */
|
||||||
|
# define HCL_HASH_INIT HCL_HASH_FNV_MAGIC_INIT
|
||||||
|
# define HCL_HASH_VALUE(hv,v) (((hv) ^ (v)) * HCL_HASH_FNV_MAGIC_PRIME)
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* SDBM hash */
|
||||||
|
# define HCL_HASH_INIT 0
|
||||||
|
# define HCL_HASH_VALUE(hv,v) (((hv) << 6) + ((hv) << 16) - (hv) + (v))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HCL_HASH_VPTL(hv, ptr, len, type) do { \
|
||||||
|
hv = HCL_HASH_INIT; \
|
||||||
|
HCL_HASH_MORE_VPTL (hv, ptr, len, type); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define HCL_HASH_MORE_VPTL(hv, ptr, len, type) do { \
|
||||||
|
type* __hcl_hash_more_vptl_p = (type*)(ptr); \
|
||||||
|
type* __hcl_hash_more_vptl_q = (type*)__hcl_hash_more_vptl_p + (len); \
|
||||||
|
while (__hcl_hash_more_vptl_p < __hcl_hash_more_vptl_q) \
|
||||||
|
{ \
|
||||||
|
hv = HCL_HASH_VALUE(hv, *__hcl_hash_more_vptl_p); \
|
||||||
|
__hcl_hash_more_vptl_p++; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define HCL_HASH_VPTR(hv, ptr, type) do { \
|
||||||
|
hv = HCL_HASH_INIT; \
|
||||||
|
HCL_HASH_MORE_VPTR (hv, ptr, type); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define HCL_HASH_MORE_VPTR(hv, ptr, type) do { \
|
||||||
|
type* __hcl_hash_more_vptr_p = (type*)(ptr); \
|
||||||
|
while (*__hcl_hash_more_vptr_p) \
|
||||||
|
{ \
|
||||||
|
hv = HCL_HASH_VALUE(hv, *__hcl_hash_more_vptr_p); \
|
||||||
|
__hcl_hash_more_vptr_p++; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define HCL_HASH_BYTES(hv, ptr, len) HCL_HASH_VPTL(hv, ptr, len, const hcl_uint8_t)
|
||||||
|
#define HCL_HASH_MORE_BYTES(hv, ptr, len) HCL_HASH_MORE_VPTL(hv, ptr, len, const hcl_uint8_t)
|
||||||
|
|
||||||
|
#define HCL_HASH_BCHARS(hv, ptr, len) HCL_HASH_VPTL(hv, ptr, len, const hcl_bch_t)
|
||||||
|
#define HCL_HASH_MORE_BCHARS(hv, ptr, len) HCL_HASH_MORE_VPTL(hv, ptr, len, const hcl_bch_t)
|
||||||
|
|
||||||
|
#define HCL_HASH_UCHARS(hv, ptr, len) HCL_HASH_VPTL(hv, ptr, len, const hcl_uch_t)
|
||||||
|
#define HCL_HASH_MORE_UCHARS(hv, ptr, len) HCL_HASH_MORE_VPTL(hv, ptr, len, const hcl_uch_t)
|
||||||
|
|
||||||
|
#define HCL_HASH_BCSTR(hv, ptr) HCL_HASH_VPTR(hv, ptr, const hcl_bch_t)
|
||||||
|
#define HCL_HASH_MORE_BCSTR(hv, ptr) HCL_HASH_MORE_VPTR(hv, ptr, const hcl_bch_t)
|
||||||
|
|
||||||
|
#define HCL_HASH_UCSTR(hv, ptr) HCL_HASH_VPTR(hv, ptr, const hcl_uch_t)
|
||||||
|
#define HCL_HASH_MORE_UCSTR(hv, ptr) HCL_HASH_MORE_VPTR(hv, ptr, const hcl_uch_t)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HCL_EXPORT hcl_oow_t hcl_hash_bytes (
|
HCL_EXPORT hcl_oow_t hcl_hash_bytes_ (
|
||||||
const hcl_oob_t* ptr,
|
const hcl_oob_t* ptr,
|
||||||
hcl_oow_t len
|
hcl_oow_t len
|
||||||
);
|
);
|
||||||
|
|
||||||
#if defined(HCL_HAVE_INLINE)
|
#if defined(HCL_HAVE_INLINE)
|
||||||
static HCL_INLINE hcl_oow_t hcl_hashbchars (const hcl_bch_t* ptr, hcl_oow_t len)
|
static HCL_INLINE hcl_oow_t hcl_hash_bytes (const hcl_oob_t* ptr, hcl_oow_t len)
|
||||||
|
{
|
||||||
|
hcl_oow_t hv;
|
||||||
|
HCL_HASH_BYTES (hv, ptr, len);
|
||||||
|
/* constrain the hash value to be representable in a small integer
|
||||||
|
* for convenience sake */
|
||||||
|
return hv % ((hcl_oow_t)HCL_SMOOI_MAX + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HCL_INLINE hcl_oow_t hcl_hash_bchars (const hcl_bch_t* ptr, hcl_oow_t len)
|
||||||
{
|
{
|
||||||
return hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_bch_t));
|
return hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_bch_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
static HCL_INLINE hcl_oow_t hcl_hashuchars (const hcl_uch_t* ptr, hcl_oow_t len)
|
static HCL_INLINE hcl_oow_t hcl_hash_uchars (const hcl_uch_t* ptr, hcl_oow_t len)
|
||||||
{
|
{
|
||||||
return hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_uch_t));
|
return hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_uch_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
static HCL_INLINE hcl_oow_t hcl_hashwords (const hcl_oow_t* ptr, hcl_oow_t len)
|
static HCL_INLINE hcl_oow_t hcl_hash_words (const hcl_oow_t* ptr, hcl_oow_t len)
|
||||||
{
|
{
|
||||||
return hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_oow_t));
|
return hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_oow_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
static HCL_INLINE hcl_oow_t hcl_hashhalfwords (const hcl_oohw_t* ptr, hcl_oow_t len)
|
static HCL_INLINE hcl_oow_t hcl_hash_halfwords (const hcl_oohw_t* ptr, hcl_oow_t len)
|
||||||
{
|
{
|
||||||
return hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_oohw_t));
|
return hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_oohw_t));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define hcl_hashbchars(ptr,len) hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_bch_t))
|
# define hcl_hash_bytes(ptr,len) hcl_hash_bytes_(ptr, len)
|
||||||
# define hcl_hashuchars(ptr,len) hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_uch_t))
|
# define hcl_hash_bchars(ptr,len) hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_bch_t))
|
||||||
# define hcl_hashwords(ptr,len) hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_oow_t))
|
# define hcl_hash_uchars(ptr,len) hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_uch_t))
|
||||||
# define hcl_hashhalfwords(ptr,len) hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_oohw_t))
|
# define hcl_hash_words(ptr,len) hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_oow_t))
|
||||||
|
# define hcl_hash_halfwords(ptr,len) hcl_hash_bytes((const hcl_oob_t*)ptr, len * HCL_SIZEOF(hcl_oohw_t))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HCL_OOCH_IS_UCH)
|
#if defined(HCL_OOCH_IS_UCH)
|
||||||
# define hcl_hashoochars(ptr,len) hcl_hashuchars(ptr,len)
|
# define hcl_hash_oochars(ptr,len) hcl_hash_uchars(ptr,len)
|
||||||
#else
|
#else
|
||||||
# define hcl_hashoochars(ptr,len) hcl_hashbchars(ptr,len)
|
# define hcl_hash_oochars(ptr,len) hcl_hash_bchars(ptr,len)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
119
lib/hcl.h
119
lib/hcl.h
@ -196,8 +196,12 @@ enum hcl_trait_t
|
|||||||
};
|
};
|
||||||
typedef enum hcl_trait_t hcl_trait_t;
|
typedef enum hcl_trait_t hcl_trait_t;
|
||||||
|
|
||||||
typedef struct hcl_obj_t hcl_obj_t;
|
/* =========================================================================
|
||||||
typedef struct hcl_obj_t* hcl_oop_t;
|
* SPECIALIZED OOP TYPES
|
||||||
|
* ========================================================================= */
|
||||||
|
|
||||||
|
/* hcl_oop_t defined in hcl-cmn.h
|
||||||
|
* hcl_obj_t defined further down */
|
||||||
|
|
||||||
/* these are more specialized types for hcl_obj_t */
|
/* these are more specialized types for hcl_obj_t */
|
||||||
typedef struct hcl_obj_oop_t hcl_obj_oop_t;
|
typedef struct hcl_obj_oop_t hcl_obj_oop_t;
|
||||||
@ -219,9 +223,9 @@ typedef struct hcl_obj_word_t* hcl_oop_word_t;
|
|||||||
#define HCL_OOHW_BITS (HCL_SIZEOF_OOHW_T * 8)
|
#define HCL_OOHW_BITS (HCL_SIZEOF_OOHW_T * 8)
|
||||||
|
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* =========================================================================
|
||||||
/* BIGINT TYPES AND MACROS */
|
* BIGINT TYPES AND MACROS
|
||||||
/* ========================================================================= */
|
* ========================================================================= */
|
||||||
#if (HCL_SIZEOF_UINTMAX_T > HCL_SIZEOF_OOW_T)
|
#if (HCL_SIZEOF_UINTMAX_T > HCL_SIZEOF_OOW_T)
|
||||||
# define HCL_USE_FULL_WORD
|
# define HCL_USE_FULL_WORD
|
||||||
#endif
|
#endif
|
||||||
@ -254,102 +258,9 @@ typedef struct hcl_obj_word_t* hcl_oop_word_t;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* =========================================================================
|
||||||
/*
|
* OBJECT STRUCTURE
|
||||||
* OOP encoding
|
* ========================================================================= */
|
||||||
* An object pointer(OOP) is an ordinary pointer value to an object.
|
|
||||||
* but some simple numeric values are also encoded into OOP using a simple
|
|
||||||
* bit-shifting and masking.
|
|
||||||
*
|
|
||||||
* A real OOP is stored without any bit-shifting while a non-pointer value encoded
|
|
||||||
* in an OOP is bit-shifted to the left by 2 and the 2 least-significant bits
|
|
||||||
* are set to 1 or 2.
|
|
||||||
*
|
|
||||||
* This scheme works because the object allocators aligns the object size to
|
|
||||||
* a multiple of sizeof(hcl_oop_t). This way, the 2 least-significant bits
|
|
||||||
* of a real OOP are always 0s.
|
|
||||||
*
|
|
||||||
* With 2 bits, i can encode only 3 special types except object pointers.
|
|
||||||
* Since I need more than 3 special types, I extend the tag bits up to 4 bits
|
|
||||||
* to represent a special data type that doesn't require a range as wide
|
|
||||||
* as a small integer. A unicode character, for instance, only requires 21
|
|
||||||
* bits at most. An error doesn't need to be as diverse as a small integer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define HCL_OOP_TAG_BITS_LO 2
|
|
||||||
#define HCL_OOP_TAG_BITS_HI 2
|
|
||||||
|
|
||||||
#define HCL_OOP_TAG_SMOOI 1 /* 01 */
|
|
||||||
#define HCL_OOP_TAG_SMPTR 2 /* 10 */
|
|
||||||
#define HCL_OOP_TAG_EXTENDED 3 /* 11 - internal use only */
|
|
||||||
#define HCL_OOP_TAG_CHAR 3 /* 0011 */
|
|
||||||
#define HCL_OOP_TAG_ERROR 7 /* 0111 */
|
|
||||||
#define HCL_OOP_TAG_RESERVED0 11 /* 1011 */
|
|
||||||
#define HCL_OOP_TAG_RESERVED1 15 /* 1111 */
|
|
||||||
|
|
||||||
#define HCL_OOP_GET_TAG_LO(oop) (((hcl_oow_t)oop) & HCL_LBMASK(hcl_oow_t, HCL_OOP_TAG_BITS_LO))
|
|
||||||
#define HCL_OOP_GET_TAG_LOHI(oop) (((hcl_oow_t)oop) & HCL_LBMASK(hcl_oow_t, HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_HI))
|
|
||||||
#define HCL_OOP_GET_TAG(oop) (HCL_OOP_GET_TAG_LO(oop) == HCL_OOP_TAG_EXTENDED? HCL_OOP_GET_TAG_LOHI(oop): HCL_OOP_GET_TAG_LO(oop))
|
|
||||||
|
|
||||||
#define HCL_OOP_IS_NUMERIC(oop) (HCL_OOP_GET_TAG_LO(oop) != 0)
|
|
||||||
#define HCL_OOP_IS_POINTER(oop) (HCL_OOP_GET_TAG_LO(oop) == 0)
|
|
||||||
|
|
||||||
#define HCL_OOP_IS_SMOOI(oop) (HCL_OOP_GET_TAG_LO(oop) == HCL_OOP_TAG_SMOOI)
|
|
||||||
#define HCL_OOP_IS_SMPTR(oop) (HCL_OOP_GET_TAG_LO(oop) == HCL_OOP_TAG_SMPTR)
|
|
||||||
|
|
||||||
#define HCL_SMOOI_TO_OOP(num) ((hcl_oop_t)((((hcl_oow_t)(hcl_ooi_t)(num)) << HCL_OOP_TAG_BITS_LO) | HCL_OOP_TAG_SMOOI))
|
|
||||||
#define HCL_OOP_TO_SMOOI(oop) (((hcl_ooi_t)oop) >> HCL_OOP_TAG_BITS_LO)
|
|
||||||
/*
|
|
||||||
#define HCL_SMPTR_TO_OOP(ptr) ((hcl_oop_t)((((hcl_oow_t)(ptr)) << HCL_OOP_TAG_BITS_LO) | HCL_OOP_TAG_SMPTR))
|
|
||||||
#define HCL_OOP_TO_SMPTR(oop) (((hcl_ooi_t)oop) >> HCL_OOP_TAG_BITS_LO)
|
|
||||||
*/
|
|
||||||
#define HCL_SMPTR_TO_OOP(ptr) ((hcl_oop_t)(((hcl_oow_t)ptr) | HCL_OOP_TAG_SMPTR))
|
|
||||||
#define HCL_OOP_TO_SMPTR(oop) ((void*)(((hcl_oow_t)oop) & ~HCL_LBMASK(hcl_oow_t, HCL_OOP_TAG_BITS_LO)))
|
|
||||||
|
|
||||||
#define HCL_OOP_IS_CHAR(oop) (HCL_OOP_GET_TAG(oop) == HCL_OOP_TAG_CHAR)
|
|
||||||
#define HCL_OOP_IS_ERROR(oop) (HCL_OOP_GET_TAG(oop) == HCL_OOP_TAG_ERROR)
|
|
||||||
|
|
||||||
#define HCL_OOP_TO_CHAR(oop) (((hcl_oow_t)oop) >> (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_LO))
|
|
||||||
#define HCL_CHAR_TO_OOP(num) ((hcl_oop_t)((((hcl_oow_t)(num)) << (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_LO)) | HCL_OOP_TAG_CHAR))
|
|
||||||
#define HCL_OOP_TO_ERROR(oop) (((hcl_oow_t)oop) >> (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_LO))
|
|
||||||
#define HCL_ERROR_TO_OOP(num) ((hcl_oop_t)((((hcl_oow_t)(num)) << (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_LO)) | HCL_OOP_TAG_ERROR))
|
|
||||||
|
|
||||||
/* SMOOI takes up 62 bit on a 64-bit architecture and 30 bits
|
|
||||||
* on a 32-bit architecture. The absolute value takes up 61 bits and 29 bits
|
|
||||||
* respectively for the 1 sign bit. */
|
|
||||||
#define HCL_SMOOI_BITS (HCL_OOI_BITS - HCL_OOP_TAG_BITS_LO)
|
|
||||||
#define HCL_SMOOI_ABS_BITS (HCL_SMOOI_BITS - 1)
|
|
||||||
#define HCL_SMOOI_MAX ((hcl_ooi_t)(~((hcl_oow_t)0) >> (HCL_OOP_TAG_BITS_LO + 1)))
|
|
||||||
/* Sacrificing 1 bit pattern for a negative SMOOI makes
|
|
||||||
* implementation a lot eaisier in many respect. */
|
|
||||||
/*#define HCL_SMOOI_MIN (-HCL_SMOOI_MAX - 1)*/
|
|
||||||
#define HCL_SMOOI_MIN (-HCL_SMOOI_MAX)
|
|
||||||
#define HCL_IN_SMOOI_RANGE(ooi) ((ooi) >= HCL_SMOOI_MIN && (ooi) <= HCL_SMOOI_MAX)
|
|
||||||
|
|
||||||
|
|
||||||
/* SMPTR is a special value which has been devised to encode an address value
|
|
||||||
* whose low HCL_OOP_TAG_BITS_LO bits are 0. its class is SmallPointer. A pointer
|
|
||||||
* returned by most of system functions would be aligned to the pointer size.
|
|
||||||
* you can use the followings macros when converting such a pointer without loss. */
|
|
||||||
#define HCL_IN_SMPTR_RANGE(ptr) ((((hcl_oow_t)ptr) & HCL_LBMASK(hcl_oow_t, HCL_OOP_TAG_BITS_LO)) == 0)
|
|
||||||
|
|
||||||
#define HCL_CHAR_BITS (HCL_OOI_BITS - HCL_OOP_TAG_BITS_LO - HCL_OOP_TAG_BITS_HI)
|
|
||||||
#define HCL_CHAR_MIN 0
|
|
||||||
#define HCL_CHAR_MAX (~((hcl_oow_t)0) >> (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_HI))
|
|
||||||
|
|
||||||
#define HCL_ERROR_BITS (HCL_OOI_BITS - HCL_OOP_TAG_BITS_LO - HCL_OOP_TAG_BITS_HI)
|
|
||||||
#define HCL_ERROR_MIN 0
|
|
||||||
#define HCL_ERROR_MAX (~((hcl_oow_t)0) >> (HCL_OOP_TAG_BITS_LO + HCL_OOP_TAG_BITS_HI))
|
|
||||||
|
|
||||||
/* TODO: There are untested code where smint is converted to hcl_oow_t.
|
|
||||||
* for example, the spec making macro treats the number as hcl_oow_t instead of hcl_ooi_t.
|
|
||||||
* as of this writing, i skip testing that part with the spec value exceeding HCL_SMOOI_MAX.
|
|
||||||
* later, please verify it works, probably by limiting the value ranges in such macros
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Object structure
|
|
||||||
*/
|
|
||||||
enum hcl_obj_type_t
|
enum hcl_obj_type_t
|
||||||
{
|
{
|
||||||
HCL_OBJ_TYPE_OOP,
|
HCL_OBJ_TYPE_OOP,
|
||||||
@ -706,6 +617,10 @@ struct hcl_process_scheduler_t
|
|||||||
#define HCL_ISTYPEOF(hcl,oop,type) \
|
#define HCL_ISTYPEOF(hcl,oop,type) \
|
||||||
(!HCL_OOP_IS_NUMERIC(oop) && HCL_OBJ_GET_FLAGS_TYPE(oop) == (type))
|
(!HCL_OOP_IS_NUMERIC(oop) && HCL_OBJ_GET_FLAGS_TYPE(oop) == (type))
|
||||||
|
|
||||||
|
/* =========================================================================
|
||||||
|
* HEAP
|
||||||
|
* ========================================================================= */
|
||||||
|
|
||||||
typedef struct hcl_heap_t hcl_heap_t;
|
typedef struct hcl_heap_t hcl_heap_t;
|
||||||
|
|
||||||
struct hcl_heap_t
|
struct hcl_heap_t
|
||||||
@ -716,7 +631,7 @@ struct hcl_heap_t
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* =========================================================================
|
/* =========================================================================
|
||||||
* HCL VM LOGGING
|
* VM LOGGING
|
||||||
* ========================================================================= */
|
* ========================================================================= */
|
||||||
|
|
||||||
enum hcl_log_mask_t
|
enum hcl_log_mask_t
|
||||||
|
@ -477,15 +477,15 @@ int hcl_hashobj (hcl_t* hcl, hcl_oop_t obj, hcl_oow_t* xhv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HCL_OBJ_TYPE_CHAR:
|
case HCL_OBJ_TYPE_CHAR:
|
||||||
hv = hcl_hashoochars (((hcl_oop_char_t)obj)->slot, HCL_OBJ_GET_SIZE(obj));
|
hv = hcl_hash_oochars (((hcl_oop_char_t)obj)->slot, HCL_OBJ_GET_SIZE(obj));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCL_OBJ_TYPE_HALFWORD:
|
case HCL_OBJ_TYPE_HALFWORD:
|
||||||
hv = hcl_hashhalfwords(((hcl_oop_halfword_t)obj)->slot, HCL_OBJ_GET_SIZE(obj));
|
hv = hcl_hash_halfwords(((hcl_oop_halfword_t)obj)->slot, HCL_OBJ_GET_SIZE(obj));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCL_OBJ_TYPE_WORD:
|
case HCL_OBJ_TYPE_WORD:
|
||||||
hv = hcl_hashwords(((hcl_oop_word_t)obj)->slot, HCL_OBJ_GET_SIZE(obj));
|
hv = hcl_hash_words(((hcl_oop_word_t)obj)->slot, HCL_OBJ_GET_SIZE(obj));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -73,7 +73,7 @@ static hcl_oop_oop_t expand_bucket (hcl_t* hcl, hcl_oop_oop_t oldbuc)
|
|||||||
HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl, symbol));
|
HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl, symbol));
|
||||||
/*HCL_ASSERT (hcl, sym->size > 0);*/
|
/*HCL_ASSERT (hcl, sym->size > 0);*/
|
||||||
|
|
||||||
index = hcl_hashoochars(symbol->slot, HCL_OBJ_GET_SIZE(symbol)) % newsz;
|
index = hcl_hash_oochars(symbol->slot, HCL_OBJ_GET_SIZE(symbol)) % newsz;
|
||||||
while (newbuc->slot[index] != hcl->_nil) index = (index + 1) % newsz;
|
while (newbuc->slot[index] != hcl->_nil) index = (index + 1) % newsz;
|
||||||
newbuc->slot[index] = (hcl_oop_t)symbol;
|
newbuc->slot[index] = (hcl_oop_t)symbol;
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ static hcl_oop_t find_or_make_symbol (hcl_t* hcl, const hcl_ooch_t* ptr, hcl_oow
|
|||||||
}
|
}
|
||||||
|
|
||||||
HCL_ASSERT (hcl, HCL_IS_ARRAY(hcl, hcl->symtab->bucket));
|
HCL_ASSERT (hcl, HCL_IS_ARRAY(hcl, hcl->symtab->bucket));
|
||||||
index = hcl_hashoochars(ptr, len) % HCL_OBJ_GET_SIZE(hcl->symtab->bucket);
|
index = hcl_hash_oochars(ptr, len) % HCL_OBJ_GET_SIZE(hcl->symtab->bucket);
|
||||||
|
|
||||||
/* find a matching symbol in the open-addressed symbol table */
|
/* find a matching symbol in the open-addressed symbol table */
|
||||||
while (hcl->symtab->bucket->slot[index] != hcl->_nil)
|
while (hcl->symtab->bucket->slot[index] != hcl->_nil)
|
||||||
@ -153,7 +153,7 @@ static hcl_oop_t find_or_make_symbol (hcl_t* hcl, const hcl_ooch_t* ptr, hcl_oow
|
|||||||
hcl->symtab->bucket = bucket;
|
hcl->symtab->bucket = bucket;
|
||||||
|
|
||||||
/* recalculate the index for the expanded bucket */
|
/* recalculate the index for the expanded bucket */
|
||||||
index = hcl_hashoochars(ptr, len) % HCL_OBJ_GET_SIZE(hcl->symtab->bucket);
|
index = hcl_hash_oochars(ptr, len) % HCL_OBJ_GET_SIZE(hcl->symtab->bucket);
|
||||||
|
|
||||||
while (hcl->symtab->bucket->slot[index] != hcl->_nil)
|
while (hcl->symtab->bucket->slot[index] != hcl->_nil)
|
||||||
index = (index + 1) % HCL_OBJ_GET_SIZE(hcl->symtab->bucket);
|
index = (index + 1) % HCL_OBJ_GET_SIZE(hcl->symtab->bucket);
|
||||||
|
43
lib/utl.c
43
lib/utl.c
@ -35,48 +35,13 @@
|
|||||||
* utobcstr -> ucstr to bcstr
|
* utobcstr -> ucstr to bcstr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if HCL_SIZEOF_OOW_T == 4
|
hcl_oow_t hcl_hash_bytes_ (const hcl_oob_t* ptr, hcl_oow_t len)
|
||||||
# define FNV_MAGIC_INIT (0x811c9dc5)
|
|
||||||
# define FNV_MAGIC_PRIME (0x01000193)
|
|
||||||
#elif HCL_SIZEOF_OOW_T == 8
|
|
||||||
# define FNV_MAGIC_INIT (0xCBF29CE484222325)
|
|
||||||
# define FNV_MAGIC_PRIME (0x100000001B3)
|
|
||||||
#elif HCL_SIZEOF_OOW_T == 16
|
|
||||||
# define FNV_MAGIC_INIT (0x6C62272E07BB014262B821756295C58D)
|
|
||||||
# define FNV_MAGIC_PRIME (0x1000000000000000000013B)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
hcl_oow_t hcl_hash_bytes (const hcl_oob_t* ptr, hcl_oow_t len)
|
|
||||||
{
|
{
|
||||||
hcl_oow_t h;
|
hcl_oow_t hv;
|
||||||
const hcl_uint8_t* bp, * be;
|
HCL_HASH_BYTES (hv, ptr, len);
|
||||||
|
|
||||||
bp = ptr; be = bp + len;
|
|
||||||
|
|
||||||
/* this hash doesn't produce good distribution */
|
|
||||||
/*
|
|
||||||
h = 0
|
|
||||||
while (bp < be) h = h * 31 + *bp++;
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(FNV_MAGIC_INIT)
|
|
||||||
/* FNV-1 hash */
|
|
||||||
h = FNV_MAGIC_INIT;
|
|
||||||
while (bp < be)
|
|
||||||
{
|
|
||||||
h ^= (hcl_oow_t)(*bp++);
|
|
||||||
h *= FNV_MAGIC_PRIME;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* SDBM hash is known to produce good overall distribution
|
|
||||||
* for many different data sets */
|
|
||||||
h = 0;
|
|
||||||
while (bp < be) h = (h << 6) + (h << 16) - h + *bp++;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* constrain the hash value to be representable in a small integer
|
/* constrain the hash value to be representable in a small integer
|
||||||
* for convenience sake */
|
* for convenience sake */
|
||||||
return h % ((hcl_oow_t)HCL_SMOOI_MAX + 1);
|
return hv % ((hcl_oow_t)HCL_SMOOI_MAX + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hcl_equal_uchars (const hcl_uch_t* str1, const hcl_uch_t* str2, hcl_oow_t len)
|
int hcl_equal_uchars (const hcl_uch_t* str1, const hcl_uch_t* str2, hcl_oow_t len)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user