--- deliantra/server/include/shstr.h 2008/12/28 06:59:27 1.23 +++ deliantra/server/include/shstr.h 2009/11/10 00:01:31 1.36 @@ -1,20 +1,21 @@ /* * This file is part of Deliantra, the Roguelike Realtime MMORPG. * - * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team + * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * - * Deliantra is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Deliantra is free software: you can redistribute it and/or modify it under + * the terms of the Affero GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the Affero GNU General Public License + * and the GNU General Public License along with this program. If not, see + * . * * The authors can be reached via e-mail to */ @@ -22,33 +23,50 @@ #ifndef SHSTR_H__ #define SHSTR_H__ +#include #include -#include "util.h" +#include "traits.h" extern size_t shstr_alloc; extern int buf_overflow (const char *buf1, const char *buf2, int bufsize); -struct shstr +template +struct shstr_vec { - static const char *null; + uint32_t hash; + uint32_t len; + uint32_t refcnt; + // pointer points here + char string [size]; +}; + +// this class is a non-refcounted shared string +// it cannot be used to create or store shared strings, but +// it can be used to apss shared strings around, i.e. as function arguments +// or return values. their lifetime must not span a gc () call, i.e. +// they are only valid as temporary values within the same server tick. +struct shstr_tmp +{ + static shstr_vec nullvec; + static const char *null () { return nullvec.string; } // this is the null pointer value const char *s; - static int &refcnt (const char *s) + static unsigned int &hash (const char *s) { - return *((int *)s - 1); + return *((unsigned int *)s - 3); } - static int &length (const char *s) + int hash () const { - return *((int *)s - 2); + return hash (s); } - int &refcnt () const + static unsigned int &length (const char *s) { - return refcnt (s); + return *((unsigned int *)s - 2); } int length () const @@ -56,118 +74,171 @@ 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 + // returns whether this shared string begins with the given prefix, + // used mainly for searches when users give only the start of a name. + bool starts_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; } + return length () >= plen && !strncasecmp (s, prefix, plen); + } - shstr () - : s (null) + // returns true if the substring is contained in the shstr + // if the shstr is 0, then this always returns false. + // the shstr is (theoretically) treated as a comma/colon/space etc. separated list. + bool contains (const char *substring) const { + return s != null () && strstr (s, substring); } - shstr (const shstr &sh) - : s (sh.s) + //TODO: case sensitive should be eradicated + bool eq_nc (const char *otherstring) const { - ++refcnt (); + return !strcasecmp (s, otherstring); } - explicit shstr (const char *s) - : s (intern (s)) + shstr_tmp () + : s (null ()) { } - ~shstr () + shstr_tmp (const shstr_tmp &sh) + : s (sh.s) { - --refcnt (); } - const shstr &operator =(const shstr &sh) + shstr_tmp operator =(const shstr_tmp &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); + // this is used for informational messages and the like + const char *operator &() const { return s; } - return *this; - } + operator const char *() const { return s == null () ? 0 : s; } - bool operator !=(const shstr &b) +protected: + // dummy is there so it isn't used as type converter accidentally + shstr_tmp (int dummy, const char *s) + : s(s) { - return !(*this == b); } }; -inline bool operator ==(const shstr &a, const shstr &b) +inline bool operator ==(const shstr_tmp &a, const shstr_tmp &b) { return a.s == b.s; } -inline int strlen (const shstr &sh) +inline bool operator !=(const shstr_tmp &a, const shstr_tmp &b) { - return sh.length (); + return a.s != b.s; } -inline int strcmp (const shstr &a, const shstr &b) +inline int strlen (shstr_tmp sh) { - // 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; + return sh.length (); } -static std::ostream &operator <<(std::ostream &o, const shstr &sh) +static inline std::ostream &operator <<(std::ostream &o, shstr_tmp sh) { o.write (sh.s, sh.length ()); + return o; } -// only good for mass comparisons to shstr objects +struct shstr : shstr_tmp +{ + static unsigned int &refcnt (const char *s) + { + return *((unsigned int *)s - 1); + } + + unsigned int &refcnt () const + { + return refcnt (s); + } + + shstr () + { + } + + static const char *find (const char *s); + static const char *intern (const char *s); + + static void gc (); // garbage collect a few strings + + shstr (const shstr &sh) + : shstr_tmp (sh) + { + ++refcnt (); + } + + shstr (const shstr_tmp &sh) + : shstr_tmp (sh) + { + ++refcnt (); + } + + explicit shstr (const char *str) + : shstr_tmp (0, is_constant (str) && !str ? null () : intern (str)) + { + } + + ~shstr () + { + --refcnt (); + } + + using shstr_tmp::operator &; + using shstr_tmp::operator const char *; + + // (note: not the copy constructor) + shstr &operator =(const shstr_tmp &sh) + { + --refcnt (); + s = sh.s; + ++refcnt (); + + return *this; + } + + // here it comes + shstr &operator =(const shstr &sh) + { + return (*this) = (shstr_tmp)sh; + } + + // shstr_tmp doesn't have this one + shstr &operator =(const char *str) + { + --refcnt (); + s = is_constant (str) && !str ? null () : intern (str); + + return *this; + } +}; + +// only good for mass comparisons to shstr objects, or very +// temporary passing, basically a non-refcounted shstr struct shstr_cmp { const char *s; - explicit shstr_cmp (const char *s) - : s (shstr::find (s)) + // initialies to the non-matching string (as opposed to the null string) + shstr_cmp () { + s = 0; } - shstr_cmp (const shstr_cmp &sh) - : s (sh.s) + shstr_cmp (const char *str) + : s (shstr::find (str)) { } - shstr_cmp (const shstr &sh) + shstr_cmp (shstr_tmp sh) : s (sh.s) { } @@ -175,25 +246,28 @@ // this is used for informational messages and the like const char *operator &() const { return 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) +inline bool operator ==(const shstr_cmp &a, const shstr_tmp &b) { return a.s == b.s; } -inline bool operator ==(const shstr &a, const shstr_cmp &b) +inline bool operator ==(const shstr_tmp &a, const shstr_cmp &b) { - return b == a; + return a.s == b.s; } -extern const shstr shstr_null; - -#define def(str) extern const shstr shstr_ ## str; +#define def2(id,str) extern const shstr id; +#define def(id) def2(shstr_ ## id, # id) # include "shstrinc.h" #undef def +#undef def2 + +// undefined external reference to catch people using str* functions when they shouldn't +//template void strcmp (const shstr_tmp &a, any b); +template void strstr (const shstr_tmp &a, any b); #endif