1
1
using System ;
2
2
using System . Collections . Generic ;
3
+ using System . Diagnostics ;
3
4
using System . Reflection ;
5
+ using System . Runtime . InteropServices ;
4
6
using System . Text ;
5
7
using UnityEngine ;
6
8
@@ -52,7 +54,6 @@ static BitWriter()
52
54
53
55
private List < object > collect = null ;
54
56
private bool tempAlloc = false ;
55
- private int collectCount = 0 ;
56
57
57
58
/// <summary>
58
59
/// Allocates a new binary collector.
@@ -73,10 +74,11 @@ public BitWriter()
73
74
74
75
private void Push < T > ( T b )
75
76
{
76
- if ( b is string || b . GetType ( ) . IsArray || IsSupportedType ( b . GetType ( ) ) )
77
+ if ( b == null ) collect . Add ( b ) ;
78
+ else if ( b is string || b . GetType ( ) . IsArray || IsSupportedType ( b . GetType ( ) ) )
77
79
collect . Add ( b is string ? Encoding . UTF8 . GetBytes ( b as string ) : b as object ) ;
78
- // else
79
- // Debug.LogWarning("MLAPI: The type \"" + b.GetType() + "\" is not supported by the Binary Serializer. It will be ignored");
80
+ else
81
+ Debug . LogWarning ( "MLAPI: The type \" " + b . GetType ( ) + "\" is not supported by the Binary Serializer. It will be ignored" ) ;
80
82
}
81
83
82
84
@@ -87,11 +89,12 @@ private void Push<T>(T b)
87
89
public void WriteUShort ( ushort s ) => Push ( s ) ;
88
90
public void WriteUInt ( uint i ) => Push ( i ) ;
89
91
public void WriteULong ( ulong l ) => Push ( l ) ;
90
- public void WriteSByte ( sbyte b ) => Push ( b ) ;
91
- public void WriteShort ( short s ) => Push ( s ) ;
92
- public void WriteInt ( int i ) => Push ( i ) ;
93
- public void WriteLong ( long l ) => Push ( l ) ;
92
+ public void WriteSByte ( sbyte b ) => Push ( ZigZagEncode ( b , 8 ) ) ;
93
+ public void WriteShort ( short s ) => Push ( ZigZagEncode ( s , 8 ) ) ;
94
+ public void WriteInt ( int i ) => Push ( ZigZagEncode ( i , 8 ) ) ;
95
+ public void WriteLong ( long l ) => Push ( ZigZagEncode ( l , 8 ) ) ;
94
96
public void WriteString ( string s ) => Push ( s ) ;
97
+ public void WriteAlignBits ( ) => Push < object > ( null ) ;
95
98
public void WriteFloatArray ( float [ ] f , bool known = false ) => PushArray ( f , known ) ;
96
99
public void WriteDoubleArray ( double [ ] d , bool known = false ) => PushArray ( d , known ) ;
97
100
public void WriteByteArray ( byte [ ] b , bool known = false ) => PushArray ( b , known ) ;
@@ -103,10 +106,12 @@ private void Push<T>(T b)
103
106
public void WriteIntArray ( int [ ] i , bool known = false ) => PushArray ( i , known ) ;
104
107
public void WriteLongArray ( long [ ] l , bool known = false ) => PushArray ( l , known ) ;
105
108
106
- private void PushArray < T > ( T [ ] t , bool knownSize = false )
109
+ public void PushArray < T > ( T [ ] t , bool knownSize = false )
107
110
{
108
- if ( ! knownSize ) Push ( t ) ;
109
- else foreach ( T t1 in t ) Push ( t1 ) ;
111
+ if ( ! knownSize ) Push ( ( uint ) t . Length ) ;
112
+ bool signed = IsSigned ( t . GetType ( ) . GetElementType ( ) ) ;
113
+ int size = Marshal . SizeOf ( t . GetType ( ) . GetElementType ( ) ) ;
114
+ foreach ( T t1 in t ) Push ( signed ? ( object ) ZigZagEncode ( t1 as long ? ?? t1 as int ? ?? t1 as short ? ?? t1 as sbyte ? ?? 0 , size ) : ( object ) t1 ) ;
110
115
}
111
116
112
117
public long Finalize ( ref byte [ ] buffer )
@@ -117,52 +122,59 @@ public long Finalize(ref byte[] buffer)
117
122
return 0 ;
118
123
}
119
124
long bitCount = 0 ;
120
- for ( int i = 0 ; i < collectCount ; ++ i ) bitCount += GetBitCount ( collect [ i ] ) ;
125
+ for ( int i = 0 ; i < collect . Count ; ++ i ) bitCount += collect [ i ] == null ? ( 8 - ( bitCount % 8 ) ) % 8 : GetBitCount ( collect [ i ] ) ;
121
126
122
- if ( buffer . Length < ( ( bitCount / 8 ) + ( bitCount % 8 == 0 ? 0 : 1 ) ) )
127
+ if ( buffer . Length < ( ( bitCount / 8 ) + ( bitCount % 8 == 0 ? 0 : 1 ) ) )
123
128
{
124
129
Debug . LogWarning ( "MLAPI: The buffer size is not large enough" ) ;
125
130
return 0 ;
126
131
}
127
132
long bitOffset = 0 ;
133
+ bool isAligned = true ;
128
134
foreach ( var item in collect )
129
- Serialize ( item , buffer , ref bitOffset ) ;
135
+ if ( item == null )
136
+ {
137
+ bitOffset += ( 8 - ( bitOffset % 8 ) ) % 8 ;
138
+ isAligned = true ;
139
+ }
140
+ else Serialize ( item , buffer , ref bitOffset , ref isAligned ) ;
130
141
131
142
return ( bitCount / 8 ) + ( bitCount % 8 == 0 ? 0 : 1 ) ;
132
143
}
133
144
134
145
public long GetFinalizeSize ( )
135
146
{
136
147
long bitCount = 0 ;
137
- for ( int i = 0 ; i < collectCount ; ++ i ) bitCount += GetBitCount ( collect [ i ] ) ;
148
+ for ( int i = 0 ; i < collect . Count ; ++ i ) bitCount += collect [ i ] == null ? ( 8 - ( bitCount % 8 ) ) % 8 : GetBitCount ( collect [ i ] ) ;
138
149
return ( ( bitCount / 8 ) + ( bitCount % 8 == 0 ? 0 : 1 ) ) ;
139
150
}
140
151
141
- private static void Serialize < T > ( T t , byte [ ] writeTo , ref long bitOffset )
152
+ private static void Serialize < T > ( T t , byte [ ] writeTo , ref long bitOffset , ref bool isAligned )
142
153
{
143
154
Type type = t . GetType ( ) ;
144
155
bool size = false ;
145
156
if ( type . IsArray )
146
157
{
147
158
var array = t as Array ;
148
- Serialize ( ( uint ) array . Length , writeTo , ref bitOffset ) ;
159
+ Serialize ( ( uint ) array . Length , writeTo , ref bitOffset , ref isAligned ) ;
149
160
foreach ( var element in array )
150
- Serialize ( element , writeTo , ref bitOffset ) ;
161
+ Serialize ( element , writeTo , ref bitOffset , ref isAligned ) ;
151
162
}
152
163
else if ( IsSupportedType ( type ) )
153
164
{
154
- long offset = GetBitAllocation ( type ) ;
165
+ long offset = t is bool ? 1 : BytesToRead ( t ) * 8 ;
155
166
if ( type == typeof ( bool ) )
156
167
{
157
168
WriteBit ( writeTo , t as bool ? ?? false , bitOffset ) ;
158
169
bitOffset += offset ;
170
+ isAligned = bitOffset % 8 == 0 ;
159
171
}
160
172
else if ( type == typeof ( decimal ) )
161
173
{
162
- WriteDynamic ( writeTo , ( int ) dec_lo . GetValue ( t ) , 4 , bitOffset ) ;
163
- WriteDynamic ( writeTo , ( int ) dec_mid . GetValue ( t ) , 4 , bitOffset + 32 ) ;
164
- WriteDynamic ( writeTo , ( int ) dec_hi . GetValue ( t ) , 4 , bitOffset + 64 ) ;
165
- WriteDynamic ( writeTo , ( int ) dec_flags . GetValue ( t ) , 4 , bitOffset + 96 ) ;
174
+ WriteDynamic ( writeTo , ( int ) dec_lo . GetValue ( t ) , 4 , bitOffset , isAligned ) ;
175
+ WriteDynamic ( writeTo , ( int ) dec_mid . GetValue ( t ) , 4 , bitOffset + 32 , isAligned ) ;
176
+ WriteDynamic ( writeTo , ( int ) dec_hi . GetValue ( t ) , 4 , bitOffset + 64 , isAligned ) ;
177
+ WriteDynamic ( writeTo , ( int ) dec_flags . GetValue ( t ) , 4 , bitOffset + 96 , isAligned ) ;
166
178
bitOffset += offset ;
167
179
}
168
180
else if ( ( size = type == typeof ( float ) ) || type == typeof ( double ) )
@@ -181,71 +193,75 @@ private static void Serialize<T>(T t, byte[] writeTo, ref long bitOffset)
181
193
182
194
// Since floating point flag bits are seemingly the highest bytes of the floating point values
183
195
// and even very small values have them, we swap the endianness in the hopes of reducing the size
184
- if ( size ) Serialize ( BinaryHelpers . SwapEndian ( ( uint ) result_holder . GetValue ( 0 ) ) , writeTo , ref bitOffset ) ;
185
- else Serialize ( BinaryHelpers . SwapEndian ( ( ulong ) result_holder . GetValue ( 0 ) ) , writeTo , ref bitOffset ) ;
196
+ if ( size ) Serialize ( BinaryHelpers . SwapEndian ( ( uint ) result_holder . GetValue ( 0 ) ) , writeTo , ref bitOffset , ref isAligned ) ;
197
+ else Serialize ( BinaryHelpers . SwapEndian ( ( ulong ) result_holder . GetValue ( 0 ) ) , writeTo , ref bitOffset , ref isAligned ) ;
186
198
}
187
- //bitOffset += offset;
188
199
}
189
200
else
190
201
{
191
- bool signed = IsSigned ( t . GetType ( ) ) ;
202
+ // bool signed = IsSigned(t.GetType());
192
203
ulong value ;
193
- if ( signed )
204
+ /* if (signed)
194
205
{
195
206
Type t1 = t.GetType();
196
207
if (t1 == typeof(sbyte)) value = (byte)ZigZagEncode(t as sbyte? ?? 0, 1);
197
208
else if (t1 == typeof(short)) value = (ushort)ZigZagEncode(t as short? ?? 0, 2);
198
209
else if (t1 == typeof(int)) value = (uint)ZigZagEncode(t as int? ?? 0, 4);
199
- else /*if (t1 == typeof(long))*/ value = ( ulong ) ZigZagEncode ( t as long ? ?? 0 , 8 ) ;
210
+ else /*if (t1 == typeof(long)) value = (ulong)ZigZagEncode(t as long? ?? 0, 8);
211
+ }
212
+ else*/
213
+ if ( t is byte )
214
+ {
215
+ WriteByte ( writeTo , t as byte ? ?? 0 , bitOffset , isAligned ) ;
216
+ return ;
200
217
}
201
- else if ( t is byte ) value = t as byte ? ?? 0 ;
202
218
else if ( t is ushort ) value = t as ushort ? ?? 0 ;
203
219
else if ( t is uint ) value = t as uint ? ?? 0 ;
204
220
else /*if (t is ulong)*/ value = t as ulong ? ?? 0 ;
205
221
206
- if ( value <= 240 ) WriteByte ( writeTo , ( byte ) value , bitOffset ) ;
222
+ if ( value <= 240 ) WriteByte ( writeTo , ( byte ) value , bitOffset , isAligned ) ;
207
223
else if ( value <= 2287 )
208
224
{
209
- WriteByte ( writeTo , ( value - 240 ) / 256 + 241 , bitOffset ) ;
210
- WriteByte ( writeTo , ( value - 240 ) % 256 , bitOffset + 8 ) ;
225
+ WriteByte ( writeTo , ( value - 240 ) / 256 + 241 , bitOffset , isAligned ) ;
226
+ WriteByte ( writeTo , ( value - 240 ) % 256 , bitOffset + 8 , isAligned ) ;
211
227
}
212
228
else if ( value <= 67823 )
213
229
{
214
- WriteByte ( writeTo , 249 , bitOffset ) ;
215
- WriteByte ( writeTo , ( value - 2288 ) / 256 , bitOffset + 8 ) ;
216
- WriteByte ( writeTo , ( value - 2288 ) % 256 , bitOffset + 16 ) ;
230
+ WriteByte ( writeTo , 249 , bitOffset , isAligned ) ;
231
+ WriteByte ( writeTo , ( value - 2288 ) / 256 , bitOffset + 8 , isAligned ) ;
232
+ WriteByte ( writeTo , ( value - 2288 ) % 256 , bitOffset + 16 , isAligned ) ;
217
233
}
218
234
else
219
235
{
220
- WriteByte ( writeTo , value & 255 , bitOffset + 8 ) ;
221
- WriteByte ( writeTo , ( value >> 8 ) & 255 , bitOffset + 16 ) ;
222
- WriteByte ( writeTo , ( value >> 16 ) & 255 , bitOffset + 24 ) ;
236
+ WriteByte ( writeTo , value & 255 , bitOffset + 8 , isAligned ) ;
237
+ WriteByte ( writeTo , ( value >> 8 ) & 255 , bitOffset + 16 , isAligned ) ;
238
+ WriteByte ( writeTo , ( value >> 16 ) & 255 , bitOffset + 24 , isAligned ) ;
223
239
if ( value > 16777215 )
224
240
{
225
- WriteByte ( writeTo , ( value >> 24 ) & 255 , bitOffset + 32 ) ;
241
+ WriteByte ( writeTo , ( value >> 24 ) & 255 , bitOffset + 32 , isAligned ) ;
226
242
if ( value > 4294967295 )
227
243
{
228
- WriteByte ( writeTo , ( value >> 32 ) & 255 , bitOffset + 40 ) ;
244
+ WriteByte ( writeTo , ( value >> 32 ) & 255 , bitOffset + 40 , isAligned ) ;
229
245
if ( value > 1099511627775 )
230
246
{
231
- WriteByte ( writeTo , ( value >> 40 ) & 55 , bitOffset + 48 ) ;
247
+ WriteByte ( writeTo , ( value >> 40 ) & 55 , bitOffset + 48 , isAligned ) ;
232
248
if ( value > 281474976710655 )
233
249
{
234
- WriteByte ( writeTo , ( value >> 48 ) & 255 , bitOffset + 56 ) ;
250
+ WriteByte ( writeTo , ( value >> 48 ) & 255 , bitOffset + 56 , isAligned ) ;
235
251
if ( value > 72057594037927935 )
236
252
{
237
- WriteByte ( writeTo , 255 , bitOffset ) ;
238
- WriteByte ( writeTo , ( value >> 56 ) & 255 , bitOffset + 64 ) ;
253
+ WriteByte ( writeTo , 255 , bitOffset , isAligned ) ;
254
+ WriteByte ( writeTo , ( value >> 56 ) & 255 , bitOffset + 64 , isAligned ) ;
239
255
}
240
- else WriteByte ( writeTo , 254 , bitOffset ) ;
256
+ else WriteByte ( writeTo , 254 , bitOffset , isAligned ) ;
241
257
}
242
- else WriteByte ( writeTo , 253 , bitOffset ) ;
258
+ else WriteByte ( writeTo , 253 , bitOffset , isAligned ) ;
243
259
}
244
- else WriteByte ( writeTo , 252 , bitOffset ) ;
260
+ else WriteByte ( writeTo , 252 , bitOffset , isAligned ) ;
245
261
}
246
- else WriteByte ( writeTo , 251 , bitOffset ) ;
262
+ else WriteByte ( writeTo , 251 , bitOffset , isAligned ) ;
247
263
}
248
- else WriteByte ( writeTo , 250 , bitOffset ) ;
264
+ else WriteByte ( writeTo , 250 , bitOffset , isAligned ) ;
249
265
}
250
266
bitOffset += BytesToRead ( value ) * 8 ;
251
267
}
@@ -255,7 +271,7 @@ private static void Serialize<T>(T t, byte[] writeTo, ref long bitOffset)
255
271
private static byte Read7BitRange ( byte higher , byte lower , int bottomBits ) => ( byte ) ( ( higher << bottomBits ) & ( lower & ( 0xFF << ( 8 - bottomBits ) ) ) ) ;
256
272
private static byte ReadNBits ( byte from , int offset , int count ) => ( byte ) ( from & ( ( 0xFF >> ( 8 - count ) ) << offset ) ) ;
257
273
258
- private static bool IsSigned ( Type t ) => Convert . ToBoolean ( t . GetField ( "MinValue" ) . GetValue ( null ) ) ;
274
+ private static bool IsSigned ( Type t ) => t == typeof ( sbyte ) || t == typeof ( short ) || t == typeof ( int ) || t == typeof ( long ) ;
259
275
260
276
private static Type GetUnsignedType ( Type t ) =>
261
277
t == typeof ( sbyte ) ? typeof ( byte ) :
@@ -274,13 +290,16 @@ private static long GetBitCount<T>(T t)
274
290
{
275
291
Type elementType = type . GetElementType ( ) ;
276
292
277
- count += 16 ; // Int16 array size. Arrays shouldn't be syncing more than 65k elements
278
- foreach ( var element in t as Array )
279
- count += GetBitCount ( element ) ;
293
+ count += BytesToRead ( ( t as Array ) . Length ) * 8 ; // Int16 array size. Arrays shouldn't be syncing more than 65k elements
294
+
295
+ if ( elementType == typeof ( bool ) ) count += ( t as Array ) . Length ;
296
+ else
297
+ foreach ( var element in t as Array )
298
+ count += GetBitCount ( element ) ;
280
299
}
281
300
else if ( IsSupportedType ( type ) )
282
301
{
283
- long ba = GetBitAllocation ( type ) ;
302
+ long ba = t is bool ? 1 : BytesToRead ( t ) * 8 ;
284
303
if ( ba == 0 ) count += Encoding . UTF8 . GetByteCount ( t as string ) ;
285
304
else if ( t is bool || t is decimal ) count += ba ;
286
305
else count += BytesToRead ( t ) * 8 ;
@@ -292,33 +311,32 @@ private static long GetBitCount<T>(T t)
292
311
293
312
private static void WriteBit ( byte [ ] b , bool bit , long index )
294
313
=> b [ index / 8 ] = ( byte ) ( ( b [ index / 8 ] & ~ ( 1 << ( int ) ( index % 8 ) ) ) | ( bit ? 1 << ( int ) ( index % 8 ) : 0 ) ) ;
295
- private static void WriteByte ( byte [ ] b , ulong value , long index ) => WriteByte ( b , ( byte ) value , index ) ;
296
- private static void WriteByte ( byte [ ] b , byte value , long index )
314
+ private static void WriteByte ( byte [ ] b , ulong value , long index , bool isAligned ) => WriteByte ( b , ( byte ) value , index , isAligned ) ;
315
+ private static void WriteByte ( byte [ ] b , byte value , long index , bool isAligned )
297
316
{
298
- int byteIndex = ( int ) ( index / 8 ) ;
299
- int shift = ( int ) ( index % 8 ) ;
300
- byte upper_mask = ( byte ) ( 0xFF << shift ) ;
301
- byte lower_mask = ( byte ) ~ upper_mask ;
317
+ if ( isAligned ) b [ index / 8 ] = value ;
318
+ else
319
+ {
320
+ int byteIndex = ( int ) ( index / 8 ) ;
321
+ int shift = ( int ) ( index % 8 ) ;
322
+ byte upper_mask = ( byte ) ( 0xFF << shift ) ;
302
323
303
- b [ byteIndex ] = ( byte ) ( ( b [ byteIndex ] & lower_mask ) | ( value << shift ) ) ;
304
- if ( shift != 0 && byteIndex + 1 < b . Length )
324
+ b [ byteIndex ] = ( byte ) ( ( b [ byteIndex ] & ( byte ) ~ upper_mask ) | ( value << shift ) ) ;
305
325
b [ byteIndex + 1 ] = ( byte ) ( ( b [ byteIndex + 1 ] & upper_mask ) | ( value >> ( 8 - shift ) ) ) ;
326
+ }
306
327
}
307
- private static void WriteBits ( byte [ ] b , byte value , int bits , int offset , long index )
308
- {
309
- for ( int i = 0 ; i < bits ; ++ i )
310
- WriteBit ( b , ( value & ( 1 << ( i + offset ) ) ) != 0 , index + i ) ;
311
- }
312
- private static void WriteDynamic ( byte [ ] b , int value , int byteCount , long index )
328
+ private static void WriteDynamic ( byte [ ] b , int value , int byteCount , long index , bool isAligned )
313
329
{
314
330
for ( int i = 0 ; i < byteCount ; ++ i )
315
- WriteByte ( b , ( byte ) ( ( value >> ( 8 * i ) ) & 0xFF ) , index + ( 8 * i ) ) ;
331
+ WriteByte ( b , ( byte ) ( ( value >> ( 8 * i ) ) & 0xFF ) , index + ( 8 * i ) , isAligned ) ;
316
332
}
317
333
318
334
private static int BytesToRead ( object i )
319
335
{
336
+ if ( i is byte ) return 1 ;
320
337
bool size ;
321
338
ulong integer ;
339
+ if ( i is decimal ) return BytesToRead ( ( int ) dec_flags . GetValue ( i ) ) + BytesToRead ( ( int ) dec_lo . GetValue ( i ) ) + BytesToRead ( ( int ) dec_mid . GetValue ( i ) ) + BytesToRead ( ( int ) dec_hi . GetValue ( i ) ) ;
322
340
if ( ( size = i is float ) || i is double )
323
341
{
324
342
int bytes = size ? 4 : 8 ;
@@ -337,7 +355,7 @@ private static int BytesToRead(object i)
337
355
else integer = BinaryHelpers . SwapEndian ( ( ulong ) result_holder . GetValue ( 0 ) ) ;
338
356
}
339
357
}
340
- else integer = i as ulong ? ?? 0 ;
358
+ else integer = i as ulong ? ?? i as uint ? ?? i as ushort ? ?? i as byte ? ?? 0 ;
341
359
return
342
360
integer <= 240 ? 1 :
343
361
integer <= 2287 ? 2 :
@@ -352,24 +370,7 @@ private static int BytesToRead(object i)
352
370
353
371
// Supported datatypes for serialization
354
372
private static bool IsSupportedType ( Type t ) => supportedTypes . Contains ( t ) ;
355
-
356
- // Specifies how many bits will be written
357
- private static long GetBitAllocation ( Type t ) =>
358
- t == typeof ( bool ) ? 1 :
359
- t == typeof ( byte ) ? 8 :
360
- t == typeof ( sbyte ) ? 8 :
361
- t == typeof ( short ) ? 16 :
362
- t == typeof ( char ) ? 16 :
363
- t == typeof ( ushort ) ? 16 :
364
- t == typeof ( int ) ? 32 :
365
- t == typeof ( uint ) ? 32 :
366
- t == typeof ( long ) ? 64 :
367
- t == typeof ( ulong ) ? 64 :
368
- t == typeof ( float ) ? 32 :
369
- t == typeof ( double ) ? 64 :
370
- t == typeof ( decimal ) ? 128 :
371
- 0 ; // Unknown type
372
-
373
+
373
374
// Creates a weak reference to the allocated collector so that reuse may be possible
374
375
public void Dispose ( )
375
376
{
0 commit comments