--- deliantra/server/include/shstr.h 2006/08/31 17:54:14 1.4
+++ deliantra/server/include/shstr.h 2010/03/26 01:04:44 1.38
@@ -1,101 +1,273 @@
+/*
+ * This file is part of Deliantra, the Roguelike Realtime MMORPG.
+ *
+ * Copyright (©) 2005,2006,2007,2008,2009,2010 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 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 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
+ */
+
#ifndef SHSTR_H__
#define SHSTR_H__
-//// OLD STUFF
+#include
+#include
-/* The size of the shared strings hashtable. This must be smaller than
- * 32767, but 947 ought to be plenty enough.
- */
-#define TABLESIZE 4133
+#include "traits.h"
-/* 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
-#endif
+extern size_t shstr_alloc;
-/* 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
+extern int buf_overflow (const char *buf1, const char *buf2, int bufsize);
-/* 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
+template
+struct shstr_vec
+{
+ uint32_t hash;
+ uint32_t len;
+ uint32_t refcnt;
+ // pointer points here
+ char string [size];
+};
-/* SS(string) will return the address of the shared_string struct which
- * contains "string".
- */
-#define SS(x) ((shared_string *) ((x) - offsetof(shared_string, string)))
+// this class is a non-refcounted shared string
+// it cannot be used to create or store shared strings, but
+// it can be used to pass 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 unsigned int &hash (const char *s)
+ {
+ return *((unsigned int *)s - 3);
+ }
+
+ int hash () const
+ {
+ return hash (s);
+ }
+
+ static unsigned int &length (const char *s)
+ {
+ return *((unsigned int *)s - 2);
+ }
+
+ int length () const
+ {
+ return length (s);
+ }
+
+ // 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);
+ }
+
+ // 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);
+ }
+
+ //TODO: case sensitive should be eradicated
+ bool eq_nc (const char *otherstring) const
+ {
+ return !strcasecmp (s, otherstring);
+ }
+
+ 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; }
+
+ operator const char *() const { return s == null () ? 0 : s; }
+
+protected:
+ // dummy is there so it isn't used as type converter accidentally
+ shstr_tmp (int dummy, const char *s)
+ : s(s)
+ {
+ }
+};
+
+inline bool operator ==(const shstr_tmp &a, const shstr_tmp &b)
+{
+ return a.s == b.s;
+}
-#define SS_STATISTICS
+inline bool operator !=(const shstr_tmp &a, const shstr_tmp &b)
+{
+ return a.s != b.s;
+}
-#define SS_DUMP_TABLE 1
-#define SS_DUMP_TOTALS 2
+inline int strlen (shstr_tmp sh)
+{
+ return sh.length ();
+}
-#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;
-
-extern void init_hash_table(void);
-extern const char *add_string(const char *str);
-extern const char *add_refcount(const char *str);
-extern int query_refcount(const char *str);
-extern const char *find_string(const char *str);
-extern void free_string(const char *str);
-extern void ss_dump_statistics(void);
-extern const char *ss_dump_table(int what);
-extern int buf_overflow(const char *buf1, const char *buf2, int bufsize);
+static inline std::ostream &operator <<(std::ostream &o, shstr_tmp sh)
+{
+ o.write (sh.s, sh.length ());
-//// NEW STUFF
+ return o;
+}
-#if 0
-struct shstr
+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;
- operator const char *() const { return s; };
- shstr &operator =(const char *str) { s = str; };
+
+ // initialies to the non-matching string (as opposed to the null string)
+ shstr_cmp ()
+ {
+ s = 0;
+ }
+
+ shstr_cmp (const char *str)
+ : s (shstr::find (str))
+ {
+ }
+
+ shstr_cmp (shstr_tmp sh)
+ : s (sh.s)
+ {
+ }
+
+ // this is used for informational messages and the like
+ const char *operator &() const { return s; }
+
+ operator const char *() const { return s; }
};
-#else
-typedef const char *shstr;
-#endif
+
+inline bool operator ==(const shstr_cmp &a, const shstr_tmp &b)
+{
+ return a.s == b.s;
+}
+
+inline bool operator ==(const shstr_tmp &a, const shstr_cmp &b)
+{
+ return a.s == b.s;
+}
+
+#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