X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=hv.h;h=58e7d1da4e29e9ead5b2b4075d0ad445ea5a9a82;hb=055bb491aa1c61403cb7de2ea930a89a362e1807;hp=adb00c1a86b6d23d19f3c343873360899d57a854;hpb=463ee0b2acbd047c27e8b5393cdd8398881824c5;p=p5sagit%2Fp5-mst-13.2.git diff --git a/hv.h b/hv.h index adb00c1..58e7d1d 100644 --- a/hv.h +++ b/hv.h @@ -1,40 +1,38 @@ -/* $RCSfile: hash.h,v $$Revision: 4.1 $$Date: 92/08/07 18:21:52 $ +/* hv.h * - * Copyright (c) 1991, Larry Wall + * Copyright (c) 1991-2001, Larry Wall * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * - * $Log: hash.h,v $ - * Revision 4.1 92/08/07 18:21:52 lwall - * - * Revision 4.0.1.2 91/11/05 17:24:31 lwall - * patch11: random cleanup - * - * Revision 4.0.1.1 91/06/07 11:10:33 lwall - * patch4: new copyright notice - * - * Revision 4.0 91/03/20 01:22:38 lwall - * 4.0 baseline. - * */ +/* typedefs to eliminate some typing */ typedef struct he HE; +typedef struct hek HEK; +/* entry in hash value chain */ struct he { - HE *hent_next; - char *hent_key; - SV *hent_val; - U32 hent_hash; - I32 hent_klen; + HE *hent_next; /* next entry in chain */ + HEK *hent_hek; /* hash key */ + SV *hent_val; /* scalar value that was hashed */ }; +/* hash key -- defined separately for use as shared pointer */ +struct hek { + U32 hek_hash; /* hash of key */ + I32 hek_len; /* length of hash key */ + char hek_key[1]; /* variable-length hash key */ +}; + +/* hash structure: */ +/* This structure must match the beginning of struct xpvmg in sv.h. */ struct xpvhv { char * xhv_array; /* pointer to malloced string */ STRLEN xhv_fill; /* how full xhv_array currently is */ STRLEN xhv_max; /* subscript of last element of xhv_array */ - STRLEN xhv_keys; /* how many elements in the array */ - double xnv_nv; /* numeric value, if any */ + IV xhv_keys; /* how many elements in the array */ + NV xnv_nv; /* numeric value, if any */ MAGIC* xmg_magic; /* magic for scalar array */ HV* xmg_stash; /* class package */ @@ -44,8 +42,88 @@ struct xpvhv { char *xhv_name; /* name, if a symbol table */ }; +/* hash a key */ +/* FYI: This is the "One-at-a-Time" algorithm by Bob Jenkins */ +/* from requirements by Colin Plumb. */ +/* (http://burtleburtle.net/bob/hash/doobs.html) */ +#define PERL_HASH(hash,str,len) \ + STMT_START { \ + register const char *s_PeRlHaSh = str; \ + register I32 i_PeRlHaSh = len; \ + register U32 hash_PeRlHaSh = 0; \ + while (i_PeRlHaSh--) { \ + hash_PeRlHaSh += *s_PeRlHaSh++; \ + hash_PeRlHaSh += (hash_PeRlHaSh << 10); \ + hash_PeRlHaSh ^= (hash_PeRlHaSh >> 6); \ + } \ + hash_PeRlHaSh += (hash_PeRlHaSh << 3); \ + hash_PeRlHaSh ^= (hash_PeRlHaSh >> 11); \ + (hash) = (hash_PeRlHaSh + (hash_PeRlHaSh << 15)); \ + } STMT_END + +/* +=for apidoc AmU||HEf_SVKEY +This flag, used in the length slot of hash entries and magic structures, +specifies the structure contains a C pointer where a C pointer +is to be expected. (For information only--not to be used). + +=for apidoc AmU||Nullhv +Null HV pointer. + +=for apidoc Am|char*|HvNAME|HV* stash +Returns the package name of a stash. See C, C. + +=for apidoc Am|void*|HeKEY|HE* he +Returns the actual pointer stored in the key slot of the hash entry. The +pointer may be either C or C, depending on the value of +C. Can be assigned to. The C or C macros are +usually preferable for finding the value of a key. + +=for apidoc Am|STRLEN|HeKLEN|HE* he +If this is negative, and amounts to C, it indicates the entry +holds an C key. Otherwise, holds the actual length of the key. Can +be assigned to. The C macro is usually preferable for finding key +lengths. + +=for apidoc Am|SV*|HeVAL|HE* he +Returns the value slot (type C) stored in the hash entry. + +=for apidoc Am|U32|HeHASH|HE* he +Returns the computed hash stored in the hash entry. + +=for apidoc Am|char*|HePV|HE* he|STRLEN len +Returns the key slot of the hash entry as a C value, doing any +necessary dereferencing of possibly C keys. The length of the string +is placed in C (this is a macro, so do I use C<&len>). If you do +not care about what the length of the key is, you may use the global +variable C, though this is rather less efficient than using a local +variable. Remember though, that hash keys in perl are free to contain +embedded nulls, so using C or similar is not a good way to find +the length of hash keys. This is very similar to the C macro +described elsewhere in this document. + +=for apidoc Am|SV*|HeSVKEY|HE* he +Returns the key as an C, or C if the hash entry does not +contain an C key. + +=for apidoc Am|SV*|HeSVKEY_force|HE* he +Returns the key as an C. Will create and return a temporary mortal +C if the hash entry contains only a C key. + +=for apidoc Am|SV*|HeSVKEY_set|HE* he|SV* sv +Sets the key to a given C, taking care to set the appropriate flags to +indicate the presence of an C key, and returns the same +C. + +=cut +*/ + +/* these hash entry flags ride on hent_klen (for use only in magic/tied HVs) */ +#define HEf_SVKEY -2 /* hent_key is a SV* */ + + #define Nullhv Null(HV*) -#define HvARRAY(hv) ((HE**)((XPVHV*) SvANY(hv))->xhv_array) +#define HvARRAY(hv) (*(HE***)&((XPVHV*) SvANY(hv))->xhv_array) #define HvFILL(hv) ((XPVHV*) SvANY(hv))->xhv_fill #define HvMAX(hv) ((XPVHV*) SvANY(hv))->xhv_max #define HvKEYS(hv) ((XPVHV*) SvANY(hv))->xhv_keys @@ -53,3 +131,69 @@ struct xpvhv { #define HvEITER(hv) ((XPVHV*) SvANY(hv))->xhv_eiter #define HvPMROOT(hv) ((XPVHV*) SvANY(hv))->xhv_pmroot #define HvNAME(hv) ((XPVHV*) SvANY(hv))->xhv_name + +#define HvSHAREKEYS(hv) (SvFLAGS(hv) & SVphv_SHAREKEYS) +#define HvSHAREKEYS_on(hv) (SvFLAGS(hv) |= SVphv_SHAREKEYS) +#define HvSHAREKEYS_off(hv) (SvFLAGS(hv) &= ~SVphv_SHAREKEYS) + +#define HvLAZYDEL(hv) (SvFLAGS(hv) & SVphv_LAZYDEL) +#define HvLAZYDEL_on(hv) (SvFLAGS(hv) |= SVphv_LAZYDEL) +#define HvLAZYDEL_off(hv) (SvFLAGS(hv) &= ~SVphv_LAZYDEL) + +/* Maybe amagical: */ +/* #define HV_AMAGICmb(hv) (SvFLAGS(hv) & (SVpgv_badAM | SVpgv_AM)) */ + +#define HV_AMAGIC(hv) (SvFLAGS(hv) & SVpgv_AM) +#define HV_AMAGIC_on(hv) (SvFLAGS(hv) |= SVpgv_AM) +#define HV_AMAGIC_off(hv) (SvFLAGS(hv) &= ~SVpgv_AM) + +/* +#define HV_AMAGICbad(hv) (SvFLAGS(hv) & SVpgv_badAM) +#define HV_badAMAGIC_on(hv) (SvFLAGS(hv) |= SVpgv_badAM) +#define HV_badAMAGIC_off(hv) (SvFLAGS(hv) &= ~SVpgv_badAM) +*/ + +#define Nullhe Null(HE*) +#define HeNEXT(he) (he)->hent_next +#define HeKEY_hek(he) (he)->hent_hek +#define HeKEY(he) HEK_KEY(HeKEY_hek(he)) +#define HeKEY_sv(he) (*(SV**)HeKEY(he)) +#define HeKLEN(he) HEK_LEN(HeKEY_hek(he)) +#define HeKUTF8(he) HEK_UTF8(HeKEY_hek(he)) +#define HeKLEN_UTF8(he) (HeKUTF8(he) ? -HeKLEN(he) : HeKLEN(he)) +#define HeVAL(he) (he)->hent_val +#define HeHASH(he) HEK_HASH(HeKEY_hek(he)) +#define HePV(he,lp) ((HeKLEN(he) == HEf_SVKEY) ? \ + SvPV(HeKEY_sv(he),lp) : \ + (((lp = HeKLEN(he)) >= 0) ? \ + HeKEY(he) : Nullch)) + +#define HeSVKEY(he) ((HeKEY(he) && \ + HeKLEN(he) == HEf_SVKEY) ? \ + HeKEY_sv(he) : Nullsv) + +#define HeSVKEY_force(he) (HeKEY(he) ? \ + ((HeKLEN(he) == HEf_SVKEY) ? \ + HeKEY_sv(he) : \ + sv_2mortal(newSVpvn(HeKEY(he), \ + HeKLEN(he)))) : \ + &PL_sv_undef) +#define HeSVKEY_set(he,sv) ((HeKLEN(he) = HEf_SVKEY), (HeKEY_sv(he) = sv)) + +#define Nullhek Null(HEK*) +#define HEK_BASESIZE STRUCT_OFFSET(HEK, hek_key[0]) +#define HEK_HASH(hek) (hek)->hek_hash +#define HEK_LEN(hek) (hek)->hek_len +#define HEK_KEY(hek) (hek)->hek_key +#define HEK_UTF8(hek) (*(HEK_KEY(hek)+HEK_LEN(hek))) + +/* calculate HV array allocation */ +#if defined(STRANGE_MALLOC) || defined(MYMALLOC) +# define PERL_HV_ARRAY_ALLOC_BYTES(size) ((size) * sizeof(HE*)) +#else +# define MALLOC_OVERHEAD 16 +# define PERL_HV_ARRAY_ALLOC_BYTES(size) \ + (((size) < 64) \ + ? (size) * sizeof(HE*) \ + : (size) * sizeof(HE*) * 2 - MALLOC_OVERHEAD) +#endif