--- deliantra/server/include/shstr.h 2006/09/03 07:57:56 1.6 +++ deliantra/server/include/shstr.h 2008/12/31 17:35:37 1.24 @@ -1,87 +1,234 @@ +/* + * This file is part of Deliantra, the Roguelike Realtime MMORPG. + * + * Copyright (©) 2005,2006,2007,2008 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. + * + * 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 . + * + * The authors can be reached via e-mail to + */ + #ifndef SHSTR_H__ #define SHSTR_H__ -extern int buf_overflow(const char *buf1, const char *buf2, int bufsize); +#include +#include + +#include "util.h" + +extern size_t shstr_alloc; -struct shstr +extern int buf_overflow (const char *buf1, const char *buf2, int bufsize); + +// 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 const char *null; + const char *s; - int &refcnt () + static unsigned int &length (const char *s) { - return *((int *)s - 1); + return *((unsigned int *)s - 2); } - static const char *find (const char *s); - static const char *intern (const char *s); + int length () const + { + return length (s); + } - static void gc (); // garbage collect a few strings + // 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 length () >= plen && !strncasecmp (s, prefix, plen); + } + + bool contains (const char *substring) const + { + return strstr (s, substring); + } + + shstr_tmp () + : s (null) + { + } + + shstr_tmp (const shstr_tmp &sh) + : s (sh.s) + { + } + + shstr_tmp operator =(const shstr_tmp &sh) + { + s = sh.s; + + return *this; + } // this is used for informational messages and the like - const char *operator &() const { return s ? s : ""; } + const char *operator &() const { return s; } - const char &operator [](int i) const { return s[i]; } - operator const char *() const { return s; } + operator const char *() const { return s == null ? 0 : s; } +}; - int length () const +inline bool operator ==(const shstr_tmp &a, const shstr_tmp &b) +{ + return a.s == b.s; +} + +inline bool operator !=(const shstr_tmp &a, const shstr_tmp &b) +{ + return a.s != b.s; +} + +inline int strlen (const shstr_tmp &sh) +{ + return sh.length (); +} + +// undefined external reference to catch people using strcmp when they shouldn't +int strcmp (const shstr_tmp &a, const shstr_tmp &b); + +static std::ostream &operator <<(std::ostream &o, shstr_tmp sh) +{ + o.write (sh.s, sh.length ()); + + return o; +} + +struct shstr : shstr_tmp +{ + static unsigned int &refcnt (const char *s) { - return s ? *((int *)s - 2) : 0; + return *((unsigned int *)s - 1); + } + + unsigned int &refcnt () const + { + return refcnt (s); } shstr () - : s (0) { } + 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) - : s (sh.s) + : shstr_tmp (sh) { - if (s) ++refcnt (); + ++refcnt (); } - explicit shstr (const char *s) - : s (intern (s)) + shstr (const shstr_tmp &sh) + : shstr_tmp (sh) { - if (s) ++refcnt (); + ++refcnt (); + } + + explicit shstr (const char *str) + { + s = is_constant (str) && !str ? null : intern (str); } ~shstr () { - if (s) --refcnt (); + --refcnt (); } - const shstr &operator =(const shstr &sh) + using shstr_tmp::operator &; + using shstr_tmp::operator const char *; + + // (note: not the copy constructor) + shstr &operator =(const shstr_tmp &sh) { - if (s) --refcnt (); + --refcnt (); s = sh.s; - if (s) ++refcnt (); + ++refcnt (); return *this; } - const shstr &operator =(const char *str) + // 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) { - if (s) --refcnt (); - s = intern (str); + --refcnt (); + s = is_constant (str) && !str ? null : intern (str); return *this; } }; -inline int strlen (const shstr &sh) +// only good for mass comparisons to shstr objects, or very +// temporary passing, basically a non-refcounted shstr +struct shstr_cmp { - return sh.length (); -} + const char *s; + + explicit shstr_cmp (const char *str) + : s (shstr::find (str)) + { + } + + shstr_cmp (const shstr_cmp &sh) + : s (sh.s) + { + } + + shstr_cmp (const shstr &sh) + : s (sh.s) + { + } -inline bool operator ==(const shstr &a, const shstr &b) + // 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_tmp &b) { return a.s == b.s; } -inline bool operator !=(const shstr &a, const shstr &b) +inline bool operator ==(const shstr_tmp &a, const shstr_cmp &b) { - return !(a == b); + return a.s == b.s; } +extern const shstr shstr_null; + +#define def(str) extern const shstr shstr_ ## str; +# include "shstrinc.h" +#undef def + #endif