Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ObjectIdBuilder.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under Apache 2.0 License. See LICENSE.md for details.
3 //
4 // Copyright 2012 Darren Kopp
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 //
10 // http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 using System;
18 using System.Runtime.CompilerServices;
19 using System.Runtime.InteropServices;
20 
21 namespace SiliconStudio.Core.Storage
22 {
23  [StructLayout(LayoutKind.Sequential, Pack = 4)]
24  public unsafe struct ObjectIdBuilder
25  {
26  private readonly uint seed;
27  const uint C1 = 0x239b961b;
28  const uint C2 = 0xab0e9789;
29  const uint C3 = 0x38b34ae5;
30  const uint C4 = 0xa1e38b93;
31 
32  internal ObjectIdBuilder(uint seed = 0)
33  {
34  this.seed = seed;
35 
36  // initialize hash values to seed values
37  H1 = H2 = H3 = H4 = seed;
38  Length = 0;
39 
40  currentBlock1 = 0;
41  currentBlock2 = 0;
42  currentBlock3 = 0;
43  currentBlock4 = 0;
44  }
45 
46  public uint Seed { get { return seed; } }
47 
48  private uint H1;
49  private uint H2;
50  private uint H3;
51  private uint H4;
52  private int Length;
53 
54  private uint currentBlock1;
55  private uint currentBlock2;
56  private uint currentBlock3;
57  private uint currentBlock4;
58 
59  public void Reset()
60  {
61  // initialize hash values to seed values
62  H1 = H2 = H3 = H4 = Seed;
63  Length = 0;
64  }
65 
66  /// <summary>
67  /// Gets the current calculated hash.
68  /// </summary>
69  /// <value>The current hash.</value>
70  [MethodImpl(MethodImplOptions.AggressiveInlining)]
72  {
73  // create our keys and initialize to 0
74  uint k1 = 0, k2 = 0, k3 = 0, k4 = 0;
75 
76  var remainder = Length % 16;
77 
78  fixed (uint* currentBlockStart = &currentBlock1)
79  {
80  var tail = (byte*)currentBlockStart;
81 
82  // determine how many bytes we have left to work with based on length
83  switch (remainder)
84  {
85  case 15: k4 ^= (uint)tail[14] << 16; goto case 14;
86  case 14: k4 ^= (uint)tail[13] << 8; goto case 13;
87  case 13: k4 ^= (uint)tail[12] << 0; goto case 12;
88  case 12: k3 ^= (uint)tail[11] << 24; goto case 11;
89  case 11: k3 ^= (uint)tail[10] << 16; goto case 10;
90  case 10: k3 ^= (uint)tail[9] << 8; goto case 9;
91  case 9: k3 ^= (uint)tail[8] << 0; goto case 8;
92  case 8: k2 ^= (uint)tail[7] << 24; goto case 7;
93  case 7: k2 ^= (uint)tail[6] << 16; goto case 6;
94  case 6: k2 ^= (uint)tail[5] << 8; goto case 5;
95  case 5: k2 ^= (uint)tail[4] << 0; goto case 4;
96  case 4: k1 ^= (uint)tail[3] << 24; goto case 3;
97  case 3: k1 ^= (uint)tail[2] << 16; goto case 2;
98  case 2: k1 ^= (uint)tail[1] << 8; goto case 1;
99  case 1: k1 ^= (uint)tail[0] << 0; break;
100  }
101  }
102 
103  var h4 = H4 ^ RotateLeft((k4 * C4), 18) * C1;
104  var h3 = H3 ^ RotateLeft((k3 * C3), 17) * C4;
105  var h2 = H2 ^ RotateLeft((k2 * C2), 16) * C3;
106  var h1 = H1 ^ RotateLeft((k1 * C1), 15) * C2;
107 
108  uint len = (uint)Length;
109  // pipelining friendly algorithm
110  h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
111 
112  h1 += (h2 + h3 + h4);
113  h2 += h1; h3 += h1; h4 += h1;
114 
115  h1 = FMix(h1);
116  h2 = FMix(h2);
117  h3 = FMix(h3);
118  h4 = FMix(h4);
119 
120  h1 += (h2 + h3 + h4);
121  h2 += h1; h3 += h1; h4 += h1;
122 
123  ObjectId result;
124 
125  var h = (uint*)&result;
126  *h++ = h1;
127  *h++ = h2;
128  *h++ = h3;
129  *h = h4;
130 
131  return result;
132  }
133 
134  /// <summary>
135  /// Writes a byte to the builder.
136  /// </summary>
137  /// <param name="value">The value.</param>
138  public void WriteByte(byte value)
139  {
140  fixed (uint* currentBlockStart = &currentBlock1)
141  {
142  var currentBlock = (byte*)currentBlockStart;
143 
144  var position = Length++ % 16;
145 
146  currentBlock[position] = value;
147 
148  if (position == 15)
149  {
150  BodyCore(currentBlock);
151  }
152  }
153  }
154 
155  /// <summary>
156  /// Writes a buffer of byte to this builder.
157  /// </summary>
158  /// <param name="buffer">The buffer.</param>
159  /// <param name="offset">The offset.</param>
160  /// <param name="count">The count.</param>
161  /// <exception cref="System.ArgumentNullException">buffer</exception>
162  /// <exception cref="System.ArgumentOutOfRangeException">count;Offset + Count is out of range</exception>
163  public void Write(byte[] buffer, int offset, int count)
164  {
165  fixed (byte* bufferStart = buffer)
166  {
167  Write(bufferStart + offset, count);
168  }
169  }
170 
171  /// <summary>
172  /// Writes a buffer of byte to this builder.
173  /// </summary>
174  /// <param name="buffer">The buffer.</param>
175  /// <param name="count">The count.</param>
176  /// <exception cref="System.ArgumentNullException">buffer</exception>
177  /// <exception cref="System.ArgumentOutOfRangeException">count;Offset + Count is out of range</exception>
178  public void Write(byte* buffer, int length)
179  {
180  if (buffer == null) throw new ArgumentNullException("buffer");
181 
182  fixed (uint* currentBlockStart = &currentBlock1)
183  {
184  var currentBlock = (byte*)currentBlockStart;
185 
186  var position = Length % 16;
187 
188  Length += length;
189 
190  // Partial block to continue?
191  if (position != 0)
192  {
193  var remainder = 16 - position;
194 
195  var partialLength = length;
196  if (partialLength > remainder)
197  partialLength = remainder;
198 
199  Utilities.CopyMemory((IntPtr)currentBlock + position, (IntPtr)buffer, partialLength);
200  buffer += partialLength;
201  length -= partialLength;
202 
203  if (partialLength == remainder)
204  {
205  BodyCore(currentBlock);
206  }
207  }
208 
209  if (length > 0)
210  {
211  int blocks = length / 16;
212  length -= blocks * 16;
213 
214  // Main loop
215  while (blocks-- > 0)
216  {
217  BodyCore(buffer);
218  buffer += 16;
219  }
220 
221  // Start partial block
222  if (length > 0)
223  {
224  Utilities.CopyMemory((IntPtr)currentBlock, (IntPtr)buffer, length);
225  }
226  }
227  }
228  }
229 
230  [MethodImpl(MethodImplOptions.AggressiveInlining)]
231  private void BodyCore(byte* data)
232  {
233  uint* b = (uint*)data;
234 
235  // K1 - consume first integer
236  H1 ^= RotateLeft((*b++ * C1), 15) * C2;
237  H1 = (RotateLeft(H1, 19) + H2) * 5 + 0x561ccd1b;
238 
239  // K2 - consume second integer
240  H2 ^= RotateLeft((*b++ * C2), 16) * C3;
241  H2 = (RotateLeft(H2, 17) + H3) * 5 + 0x0bcaa747;
242 
243  // K3 - consume third integer
244  H3 ^= RotateLeft((*b++ * C3), 17) * C4;
245  H3 = (RotateLeft(H3, 15) + H4) * 5 + 0x96cd1c35;
246 
247  // K4 - consume fourth integer
248  H4 ^= RotateLeft((*b++ * C4), 18) * C1;
249  H4 = (RotateLeft(H4, 13) + H1) * 5 + 0x32ac3b17;
250  }
251 
252  [MethodImpl(MethodImplOptions.AggressiveInlining)]
253  private static uint RotateLeft(uint x, byte r)
254  {
255  return (x << r) | (x >> (32 - r));
256  }
257 
258  [MethodImpl(MethodImplOptions.AggressiveInlining)]
259  private static uint FMix(uint h)
260  {
261  // pipelining friendly algorithm
262  h = (h ^ (h >> 16)) * 0x85ebca6b;
263  h = (h ^ (h >> 13)) * 0xc2b2ae35;
264  return h ^ (h >> 16);
265  }
266  }
267 }
ObjectId ComputeHash()
Gets the current calculated hash.
function b
void Write(byte[] buffer, int offset, int count)
Writes a buffer of byte to this builder.
_In_ size_t count
Definition: DirectXTexP.h:174
void WriteByte(byte value)
Writes a byte to the builder.
A hash to uniquely identify data.
Definition: ObjectId.cs:13
void Write(byte *buffer, int length)
Writes a buffer of byte to this builder.