//========= 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::type is a typedef of A if sel is nonzero, else B template struct CTypeSelect { typedef A type; }; template struct CTypeSelect<0, A, B> { typedef B type; }; // CTypeEquals::value is nonzero if A and B are the same type template struct CTypeEquals { enum { value = 0 }; }; template struct CTypeEquals { enum { value = 1 }; }; template struct CTypeEquals : CTypeEquals {}; template struct CTypeEquals : CTypeEquals {}; template struct CTypeEquals : CTypeEquals {}; // 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 class CUtlKeyValuePair { public: typedef V ValueReturn_t; K m_key; V m_value; CUtlKeyValuePair() {} template explicit CUtlKeyValuePair(const KInit &k) : m_key(k) {} template 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 class CUtlKeyValuePair { public: typedef const K ValueReturn_t; K m_key; CUtlKeyValuePair() {} template explicit CUtlKeyValuePair(const KInit &k) : m_key(k) {} template 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 struct DefaultLessFunctor; template 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 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 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 struct DefaultLessFunctor { bool operator()(typename ArgumentTypeInfo::Arg_t a, typename ArgumentTypeInfo::Arg_t b) const { return a < b; } bool operator()(typename ArgumentTypeInfo::Alt_t a, typename ArgumentTypeInfo::Arg_t b) const { return a < b; } bool operator()(typename ArgumentTypeInfo::Arg_t a, typename ArgumentTypeInfo::Alt_t b) const { return a < b; } }; template struct DefaultEqualFunctor { bool operator()(typename ArgumentTypeInfo::Arg_t a, typename ArgumentTypeInfo::Arg_t b) const { return a == b; } bool operator()(typename ArgumentTypeInfo::Alt_t a, typename ArgumentTypeInfo::Arg_t b) const { return a == b; } bool operator()(typename ArgumentTypeInfo::Arg_t a, typename ArgumentTypeInfo::Alt_t b) const { return a == b; } }; // Hashes for basic types template <> struct DefaultHashFunctor : Mix32HashFunctor {}; template <> struct DefaultHashFunctor : Mix32HashFunctor {}; template <> struct DefaultHashFunctor : Mix32HashFunctor {}; template <> struct DefaultHashFunctor : Mix32HashFunctor {}; template <> struct DefaultHashFunctor : Mix32HashFunctor {}; template <> struct DefaultHashFunctor : Mix32HashFunctor {}; template <> struct DefaultHashFunctor : Mix32HashFunctor {}; template <> struct DefaultHashFunctor : Mix32HashFunctor {}; template <> struct DefaultHashFunctor : Mix32HashFunctor {}; template <> struct DefaultHashFunctor : PointerHashFunctor {}; template <> struct DefaultHashFunctor : PointerHashFunctor {}; #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) template <> struct DefaultHashFunctor : 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 : StringLessFunctor {}; template <> struct DefaultLessFunctor : StringLessFunctor {}; template <> struct DefaultEqualFunctor : StringEqualFunctor {}; template <> struct DefaultEqualFunctor : StringEqualFunctor {}; template <> struct DefaultHashFunctor : StringHashFunctor {}; template <> struct DefaultHashFunctor : 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 class CUtlConstStringBase; template <> struct DefaultLessFunctor : StringLessFunctor {}; template <> struct DefaultHashFunctor : StringHashFunctor {}; template struct DefaultLessFunctor > : StringLessFunctor {}; template struct DefaultHashFunctor > : StringHashFunctor {}; // Helpers to deduce if a type defines a public AltArgumentType_t typedef: template struct HasClassAltArgumentType { template static long Test(typename X::AltArgumentType_t *); template static char Test(...); enum { value = (sizeof(Test(NULL)) != sizeof(char)) }; }; template ::value> struct GetClassAltArgumentType { typedef typename T::AltArgumentType_t Result_t; }; template struct GetClassAltArgumentType { typedef undefined_t Result_t; }; // Unwrap references; reference types don't have member typedefs. template struct GetClassAltArgumentType : GetClassAltArgumentType {}; // ArgumentTypeInfoImpl is the base for all ArgumentTypeInfo specializations. template ::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 struct ArgumentTypeInfoImpl { 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 struct ArgumentTypeInfoImpl { 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 struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; // Small native types are most efficiently passed by value. template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl { }; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) template <> struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; #endif // Pointers are also most efficiently passed by value. template struct ArgumentTypeInfo : ArgumentTypeInfoImpl {}; // Specializations to unwrap const-decorated types and references template struct ArgumentTypeInfo : ArgumentTypeInfo {}; template struct ArgumentTypeInfo : ArgumentTypeInfo {}; template struct ArgumentTypeInfo : ArgumentTypeInfo {}; template struct ArgumentTypeInfo : ArgumentTypeInfo {}; template struct DefaultLessFunctor : DefaultLessFunctor {}; template struct DefaultLessFunctor : DefaultLessFunctor {}; template struct DefaultLessFunctor : DefaultLessFunctor {}; template struct DefaultLessFunctor : DefaultLessFunctor {}; template struct DefaultEqualFunctor : DefaultEqualFunctor {}; template struct DefaultEqualFunctor : DefaultEqualFunctor {}; template struct DefaultEqualFunctor : DefaultEqualFunctor {}; template struct DefaultEqualFunctor : DefaultEqualFunctor {}; template struct DefaultHashFunctor : DefaultHashFunctor {}; template struct DefaultHashFunctor : DefaultHashFunctor {}; template struct DefaultHashFunctor : DefaultHashFunctor {}; template struct DefaultHashFunctor : DefaultHashFunctor {}; // Hash all pointer types as raw pointers by default template struct DefaultHashFunctor : 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