public/sm_stringhashmap.h
author David Anderson <dvander@alliedmods.net>
Sun Aug 25 11:59:47 2013 -0700 (2013-08-25)
changeset 4066 c055944bdfd6
parent 4065 0f85577d23ee
child 4071 dbb9a3f48650
permissions -rw-r--r--
Switch smn_maplists off KTrie (bug 5884 part 4, r=ds).
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@4056
    50
#include <string.h>
dvander@4056
    51
dvander@4056
    52
namespace SourceMod
dvander@4056
    53
{
dvander@4056
    54
dvander@4056
    55
using namespace ke;
dvander@4056
    56
dvander@4056
    57
namespace detail
dvander@4056
    58
{
dvander@4056
    59
	class CharsAndLength
dvander@4056
    60
	{
dvander@4056
    61
	 public:
dvander@4056
    62
	  CharsAndLength(const char *str)
dvander@4056
    63
		: str_(str),
dvander@4056
    64
		  length_(0)
dvander@4056
    65
	  {
dvander@4056
    66
		  int c;
dvander@4056
    67
		  uint32_t hash = 0;
dvander@4056
    68
		  while ((c = *str++))
dvander@4056
    69
			  hash = c + (hash << 6) + (hash << 16) - hash;
dvander@4056
    70
		  hash_ = hash;
dvander@4056
    71
		  length_ = str - str_ - 1;
dvander@4056
    72
	  }
dvander@4056
    73
dvander@4056
    74
	  uint32_t hash() const {
dvander@4056
    75
		  return hash_;
dvander@4056
    76
	  }
dvander@4056
    77
	  const char *chars() const {
dvander@4056
    78
		  return str_;
dvander@4056
    79
	  }
dvander@4056
    80
	  size_t length() const {
dvander@4056
    81
		  return length_;
dvander@4056
    82
	  }
dvander@4056
    83
dvander@4056
    84
	 private:
dvander@4056
    85
	  const char *str_;
dvander@4056
    86
	  size_t length_;
dvander@4056
    87
	  uint32_t hash_;
dvander@4056
    88
	};
dvander@4056
    89
dvander@4056
    90
	struct StringHashMapPolicy
dvander@4056
    91
	{
dvander@4056
    92
		static inline bool matches(const CharsAndLength &lookup, const AString &key) {
dvander@4056
    93
			return lookup.length() == key.length() &&
dvander@4056
    94
				   memcmp(lookup.chars(), key.chars(), key.length()) == 0;
dvander@4056
    95
		}
dvander@4056
    96
		static inline uint32_t hash(const CharsAndLength &key) {
dvander@4056
    97
			return key.hash();
dvander@4056
    98
		}
dvander@4056
    99
	};
dvander@4056
   100
}
dvander@4056
   101
dvander@4056
   102
template <typename T>
dvander@4056
   103
class StringHashMap
dvander@4056
   104
{
dvander@4056
   105
	typedef detail::CharsAndLength CharsAndLength;
dvander@4056
   106
	typedef HashMap<AString, T, detail::StringHashMapPolicy> Internal;
dvander@4056
   107
dvander@4056
   108
public:
dvander@4056
   109
	StringHashMap()
dvander@4056
   110
		: internal_(SystemAllocatorPolicy()),
dvander@4056
   111
		  memory_used_(0)
dvander@4056
   112
	{
dvander@4056
   113
		if (!internal_.init())
dvander@4056
   114
			internal_.reportOutOfMemory();
dvander@4056
   115
	}
dvander@4056
   116
dvander@4058
   117
	typedef typename Internal::Result Result;
dvander@4058
   118
dvander@4056
   119
	// Some KTrie-like helper functions.
dvander@4056
   120
	bool retrieve(const char *aKey, T *aResult = NULL)
dvander@4056
   121
	{
dvander@4056
   122
		CharsAndLength key(aKey);
dvander@4065
   123
		Result r = internal_.find(key);
dvander@4056
   124
		if (!r.found())
dvander@4056
   125
			return false;
dvander@4056
   126
		if (aResult)
dvander@4056
   127
			*aResult = r->value;
dvander@4056
   128
		return true;
dvander@4056
   129
	}
dvander@4056
   130
dvander@4058
   131
	Result find(const char *aKey)
dvander@4058
   132
	{
dvander@4058
   133
		CharsAndLength key(aKey);
dvander@4058
   134
		return internal_.find(key);
dvander@4058
   135
	}
dvander@4058
   136
dvander@4056
   137
	bool contains(const char *aKey)
dvander@4056
   138
	{
dvander@4056
   139
		CharsAndLength key(aKey);
dvander@4065
   140
		Result r = internal_.find(key);
dvander@4056
   141
		return r.found();
dvander@4056
   142
	}
dvander@4056
   143
dvander@4056
   144
	bool replace(const char *aKey, const T &value)
dvander@4056
   145
	{
dvander@4056
   146
		CharsAndLength key(aKey);
dvander@4056
   147
		typename Internal::Insert i = internal_.findForAdd(key);
dvander@4056
   148
		if (!i.found())
dvander@4056
   149
		{
dvander@4056
   150
			memory_used_ += key.length() + 1;
dvander@4062
   151
			if (!internal_.add(i))
dvander@4058
   152
				return false;
dvander@4058
   153
			i->key = aKey;
dvander@4056
   154
		}
dvander@4056
   155
		i->value = value;
dvander@4056
   156
		return true;
dvander@4056
   157
	}
dvander@4056
   158
dvander@4056
   159
	bool insert(const char *aKey, const T &value)
dvander@4056
   160
	{
dvander@4056
   161
		CharsAndLength key(aKey);
dvander@4056
   162
		typename Internal::Insert i = internal_.findForAdd(key);
dvander@4056
   163
		if (i.found())
dvander@4056
   164
			return false;
dvander@4056
   165
		if (!internal_.add(i))
dvander@4056
   166
			return false;
dvander@4056
   167
		memory_used_ += key.length() + 1;
dvander@4056
   168
		i->key = aKey;
dvander@4056
   169
		i->value = value;
dvander@4056
   170
		return true;
dvander@4056
   171
	}
dvander@4056
   172
dvander@4056
   173
	bool remove(const char *aKey)
dvander@4056
   174
	{
dvander@4056
   175
		CharsAndLength key(aKey);
dvander@4065
   176
		Result r = internal_.find(key);
dvander@4056
   177
		if (!r.found())
dvander@4056
   178
			return false;
dvander@4056
   179
		memory_used_ -= key.length() + 1;
dvander@4056
   180
		internal_.remove(r);
dvander@4056
   181
		return true;
dvander@4056
   182
	}
dvander@4056
   183
dvander@4065
   184
	void remove(Result &r)
dvander@4065
   185
	{
dvander@4065
   186
		internal_.remove(r);
dvander@4065
   187
	}
dvander@4065
   188
dvander@4056
   189
	void clear()
dvander@4056
   190
	{
dvander@4056
   191
		internal_.clear();
dvander@4056
   192
	}
dvander@4056
   193
dvander@4056
   194
	size_t mem_usage() const {
dvander@4056
   195
		return internal_.estimateMemoryUse() + memory_used_;
dvander@4056
   196
	}
dvander@4056
   197
dvander@4056
   198
private:
dvander@4056
   199
	Internal internal_;
dvander@4056
   200
	size_t memory_used_;
dvander@4056
   201
};
dvander@4056
   202
dvander@4056
   203
}
dvander@4056
   204
dvander@4056
   205
#endif // _include_sourcemod_hashtable_h_