public/sm_stringhashmap.h
author Ruben Gonzalez <drifter01620@gmail.com>
Thu Feb 13 12:12:36 2014 -0500 (2014-02-13)
changeset 4251 9290c598d3cb
parent 4096 1ed7fe4e8f7e
permissions -rw-r--r--
Update CSSDM gdc patch bytes (NPOTB)
dvander@4056
     1
/**
dvander@4056
     2
 * vim: set ts=4 sw=4 tw=99 noet :
dvander@4056
     3
 * =============================================================================
dvander@4056
     4
 * SourceMod
dvander@4056
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@4056
     6
 * =============================================================================
dvander@4056
     7
 *
dvander@4056
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@4056
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@4056
    10
 * Free Software Foundation.
dvander@4056
    11
 * 
dvander@4056
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@4056
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@4056
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@4056
    15
 * details.
dvander@4056
    16
 *
dvander@4056
    17
 * You should have received a copy of the GNU General Public License along with
dvander@4056
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@4056
    19
 *
dvander@4056
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@4056
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@4056
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@4056
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@4056
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@4056
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@4056
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@4056
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@4056
    28
 *
dvander@4056
    29
 * Version: $Id$
dvander@4056
    30
 */
dvander@4056
    31
dvander@4056
    32
#ifndef _include_sourcemod_hashtable_h_
dvander@4056
    33
#define _include_sourcemod_hashtable_h_
dvander@4056
    34
dvander@4058
    35
/**
dvander@4058
    36
 * @file sm_stringhashmap.h
dvander@4058
    37
 *
dvander@4058
    38
 * @brief Generic Key -> Value map class, based on a hash table. The Key, in
dvander@4058
    39
 * this case, is always an ASCII string, and the value type is a template
dvander@4058
    40
 * parameter. This class is intended as a drop-in replacement for KTrie
dvander@4058
    41
 * (though the retrieve() signature has been improved).
dvander@4058
    42
 *
dvander@4058
    43
 * If your Value type already contains the key string, consider using
dvander@4058
    44
 * NameHashSet instead.
dvander@4058
    45
 */
dvander@4058
    46
dvander@4056
    47
#include <am-allocator-policies.h>
dvander@4056
    48
#include <am-hashmap.h>
dvander@4056
    49
#include <am-string.h>
dvander@4096
    50
#include <am-moveable.h>
dvander@4056
    51
#include <string.h>
dvander@4056
    52
dvander@4056
    53
namespace SourceMod
dvander@4056
    54
{
dvander@4056
    55
dvander@4056
    56
namespace detail
dvander@4056
    57
{
dvander@4056
    58
	class CharsAndLength
dvander@4056
    59
	{
dvander@4056
    60
	 public:
dvander@4056
    61
	  CharsAndLength(const char *str)
dvander@4056
    62
		: str_(str),
dvander@4056
    63
		  length_(0)
dvander@4056
    64
	  {
dvander@4056
    65
		  int c;
dvander@4056
    66
		  uint32_t hash = 0;
dvander@4056
    67
		  while ((c = *str++))
dvander@4056
    68
			  hash = c + (hash << 6) + (hash << 16) - hash;
dvander@4056
    69
		  hash_ = hash;
dvander@4056
    70
		  length_ = str - str_ - 1;
dvander@4056
    71
	  }
dvander@4056
    72
dvander@4056
    73
	  uint32_t hash() const {
dvander@4056
    74
		  return hash_;
dvander@4056
    75
	  }
dvander@4056
    76
	  const char *chars() const {
dvander@4056
    77
		  return str_;
dvander@4056
    78
	  }
dvander@4056
    79
	  size_t length() const {
dvander@4056
    80
		  return length_;
dvander@4056
    81
	  }
dvander@4056
    82
dvander@4056
    83
	 private:
dvander@4056
    84
	  const char *str_;
dvander@4056
    85
	  size_t length_;
dvander@4056
    86
	  uint32_t hash_;
dvander@4056
    87
	};
dvander@4056
    88
dvander@4056
    89
	struct StringHashMapPolicy
dvander@4056
    90
	{
dvander@4080
    91
		static inline bool matches(const CharsAndLength &lookup, const ke::AString &key) {
dvander@4056
    92
			return lookup.length() == key.length() &&
dvander@4056
    93
				   memcmp(lookup.chars(), key.chars(), key.length()) == 0;
dvander@4056
    94
		}
dvander@4056
    95
		static inline uint32_t hash(const CharsAndLength &key) {
dvander@4056
    96
			return key.hash();
dvander@4056
    97
		}
dvander@4056
    98
	};
dvander@4056
    99
}
dvander@4056
   100
dvander@4056
   101
template <typename T>
dvander@4056
   102
class StringHashMap
dvander@4056
   103
{
dvander@4056
   104
	typedef detail::CharsAndLength CharsAndLength;
dvander@4080
   105
	typedef ke::HashMap<ke::AString, T, detail::StringHashMapPolicy> Internal;
dvander@4056
   106
dvander@4056
   107
public:
dvander@4056
   108
	StringHashMap()
dvander@4080
   109
		: internal_(ke::SystemAllocatorPolicy()),
dvander@4056
   110
		  memory_used_(0)
dvander@4056
   111
	{
dvander@4056
   112
		if (!internal_.init())
dvander@4056
   113
			internal_.reportOutOfMemory();
dvander@4056
   114
	}
dvander@4056
   115
dvander@4058
   116
	typedef typename Internal::Result Result;
dvander@4096
   117
	typedef typename Internal::Insert Insert;
dvander@4071
   118
	typedef typename Internal::iterator iterator;
dvander@4058
   119
dvander@4056
   120
	// Some KTrie-like helper functions.
dvander@4056
   121
	bool retrieve(const char *aKey, T *aResult = NULL)
dvander@4056
   122
	{
dvander@4056
   123
		CharsAndLength key(aKey);
dvander@4065
   124
		Result r = internal_.find(key);
dvander@4056
   125
		if (!r.found())
dvander@4056
   126
			return false;
dvander@4056
   127
		if (aResult)
dvander@4056
   128
			*aResult = r->value;
dvander@4056
   129
		return true;
dvander@4056
   130
	}
dvander@4056
   131
dvander@4058
   132
	Result find(const char *aKey)
dvander@4058
   133
	{
dvander@4058
   134
		CharsAndLength key(aKey);
dvander@4058
   135
		return internal_.find(key);
dvander@4058
   136
	}
dvander@4058
   137
dvander@4056
   138
	bool contains(const char *aKey)
dvander@4056
   139
	{
dvander@4056
   140
		CharsAndLength key(aKey);
dvander@4065
   141
		Result r = internal_.find(key);
dvander@4056
   142
		return r.found();
dvander@4056
   143
	}
dvander@4056
   144
dvander@4056
   145
	bool replace(const char *aKey, const T &value)
dvander@4056
   146
	{
dvander@4056
   147
		CharsAndLength key(aKey);
dvander@4096
   148
		Insert i = internal_.findForAdd(key);
dvander@4056
   149
		if (!i.found())
dvander@4056
   150
		{
dvander@4056
   151
			memory_used_ += key.length() + 1;
dvander@4062
   152
			if (!internal_.add(i))
dvander@4058
   153
				return false;
dvander@4058
   154
			i->key = aKey;
dvander@4056
   155
		}
dvander@4056
   156
		i->value = value;
dvander@4056
   157
		return true;
dvander@4056
   158
	}
dvander@4056
   159
dvander@4056
   160
	bool insert(const char *aKey, const T &value)
dvander@4056
   161
	{
dvander@4056
   162
		CharsAndLength key(aKey);
dvander@4096
   163
		Insert i = internal_.findForAdd(key);
dvander@4056
   164
		if (i.found())
dvander@4056
   165
			return false;
dvander@4056
   166
		if (!internal_.add(i))
dvander@4056
   167
			return false;
dvander@4056
   168
		memory_used_ += key.length() + 1;
dvander@4056
   169
		i->key = aKey;
dvander@4056
   170
		i->value = value;
dvander@4056
   171
		return true;
dvander@4056
   172
	}
dvander@4056
   173
dvander@4056
   174
	bool remove(const char *aKey)
dvander@4056
   175
	{
dvander@4056
   176
		CharsAndLength key(aKey);
dvander@4065
   177
		Result r = internal_.find(key);
dvander@4056
   178
		if (!r.found())
dvander@4056
   179
			return false;
dvander@4056
   180
		memory_used_ -= key.length() + 1;
dvander@4056
   181
		internal_.remove(r);
dvander@4056
   182
		return true;
dvander@4056
   183
	}
dvander@4056
   184
dvander@4065
   185
	void remove(Result &r)
dvander@4065
   186
	{
dvander@4065
   187
		internal_.remove(r);
dvander@4065
   188
	}
dvander@4065
   189
dvander@4056
   190
	void clear()
dvander@4056
   191
	{
dvander@4056
   192
		internal_.clear();
dvander@4056
   193
	}
dvander@4056
   194
dvander@4096
   195
	iterator iter()
dvander@4096
   196
	{
dvander@4071
   197
		return internal_.iter();
dvander@4071
   198
	}
dvander@4071
   199
dvander@4096
   200
	size_t mem_usage() const
dvander@4096
   201
	{
dvander@4056
   202
		return internal_.estimateMemoryUse() + memory_used_;
dvander@4056
   203
	}
dvander@4056
   204
dvander@4096
   205
	size_t elements() const
dvander@4096
   206
	{
dvander@4096
   207
		return internal_.elements();
dvander@4096
   208
	}
dvander@4096
   209
dvander@4096
   210
dvander@4096
   211
	Insert findForAdd(const char *aKey)
dvander@4096
   212
	{
dvander@4096
   213
		CharsAndLength key(aKey);
dvander@4096
   214
		return internal_.findForAdd(key);
dvander@4096
   215
	}
dvander@4096
   216
dvander@4096
   217
	// Note that |i->key| must be set after calling this, and the key must
dvander@4096
   218
	// be the same as used with findForAdd(). It is best to avoid these two
dvander@4096
   219
	// functions as the combined variants above are safer.
dvander@4096
   220
	bool add(Insert &i)
dvander@4096
   221
	{
dvander@4096
   222
		return internal_.add(i);
dvander@4096
   223
	}
dvander@4096
   224
dvander@4096
   225
	// Only value needs to be set after.
dvander@4096
   226
	bool add(Insert &i, const char *aKey)
dvander@4096
   227
	{
dvander@4096
   228
		if (!internal_.add(i))
dvander@4096
   229
			return false;
dvander@4096
   230
		i->key = aKey;
dvander@4096
   231
		return true;
dvander@4096
   232
	}
dvander@4096
   233
dvander@4056
   234
private:
dvander@4056
   235
	Internal internal_;
dvander@4056
   236
	size_t memory_used_;
dvander@4056
   237
};
dvander@4056
   238
dvander@4056
   239
}
dvander@4056
   240
dvander@4056
   241
#endif // _include_sourcemod_hashtable_h_