forked from hitmen047/Source-PlusPlus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutlcommon.h
345 lines (283 loc) · 14.9 KB
/
utlcommon.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: common helpers for reuse among various Utl containers
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef UTLCOMMON_H
#define UTLCOMMON_H
#pragma once
//-----------------------------------------------------------------------------
// Henry Goffin (henryg) was here. Questions? Bugs? Go slap him around a bit.
//-----------------------------------------------------------------------------
// empty_t is the canonical "no-value" type which is fully defined but empty.
struct empty_t {};
// undefined_t is the canonical "undefined" type, used mostly for typedefs;
// parameters of type undefined_t will not compile, which is actually useful
// behavior when it comes to template programming. Google "SFINAE" for info.
struct undefined_t;
// CTypeSelect<sel,A,B>::type is a typedef of A if sel is nonzero, else B
template <int sel, typename A, typename B>
struct CTypeSelect { typedef A type; };
template <typename A, typename B>
struct CTypeSelect<0, A, B> { typedef B type; };
// CTypeEquals<A, B>::value is nonzero if A and B are the same type
template <typename A, typename B, bool bIgnoreConstVolatile = false, bool bIgnoreReference = false>
struct CTypeEquals { enum { value = 0 }; };
template <typename Same>
struct CTypeEquals<Same, Same, false, false> { enum { value = 1 }; };
template <typename A, typename B>
struct CTypeEquals<A, B, true, true> : CTypeEquals< const volatile A&, const volatile B& > {};
template <typename A, typename B>
struct CTypeEquals<A, B, true, false> : CTypeEquals< const volatile A, const volatile B > {};
template <typename A, typename B>
struct CTypeEquals<A, B, false, true> : CTypeEquals< A&, B& > {};
// CUtlKeyValuePair is intended for use with key-lookup containers.
// Because it is specialized for "empty_t" values, one container can
// function as either a set of keys OR a key-value dictionary while
// avoiding storage waste or padding for the empty_t value objects.
template <typename K, typename V>
class CUtlKeyValuePair
{
public:
typedef V ValueReturn_t;
K m_key;
V m_value;
CUtlKeyValuePair() {}
template < typename KInit >
explicit CUtlKeyValuePair( const KInit &k ) : m_key( k ) {}
template < typename KInit, typename VInit >
CUtlKeyValuePair( const KInit &k, const VInit &v ) : m_key( k ), m_value( v ) {}
V &GetValue() { return m_value; }
const V &GetValue() const { return m_value; }
};
template <typename K>
class CUtlKeyValuePair<K, empty_t>
{
public:
typedef const K ValueReturn_t;
K m_key;
CUtlKeyValuePair() {}
template < typename KInit >
explicit CUtlKeyValuePair( const KInit &k ) : m_key( k ) {}
template < typename KInit >
CUtlKeyValuePair( const KInit &k, empty_t ) : m_key( k ) {}
CUtlKeyValuePair( const K &k, const empty_t& ) : m_key( k ) {}
const K &GetValue() const { return m_key; }
};
// Default functors. You can specialize these if your type does
// not implement operator== or operator< in an efficient way for
// some odd reason.
template <typename T> struct DefaultLessFunctor;
template <typename T> struct DefaultEqualFunctor;
// Hashing functor used by hash tables. You can either specialize
// for types which are widely used, or plug a custom functor directly
// into the hash table. If you do roll your own, please read up on
// bit-mixing and the avalanche property; be sure that your values
// are reasonably well-distributed across the entire 32-bit range.
// http://en.wikipedia.org/wiki/Avalanche_effect
// http://home.comcast.net/~bretm/hash/5.html
//
template <typename T> struct DefaultHashFunctor;
// Argument type information. Struct currently contains one or two typedefs:
// typename Arg_t = primary argument type. Usually const T&, sometimes T.
// typename Alt_t = optional alternate type. Usually *undefined*.
//
// Any specializations should be implemented via simple inheritance
// from ArgumentTypeInfoImpl< BestArgType, [optional] AlternateArgType >
//
template <typename T> struct ArgumentTypeInfo;
// Some fundamental building-block functors...
struct StringLessFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcmp( a, b ) < 0; } };
struct StringEqualFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcmp( a, b ) == 0; } };
struct CaselessStringLessFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcasecmp( a, b ) < 0; } };
struct CaselessStringEqualFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcasecmp( a, b ) == 0; } };
struct Mix32HashFunctor { unsigned int operator()( uint32 s ) const; };
struct StringHashFunctor { unsigned int operator()( const char* s ) const; };
struct CaselessStringHashFunctor { unsigned int operator()( const char* s ) const; };
struct PointerLessFunctor { bool operator()( const void *a, const void *b ) const { return a < b; } };
struct PointerEqualFunctor { bool operator()( const void *a, const void *b ) const { return a == b; } };
struct PointerHashFunctor { unsigned int operator()( const void* s ) const { return Mix32HashFunctor()((uint32)POINTER_TO_INT(s)); } };
// Generic implementation of Less and Equal functors
template < typename T >
struct DefaultLessFunctor
{
bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a < b; }
bool operator()( typename ArgumentTypeInfo< T >::Alt_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a < b; }
bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Alt_t b ) const { return a < b; }
};
template < typename T >
struct DefaultEqualFunctor
{
bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a == b; }
bool operator()( typename ArgumentTypeInfo< T >::Alt_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a == b; }
bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Alt_t b ) const { return a == b; }
};
// Hashes for basic types
template <> struct DefaultHashFunctor<char> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<signed char> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<unsigned char> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<signed short> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<unsigned short> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<signed int> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<unsigned int> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<signed long> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<unsigned long> : Mix32HashFunctor { };
template <> struct DefaultHashFunctor<void*> : PointerHashFunctor { };
template <> struct DefaultHashFunctor<const void*> : PointerHashFunctor { };
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template <> struct DefaultHashFunctor<wchar_t> : Mix32HashFunctor { };
#endif
// String specializations. If you want to operate on raw values, use
// PointerLessFunctor and friends from the "building-block" section above
template <> struct DefaultLessFunctor<char*> : StringLessFunctor { };
template <> struct DefaultLessFunctor<const char*> : StringLessFunctor { };
template <> struct DefaultEqualFunctor<char*> : StringEqualFunctor { };
template <> struct DefaultEqualFunctor<const char*> : StringEqualFunctor { };
template <> struct DefaultHashFunctor<char*> : StringHashFunctor { };
template <> struct DefaultHashFunctor<const char*> : StringHashFunctor { };
// CUtlString/CUtlConstString are specialized here and not in utlstring.h
// because I consider string datatypes to be fundamental, and don't feel
// comfortable making that header file dependent on this one. (henryg)
class CUtlString;
template < typename T > class CUtlConstStringBase;
template <> struct DefaultLessFunctor<CUtlString> : StringLessFunctor { };
template <> struct DefaultHashFunctor<CUtlString> : StringHashFunctor { };
template < typename T > struct DefaultLessFunctor< CUtlConstStringBase<T> > : StringLessFunctor { };
template < typename T > struct DefaultHashFunctor< CUtlConstStringBase<T> > : StringHashFunctor { };
// Helpers to deduce if a type defines a public AltArgumentType_t typedef:
template < typename T >
struct HasClassAltArgumentType
{
template < typename X > static long Test( typename X::AltArgumentType_t* );
template < typename X > static char Test( ... );
enum { value = ( sizeof( Test< T >( NULL ) ) != sizeof( char ) ) };
};
template < typename T, bool = HasClassAltArgumentType< T >::value >
struct GetClassAltArgumentType { typedef typename T::AltArgumentType_t Result_t; };
template < typename T >
struct GetClassAltArgumentType< T, false > { typedef undefined_t Result_t; };
// Unwrap references; reference types don't have member typedefs.
template < typename T >
struct GetClassAltArgumentType< T&, false > : GetClassAltArgumentType< T > { };
// ArgumentTypeInfoImpl is the base for all ArgumentTypeInfo specializations.
template < typename ArgT, typename AltT = typename GetClassAltArgumentType<ArgT>::Result_t >
struct ArgumentTypeInfoImpl
{
enum { has_alt = 1 };
typedef ArgT Arg_t;
typedef AltT Alt_t;
};
// Handle cases where AltArgumentType_t is typedef'd to undefined_t
template < typename ArgT >
struct ArgumentTypeInfoImpl< ArgT, undefined_t >
{
enum { has_alt = 0 };
typedef ArgT Arg_t;
typedef undefined_t Alt_t;
};
// Handle cases where AltArgumentType_t is typedef'd to the primary type
template < typename ArgT >
struct ArgumentTypeInfoImpl< ArgT, ArgT >
{
enum { has_alt = 0 };
typedef ArgT Arg_t;
typedef undefined_t Alt_t;
};
// By default, everything is passed via const ref and doesn't define an alternate type.
template <typename T> struct ArgumentTypeInfo : ArgumentTypeInfoImpl< const T& > { };
// Small native types are most efficiently passed by value.
template <> struct ArgumentTypeInfo< bool > : ArgumentTypeInfoImpl< bool > { };
template <> struct ArgumentTypeInfo< char > : ArgumentTypeInfoImpl< char > { };
template <> struct ArgumentTypeInfo< signed char > : ArgumentTypeInfoImpl< signed char > { };
template <> struct ArgumentTypeInfo< unsigned char > : ArgumentTypeInfoImpl< unsigned char > { };
template <> struct ArgumentTypeInfo< signed short > : ArgumentTypeInfoImpl< signed short > { };
template <> struct ArgumentTypeInfo< unsigned short > : ArgumentTypeInfoImpl< unsigned short > { };
template <> struct ArgumentTypeInfo< signed int > : ArgumentTypeInfoImpl< signed int > { };
template <> struct ArgumentTypeInfo< unsigned int > : ArgumentTypeInfoImpl< unsigned int > { };
template <> struct ArgumentTypeInfo< signed long > : ArgumentTypeInfoImpl< signed long > { };
template <> struct ArgumentTypeInfo< unsigned long > : ArgumentTypeInfoImpl< unsigned long > { };
template <> struct ArgumentTypeInfo< signed long long > : ArgumentTypeInfoImpl< signed long long > { };
template <> struct ArgumentTypeInfo< unsigned long long > : ArgumentTypeInfoImpl< unsigned long long > { };
template <> struct ArgumentTypeInfo< float > : ArgumentTypeInfoImpl< float > { };
template <> struct ArgumentTypeInfo< double > : ArgumentTypeInfoImpl< double > { };
template <> struct ArgumentTypeInfo< long double > : ArgumentTypeInfoImpl< long double > { };
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template <> struct ArgumentTypeInfo< wchar_t > : ArgumentTypeInfoImpl< wchar_t > { };
#endif
// Pointers are also most efficiently passed by value.
template < typename T > struct ArgumentTypeInfo< T* > : ArgumentTypeInfoImpl< T* > { };
// Specializations to unwrap const-decorated types and references
template <typename T> struct ArgumentTypeInfo<const T> : ArgumentTypeInfo<T> { };
template <typename T> struct ArgumentTypeInfo<volatile T> : ArgumentTypeInfo<T> { };
template <typename T> struct ArgumentTypeInfo<const volatile T> : ArgumentTypeInfo<T> { };
template <typename T> struct ArgumentTypeInfo<T&> : ArgumentTypeInfo<T> { };
template <typename T> struct DefaultLessFunctor<const T> : DefaultLessFunctor<T> { };
template <typename T> struct DefaultLessFunctor<volatile T> : DefaultLessFunctor<T> { };
template <typename T> struct DefaultLessFunctor<const volatile T> : DefaultLessFunctor<T> { };
template <typename T> struct DefaultLessFunctor<T&> : DefaultLessFunctor<T> { };
template <typename T> struct DefaultEqualFunctor<const T> : DefaultEqualFunctor<T> { };
template <typename T> struct DefaultEqualFunctor<volatile T> : DefaultEqualFunctor<T> { };
template <typename T> struct DefaultEqualFunctor<const volatile T> : DefaultEqualFunctor<T> { };
template <typename T> struct DefaultEqualFunctor<T&> : DefaultEqualFunctor<T> { };
template <typename T> struct DefaultHashFunctor<const T> : DefaultHashFunctor<T> { };
template <typename T> struct DefaultHashFunctor<volatile T> : DefaultHashFunctor<T> { };
template <typename T> struct DefaultHashFunctor<const volatile T> : DefaultHashFunctor<T> { };
template <typename T> struct DefaultHashFunctor<T&> : DefaultHashFunctor<T> { };
// Hash all pointer types as raw pointers by default
template <typename T> struct DefaultHashFunctor< T * > : PointerHashFunctor { };
// Here follow the useful implementations.
// Bob Jenkins's 32-bit mix function.
inline unsigned int Mix32HashFunctor::operator()( uint32 n ) const
{
// Perform a mixture of the bits in n, where each bit
// of the input value has an equal chance to affect each
// bit of the output. This turns tightly clustered input
// values into a smooth distribution.
//
// This takes 16-20 cycles on modern x86 architectures;
// that's roughly the same cost as a mispredicted branch.
// It's also reasonably efficient on PPC-based consoles.
//
// If you're still thinking, "too many instructions!",
// do keep in mind that reading one byte of uncached RAM
// is about 30x slower than executing this code. It pays
// to have a good hash function which minimizes collisions
// (and therefore long lookup chains).
n = ( n + 0x7ed55d16 ) + ( n << 12 );
n = ( n ^ 0xc761c23c ) ^ ( n >> 19 );
n = ( n + 0x165667b1 ) + ( n << 5 );
n = ( n + 0xd3a2646c ) ^ ( n << 9 );
n = ( n + 0xfd7046c5 ) + ( n << 3 );
n = ( n ^ 0xb55a4f09 ) ^ ( n >> 16 );
return n;
}
// Based on the widely-used FNV-1A string hash with a final
// mixing step to improve dispersion for very small and very
// large hash table sizes.
inline unsigned int StringHashFunctor::operator()( const char* s ) const
{
uint32 h = 2166136261u;
for ( ; *s; ++s )
{
uint32 c = (unsigned char) *s;
h = (h ^ c) * 16777619;
}
return (h ^ (h << 17)) + (h >> 21);
}
// Equivalent to StringHashFunctor on lower-case strings.
inline unsigned int CaselessStringHashFunctor::operator()( const char* s ) const
{
uint32 h = 2166136261u;
for ( ; *s; ++s )
{
uint32 c = (unsigned char) *s;
// Brutally fast branchless ASCII tolower():
// if ((c >= 'A') && (c <= 'Z')) c += ('a' - 'A');
c += (((('A'-1) - c) & (c - ('Z'+1))) >> 26) & 32;
h = (h ^ c) * 16777619;
}
return (h ^ (h << 17)) + (h >> 21);
}
#endif // UTLCOMMON_H