Improved efficiency of startup methods.

- ShpReader will copy the input stream into memory just once rather than for every header.
- ShpReader.CopyImageData switched to use Array.Copy since that uses some unsafe magic for speed.
- In ActorInfo, cache a GetType call and prevent needless materialization in PrerequisitesOf.
- In ObjectCreator, cache type and ctor lookups since these are expensive and often repeated.
- Implement IReadOnlyDictionary<T, U> on Cache<T, U> to provide some supplementary functions.
- In TechTree.GatherOwnedPrerequisites, rearrange a Boolean 'and' expression to evaluate expensive functions later in the chain, and use ContainsKey to speed up name check.
This commit is contained in:
RoosterDragon
2014-05-28 21:29:29 +01:00
parent 334a210231
commit e63f330717
8 changed files with 93 additions and 77 deletions

View File

@@ -12,58 +12,58 @@ namespace OpenRA.FileFormats
{
public static class Format40
{
public static int DecodeInto( byte[] src, byte[] dest )
public static int DecodeInto(byte[] src, byte[] dest, int srcOffset)
{
var ctx = new FastByteReader(src);
var ctx = new FastByteReader(src, srcOffset);
int destIndex = 0;
while( true )
while (true)
{
byte i = ctx.ReadByte();
if( ( i & 0x80 ) == 0 )
if ((i & 0x80) == 0)
{
int count = i & 0x7F;
if( count == 0 )
if (count == 0)
{
// case 6
count = ctx.ReadByte();
byte value = ctx.ReadByte();
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[ destIndex ] ^= value;
for (int end = destIndex + count; destIndex < end; destIndex++)
dest[destIndex] ^= value;
}
else
{
// case 5
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
for (int end = destIndex + count; destIndex < end; destIndex++)
dest[destIndex] ^= ctx.ReadByte();
}
}
else
{
int count = i & 0x7F;
if( count == 0 )
if (count == 0)
{
count = ctx.ReadWord();
if( count == 0 )
if (count == 0)
return destIndex;
if( ( count & 0x8000 ) == 0 )
if ((count & 0x8000) == 0)
{
// case 2
destIndex += ( count & 0x7FFF );
destIndex += (count & 0x7FFF);
}
else if( ( count & 0x4000 ) == 0 )
else if ((count & 0x4000) == 0)
{
// case 3
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
for (int end = destIndex + (count & 0x3FFF); destIndex < end; destIndex++)
dest[destIndex] ^= ctx.ReadByte();
}
else
{
// case 4
byte value = ctx.ReadByte();
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
dest[ destIndex ] ^= value;
for (int end = destIndex + (count & 0x3FFF); destIndex < end; destIndex++)
dest[destIndex] ^= value;
}
}
else

View File

@@ -16,11 +16,12 @@ namespace OpenRA.FileFormats
class FastByteReader
{
readonly byte[] src;
int offset = 0;
int offset;
public FastByteReader(byte[] src)
public FastByteReader(byte[] src, int offset = 0)
{
this.src = src;
this.offset = offset;
}
public bool Done() { return offset >= src.Length; }
@@ -59,9 +60,9 @@ namespace OpenRA.FileFormats
}
}
public static int DecodeInto(byte[] src, byte[] dest)
public static int DecodeInto(byte[] src, byte[] dest, int srcOffset = 0)
{
var ctx = new FastByteReader(src);
var ctx = new FastByteReader(src, srcOffset);
var destIndex = 0;
while (true)

View File

@@ -67,6 +67,9 @@ namespace OpenRA.FileFormats
int recurseDepth = 0;
readonly int imageCount;
readonly long shpBytesFileOffset;
readonly byte[] shpBytes;
public ShpReader(Stream stream)
{
imageCount = stream.ReadUInt16();
@@ -93,22 +96,16 @@ namespace OpenRA.FileFormats
throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.FileOffset, h.RefOffset));
}
shpBytesFileOffset = stream.Position;
shpBytes = stream.ReadBytes((int)(stream.Length - stream.Position));
foreach (var h in headers)
Decompress(stream, h);
Decompress(h);
spriteFrames = Exts.Lazy(() => headers.Cast<ISpriteFrame>());
}
static byte[] ReadCompressedData(Stream stream, ImageHeader h)
{
stream.Position = h.FileOffset;
// Actually, far too big. There's no length field with the correct length though :(
var compressedLength = (int)(stream.Length - stream.Position);
return stream.ReadBytes(compressedLength);
}
void Decompress(Stream stream, ImageHeader h)
void Decompress(ImageHeader h)
{
// No extra work is required for empty frames
if (h.Size.Width == 0 || h.Size.Height == 0)
@@ -125,19 +122,19 @@ namespace OpenRA.FileFormats
if (h.RefImage.Data == null)
{
++recurseDepth;
Decompress(stream, h.RefImage);
Decompress(h.RefImage);
--recurseDepth;
}
h.Data = CopyImageData(h.RefImage.Data);
Format40.DecodeInto(ReadCompressedData(stream, h), h.Data);
Format40.DecodeInto(shpBytes, h.Data, (int)(h.FileOffset - shpBytesFileOffset));
break;
}
case Format.Format80:
{
var imageBytes = new byte[Size.Width * Size.Height];
Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
Format80.DecodeInto(shpBytes, imageBytes, (int)(h.FileOffset - shpBytesFileOffset));
h.Data = imageBytes;
break;
}
@@ -150,9 +147,7 @@ namespace OpenRA.FileFormats
byte[] CopyImageData(byte[] baseImage)
{
var imageData = new byte[Size.Width * Size.Height];
for (var i = 0; i < Size.Width * Size.Height; i++)
imageData[i] = baseImage[i];
Array.Copy(baseImage, imageData, imageData.Length);
return imageData;
}