--- deliantra/server/include/shstr.h 2006/02/03 07:12:50 1.1 +++ deliantra/server/include/shstr.h 2007/05/14 21:52:32 1.15 @@ -1,70 +1,164 @@ -/* The size of the shared strings hashtable. This must be smaller than - * 32767, but 947 ought to be plenty enough. - */ -#define TABLESIZE 4133 - -/* This specifies how many characters the hashing routine should look at. - * You may actually save CPU by increasing this number if the typical string - * is large. - */ -#ifndef MAXSTRING -#define MAXSTRING 20 +#ifndef SHSTR_H__ +#define SHSTR_H__ + +#include + +#include "util.h" + +extern int buf_overflow (const char *buf1, const char *buf2, int bufsize); + +struct shstr +{ + static const char *null; + + const char *s; + + static int &refcnt (const char *s) + { + return *((int *)s - 1); + } + + static int &length (const char *s) + { + return *((int *)s - 2); + } + + int &refcnt () const + { + return refcnt (s); + } + + int length () const + { + return length (s); + } + + // returns wether this shared string begins with the given prefix, + // used mainly for searched when users give only the start of a name. + bool begins_with (const char *prefix) const + { + int plen = strlen (prefix); + return !strncasecmp (s, prefix, plen) && length () >= plen; + } + + static const char *find (const char *s); + static const char *intern (const char *s); + + static void gc (); // garbage collect a few strings + + // this is used for informational messages and the like + const char *operator &() const { return s; } + + const char &operator [](int i) const { return s[i]; } + operator const char *() const { return s == null ? 0 : s; } + + shstr () + : s (null) + { + } + + shstr (const shstr &sh) + : s (sh.s) + { + ++refcnt (); + } + + explicit shstr (const char *s) + : s (intern (s)) + { + } + + ~shstr () + { + --refcnt (); + } + + const shstr &operator =(const shstr &sh) + { + --refcnt (); + s = sh.s; + ++refcnt (); + + return *this; + } + + const shstr &operator =(const char *str) + { + --refcnt (); + + // this optimises the important case of str == constant 0 + if (is_constant (str)) + s = str ? intern (str) : null; + else + s = intern (str); + + return *this; + } + + bool operator ==(const shstr &b) + { + return s == b.s; + } + + bool operator !=(const shstr &b) + { + return !(*this == b); + } +}; + +inline int strlen (const shstr &sh) +{ + return sh.length (); +} + +inline int strcmp (const shstr &a, const shstr &b) +{ + // TODO: use this to find all the occurences of people using strcmp + // all uses should be bogus, as we should be never interested in + // comparing shstr's alphabetically +#if 0 + extern void do_not_use_strcmp_to_compare_shstr_values (); + do_not_use_strcmp_to_compare_shstr_values (); #endif + return a != b; +} + +static std::ostream &operator <<(std::ostream &o, const shstr &sh) +{ + o.write (sh.s, sh.length ()); + return o; +} + +// only good for mass comparisons to shstr objects +struct shstr_cmp +{ + const char *s; + + explicit shstr_cmp (const char *s) + : s (shstr::find (s)) + { + } + + shstr_cmp (const shstr_cmp &sh) + : s (sh.s) + { + } + + shstr_cmp &operator =(const shstr_cmp sh) { s = sh.s; return *this; } + operator const char *() const { return s; } +}; + +inline bool operator ==(const shstr_cmp &a, const shstr &b) +{ + return a.s == b.s; +} + +inline bool operator ==(const shstr &a, const shstr_cmp &b) +{ + return b == a; +} + +extern const shstr undead_name; /* Used in hit_player() in main.c */ -/* In the unlikely occurence that 16383 references to a string are too - * few, you can modify the below type to something bigger. - * (The top bit of "refcount" is used to signify that "u.array" points - * at the array entry.) - */ -#define REFCOUNT_TYPE int - -/* The offsetof macro is part of ANSI C, but many compilers lack it, for - * example "gcc -ansi" - */ -#if !defined (offsetof) -#define offsetof(type, member) (int)&(((type *)0)->member) #endif -/* SS(string) will return the address of the shared_string struct which - * contains "string". - */ -#define SS(x) ((shared_string *) ((x) - offsetof(shared_string, string))) - -#define SS_STATISTICS - -#define SS_DUMP_TABLE 1 -#define SS_DUMP_TOTALS 2 - -#ifdef SS_STATISTICS -static struct statistics { - int calls; - int hashed; - int strcmps; - int search; - int linked; -} add_stats, add_ref_stats, free_stats, find_stats, hash_stats; -#define GATHER(n) (++n) -#else /* !SS_STATISTICS */ -#define GATHER(n) -#endif /* SS_STATISTICS */ - -#define TOPBIT ((unsigned REFCOUNT_TYPE) 1 << (sizeof(REFCOUNT_TYPE) * CHAR_BIT - 1)) - -#define PADDING ((2 * sizeof(long) - sizeof(REFCOUNT_TYPE)) % sizeof(long)) + 1 - -typedef struct _shared_string { - union { - struct _shared_string **array; - struct _shared_string *previous; - } u; - struct _shared_string *next; - /* The top bit of "refcount" is used to signify that "u.array" points - * at the array entry. - */ - unsigned REFCOUNT_TYPE refcount; - /* Padding will be unused memory, since we can't know how large - * the padding when allocating memory. We assume here that - * sizeof(long) is a good boundary. - */ - char string[PADDING]; -} shared_string;