55using System . Numerics ;
66using System . IO ;
77using System . Diagnostics ;
8- using System . Reflection ;
98using System . Runtime . CompilerServices ;
9+ using System . Threading ;
1010
1111namespace Datamodel . Codecs
1212{
@@ -249,96 +249,116 @@ public void Encode(Datamodel dm, string encoding, int encoding_version, Stream s
249249 encoder . Encode ( ) ;
250250 }
251251
252- float [ ] ReadVector ( int dim , BinaryReader reader )
252+ private static readonly Dictionary < RuntimeTypeHandle , int > TypeMap = new Dictionary < RuntimeTypeHandle , int >
253253 {
254- var output = new float [ dim ] ;
255- foreach ( int i in Enumerable . Range ( 0 , dim ) )
256- output [ i ] = reader . ReadSingle ( ) ;
257- return output ;
254+ { typeof ( Element ) . TypeHandle , 0 } ,
255+ { typeof ( int ) . TypeHandle , 1 } ,
256+ { typeof ( float ) . TypeHandle , 2 } ,
257+ { typeof ( bool ) . TypeHandle , 3 } ,
258+ { typeof ( string ) . TypeHandle , 4 } ,
259+ { typeof ( byte [ ] ) . TypeHandle , 5 } ,
260+ { typeof ( TimeSpan ) . TypeHandle , 6 } ,
261+ { typeof ( Color ) . TypeHandle , 7 } ,
262+ { typeof ( Vector2 ) . TypeHandle , 8 } ,
263+ { typeof ( Vector3 ) . TypeHandle , 9 } ,
264+ { typeof ( QAngle ) . TypeHandle , 10 } ,
265+ { typeof ( Vector4 ) . TypeHandle , 11 } ,
266+ { typeof ( Quaternion ) . TypeHandle , 12 } ,
267+ { typeof ( Matrix4x4 ) . TypeHandle , 13 } ,
268+ { typeof ( byte ) . TypeHandle , 14 } ,
269+ { typeof ( UInt64 ) . TypeHandle , 15 }
270+ } ;
271+
272+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
273+ object ? ReadValue ( Datamodel dm , int typeIndex , bool raw_string , BinaryReader reader )
274+ {
275+ return typeIndex switch
276+ {
277+ 0 => ReadElement ( dm , reader ) ,
278+ 1 => reader . ReadInt32 ( ) ,
279+ 2 => reader . ReadSingle ( ) ,
280+ 3 => reader . ReadBoolean ( ) ,
281+ 4 => raw_string ? ReadString_Raw ( reader ) : StringDict ! . ReadString ( reader ) ,
282+ 5 => reader . ReadBytes ( reader . ReadInt32 ( ) ) ,
283+ 6 => TimeSpan . FromTicks ( reader . ReadInt32 ( ) * ( TimeSpan . TicksPerSecond / DatamodelTicksPerSecond ) ) ,
284+ 7 => ReadColor ( reader ) ,
285+ 8 => ReadVector2 ( reader ) ,
286+ 9 => ReadVector3 ( reader ) ,
287+ 10 => ReadQAngle ( reader ) ,
288+ 11 => ReadVector4 ( reader ) ,
289+ 12 => ReadQuaternion ( reader ) ,
290+ 13 => ReadMatrix4x4 ( reader ) ,
291+ 14 => reader . ReadByte ( ) ,
292+ 15 => reader . ReadUInt64 ( ) ,
293+ _ => throw new ArgumentException ( "Cannot read value of type" )
294+ } ;
258295 }
259296
260- object ? ReadValue ( Datamodel dm , Type ? type , bool raw_string , BinaryReader reader )
297+ // Specialized methods to avoid repeated vector allocations
298+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
299+ private object ? ReadElement ( Datamodel dm , BinaryReader reader )
261300 {
262- if ( type == typeof ( Element ) )
301+ var index = reader . ReadInt32 ( ) ;
302+ return index switch
263303 {
264- var index = reader . ReadInt32 ( ) ;
265- if ( index == - 1 )
266- return null ;
267- else if ( index == - 2 )
268- {
269- var id = new Guid ( ReadString_Raw ( reader ) ) ; // yes, it's in ASCII!
270- return dm . AllElements [ id ] ?? new Element ( dm , id ) ;
271- }
272- else
273- return dm . AllElements [ index ] ;
274- }
275- if ( type == typeof ( int ) )
276- return reader . ReadInt32 ( ) ;
277- if ( type == typeof ( float ) )
278- return reader . ReadSingle ( ) ;
279- if ( type == typeof ( bool ) )
280- return reader . ReadBoolean ( ) ;
281- if ( type == typeof ( string ) )
282- return raw_string ? ReadString_Raw ( reader ) : StringDict ! . ReadString ( reader ) ;
283-
284- if ( type == typeof ( byte [ ] ) )
285- return reader . ReadBytes ( reader . ReadInt32 ( ) ) ;
286- if ( type == typeof ( TimeSpan ) )
287- return TimeSpan . FromTicks ( reader . ReadInt32 ( ) * ( TimeSpan . TicksPerSecond / DatamodelTicksPerSecond ) ) ;
304+ - 1 => null ,
305+ - 2 => dm . AllElements [ new Guid ( StringDict . ReadString ( reader ) ) ] ?? new Element ( dm , new Guid ( StringDict . ReadString ( reader ) ) ) ,
306+ _ => dm . AllElements [ index ]
307+ } ;
308+ }
288309
289- if ( type == typeof ( Color ) )
290- {
291- var rgba = reader . ReadBytes ( 4 ) ;
292- return Color . FromBytes ( rgba ) ;
293- }
310+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
311+ private static Color ReadColor ( BinaryReader reader )
312+ {
313+ var rgba = reader . ReadBytes ( 4 ) ;
314+ return Color . FromBytes ( rgba ) ;
315+ }
294316
295- if ( type == typeof ( Vector2 ) )
296- {
297- var ords = ReadVector ( 2 , reader ) ;
298- return new Vector2 ( ords [ 0 ] , ords [ 1 ] ) ;
299- }
300- if ( type == typeof ( Vector3 ) )
301- {
302- var ords = ReadVector ( 3 , reader ) ;
303- return new Vector3 ( ords [ 0 ] , ords [ 1 ] , ords [ 2 ] ) ;
304- }
305- if ( type == typeof ( QAngle ) )
306- {
307- var ords = ReadVector ( 3 , reader ) ;
308- return new QAngle ( ords [ 0 ] , ords [ 1 ] , ords [ 2 ] ) ;
309- }
317+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
318+ private static Vector2 ReadVector2 ( BinaryReader reader )
319+ {
320+ return new Vector2 ( reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
321+ }
310322
311- if ( type == typeof ( Vector4 ) )
312- {
313- var ords = ReadVector ( 4 , reader ) ;
314- return new Vector4 ( ords [ 0 ] , ords [ 1 ] , ords [ 2 ] , ords [ 3 ] ) ;
315- }
316- if ( type == typeof ( Quaternion ) )
317- {
318- var ords = ReadVector ( 4 , reader ) ;
319- return new Quaternion ( ords [ 0 ] , ords [ 1 ] , ords [ 2 ] , ords [ 3 ] ) ;
320- }
321- if ( type == typeof ( Matrix4x4 ) )
322- {
323- var ords = ReadVector ( 4 * 4 , reader ) ;
324- return new Matrix4x4 (
325- ords [ 0 ] , ords [ 1 ] , ords [ 2 ] , ords [ 3 ] ,
326- ords [ 4 ] , ords [ 5 ] , ords [ 6 ] , ords [ 7 ] ,
327- ords [ 8 ] , ords [ 9 ] , ords [ 10 ] , ords [ 11 ] ,
328- ords [ 12 ] , ords [ 13 ] , ords [ 14 ] , ords [ 15 ] ) ;
329- }
323+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
324+ private static Vector3 ReadVector3 ( BinaryReader reader )
325+ {
326+ return new Vector3 ( reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
327+ }
330328
331- if ( type == typeof ( byte ) )
332- return reader . ReadByte ( ) ;
333- if ( type == typeof ( UInt64 ) )
334- return reader . ReadUInt64 ( ) ;
329+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
330+ private static QAngle ReadQAngle ( BinaryReader reader )
331+ {
332+ return new QAngle ( reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
333+ }
335334
336- throw new ArgumentException ( type == null ? "No type provided to GetValue()" : "Cannot read value of type " + type . Name ) ;
335+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
336+ private static Vector4 ReadVector4 ( BinaryReader reader )
337+ {
338+ return new Vector4 ( reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
339+ }
340+
341+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
342+ private static Quaternion ReadQuaternion ( BinaryReader reader )
343+ {
344+ return new Quaternion ( reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
345+ }
346+
347+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
348+ private static Matrix4x4 ReadMatrix4x4 ( BinaryReader reader )
349+ {
350+ // Read all 16 floats directly without intermediate array
351+ return new Matrix4x4 (
352+ reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ,
353+ reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ,
354+ reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ,
355+ reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
337356 }
338357
339358 public Datamodel Decode ( string encoding , int encoding_version , string format , int format_version , Stream stream , DeferredMode defer_mode , ReflectionParams reflectionParams )
340359 {
341- var types = CodecUtilities . GetReflectionTypes ( reflectionParams ) ;
360+ var elementFactoryTypes = CodecUtilities . GetIElementFactoryClasses ( ) ;
361+ var elementFactory = ( IElementFactory ) Activator . CreateInstance ( elementFactoryTypes . First ( ) ) ;
342362
343363 stream . Seek ( 0 , SeekOrigin . Begin ) ;
344364 while ( true )
@@ -349,7 +369,8 @@ public Datamodel Decode(string encoding, int encoding_version, string format, in
349369 var dm = new Datamodel ( format , format_version ) ;
350370
351371 EncodingVersion = encoding_version ;
352- Reader = new BinaryReader ( stream , Datamodel . TextEncoding ) ;
372+
373+ Reader = new BinaryReader ( stream ) ;
353374
354375 if ( EncodingVersion >= 9 )
355376 {
@@ -377,13 +398,14 @@ public Datamodel Decode(string encoding, int encoding_version, string format, in
377398 var id_bits = Reader . ReadBytes ( 16 ) ;
378399 var id = new Guid ( BitConverter . IsLittleEndian ? id_bits : id_bits . Reverse ( ) . ToArray ( ) ) ;
379400
380- if ( ! CodecUtilities . TryConstructCustomElement ( types , dm , type , name , id , out _ ) )
401+ if ( ! CodecUtilities . TryConstructCustomElement ( elementFactory , reflectionParams , dm , type , name , id , out _ ) )
381402 {
382403 // note: constructing an element, adds it to the datamodel.AllElements
383404 _ = new Element ( dm , name , id , type ) ;
384405 }
385406 }
386407
408+
387409 // read attributes (or not, if we're deferred)
388410 foreach ( var elem in dm . AllElements . ToArray ( ) )
389411 {
@@ -414,12 +436,12 @@ public Datamodel Decode(string encoding, int encoding_version, string format, in
414436
415437 public object ? DeferredDecodeAttribute ( Datamodel dm , long offset )
416438 {
417- if ( Reader is null )
439+ if ( Reader is null )
418440 {
419441 throw new InvalidDataException ( "Tried to read a deferred attribute but the reader is invalid" ) ;
420442 }
421443
422- Reader . BaseStream . Seek ( offset , SeekOrigin . Begin ) ;
444+ Reader . BaseStream . Seek ( ( int ) offset , SeekOrigin . Begin ) ;
423445 return DecodeAttribute ( dm , false , Reader ) ;
424446 }
425447
@@ -428,15 +450,16 @@ public Datamodel Decode(string encoding, int encoding_version, string format, in
428450 var types = IdToType ( reader . ReadByte ( ) ) ;
429451
430452 if ( types . Item2 == null )
431- return ReadValue ( dm , types . Item1 , EncodingVersion < 4 || prefix , reader ) ;
453+ return ReadValue ( dm , TypeMap [ types . Item1 . TypeHandle ] , EncodingVersion < 4 || prefix , reader ) ;
432454 else
433455 {
434456 var count = reader . ReadInt32 ( ) ;
435457 var inner_type = types . Item2 ;
436458 var array = CodecUtilities . MakeList ( inner_type , count ) ;
437459
460+ var typeId = TypeMap [ inner_type . TypeHandle ] ;
438461 foreach ( var x in Enumerable . Range ( 0 , count ) )
439- array . Add ( ReadValue ( dm , inner_type , true , reader ) ) ;
462+ array . Add ( ReadValue ( dm , typeId , true , reader ) ) ;
440463
441464 return array ;
442465 }
@@ -449,7 +472,7 @@ void SkipAttribute(BinaryReader reader)
449472 int count = 1 ;
450473 Type ? type = types . Item1 ;
451474
452- if ( type is null )
475+ if ( type is null )
453476 {
454477 throw new InvalidDataException ( "Failed to match id to type" ) ;
455478 }
@@ -554,7 +577,7 @@ public void Encode()
554577
555578 int CountChildren ( Element ? elem , HashSet < Element > counter )
556579 {
557- if ( elem is null )
580+ if ( elem is null )
558581 {
559582 return 0 ;
560583 }
0 commit comments