Blender  V2.59
STR_HashedString.h
Go to the documentation of this file.
00001 /*
00002  * $Id: STR_HashedString.h 35160 2011-02-25 11:51:19Z jesterking $
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): none yet.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00042 #ifndef __STR_HASHSTRING
00043 #define __STR_HASHSTRING
00044 
00045 #include "STR_String.h"
00046 
00047 
00048 // Hash Mix utility function, by Bob Jenkins - Mix 3 32-bit values reversibly
00049 //
00050 // - If gHashMix() is run forward or backward, at least 32 bits in a,b,c have at
00051 //   least 1/4 probability of changing.
00052 //
00053 // - If gHashMix() is run forward, every bit of c will change between 1/3 and
00054 //   2/3 of the time.
00055 //
00056 static inline void STR_gHashMix(dword& a, dword& b, dword& c)
00057 {
00058         a -= b; a -= c; a ^= (c>>13);
00059         b -= c; b -= a; b ^= (a<<8);
00060         c -= a; c -= b; c ^= (b>>13);
00061         a -= b; a -= c; a ^= (c>>12);
00062         b -= c; b -= a; b ^= (a<<16);
00063         c -= a; c -= b; c ^= (b>>5);
00064         a -= b; a -= c; a ^= (c>>3);
00065         b -= c; b -= a; b ^= (a<<10);
00066         c -= a; c -= b; c ^= (b>>15);
00067 }
00068 
00069 //
00070 // Fast Hashable<int32> functionality
00071 // http://www.concentric.net/~Ttwang/tech/inthash.htm
00072 //
00073 static inline dword                     STR_gHash(dword inDWord)
00074 {
00075         dword key = inDWord;
00076         key += ~(key << 16);
00077         key ^=  (key >>  5);
00078         key +=  (key <<  3);
00079         key ^=  (key >> 13);
00080         key += ~(key <<  9);
00081         key ^=  (key >> 17);
00082         return key;
00083 }
00084 
00085 enum { GOLDEN_RATIO = 0x9e3779b9 }; // arbitrary value to initialize hash funtion, well not so arbitrary
00086                                                                         // as this value is taken from the pigs library (Orange Games/Lost Boys)
00087 
00088 
00089 
00090 static dword STR_gHash(const void* in, int len, dword init_val)
00091 {
00092         unsigned int  length = len;
00093         dword a = (dword)GOLDEN_RATIO;
00094         dword b = (dword)GOLDEN_RATIO;
00095         dword c = init_val;                                                                                                                     // the previous hash value
00096         byte  *p_in = (byte *)in;
00097 
00098         // Do the largest part of the key
00099         while (length >= 12)
00100         {
00101                 a += (p_in[0] + ((dword)p_in[1]<<8) + ((dword)p_in[2] <<16) + ((dword)p_in[3] <<24));
00102                 b += (p_in[4] + ((dword)p_in[5]<<8) + ((dword)p_in[6] <<16) + ((dword)p_in[7] <<24));
00103                 c += (p_in[8] + ((dword)p_in[9]<<8) + ((dword)p_in[10]<<16) + ((dword)p_in[11]<<24));
00104                 STR_gHashMix(a, b, c);
00105                 p_in += 12; length -= 12;
00106         }
00107 
00108         // Handle the last 11 bytes
00109         c += len;
00110         switch(length) {
00111         case 11: c+=((dword)p_in[10]<<24);
00112         case 10: c+=((dword)p_in[9]<<16);
00113         case 9 : c+=((dword)p_in[8]<<8);                                                                                        // the first byte of c is reserved for the length
00114         case 8 : b+=((dword)p_in[7]<<24);
00115         case 7 : b+=((dword)p_in[6]<<16);
00116         case 6 : b+=((dword)p_in[5]<<8);
00117         case 5 : b+=p_in[4];
00118         case 4 : a+=((dword)p_in[3]<<24);
00119         case 3 : a+=((dword)p_in[2]<<16);
00120         case 2 : a+=((dword)p_in[1]<<8);
00121         case 1 : a+=p_in[0];
00122         }
00123         STR_gHashMix(a, b, c);
00124 
00125         return c;
00126 }
00127 
00128 
00129 
00130 
00131 class STR_HashedString : public STR_String
00132 {
00133 public:
00134         STR_HashedString()      : STR_String(),m_Hashed(false) {}
00135         STR_HashedString(const char* str)       : STR_String(str),m_Hashed(false) {}
00136         STR_HashedString(const STR_String& str) : STR_String(str),m_Hashed(false) {}
00137 
00138         inline dword hash(dword init=0) const
00139         { 
00140                 if (!m_Hashed) 
00141                 {
00142                         const char* str = *this;
00143                         int length = this->Length();
00144                         m_CachedHash = STR_gHash(str,length,init);
00145                         m_Hashed=true;
00146                 } 
00147                 return m_CachedHash;
00148         }
00149 
00150 private:
00151         mutable bool m_Hashed;
00152         mutable dword m_CachedHash;
00153 };
00154 
00155 #endif //__STR_HASHSTRING
00156