fix: Adds BitArray support with codegen (#888)

* Adds a custom BitArray class with the following added features:
  * ctor for creating BitArray against read only span
  * ctor for creating BitArray against BinaryReader
  * CopyTo to copy a BitArray to a Span
* Adds BitArray to UO Primitive serialization so it can be codegenned.
This commit is contained in:
Kamron Batman 2021-12-13 09:31:02 -08:00 • committed by GitHub
parent 61e2177011
commit b125146b27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 1489 additions and 19 deletions

View file

@ -43,6 +43,7 @@ namespace SerializableMigration
_ when symbol.IsRectangle3D(compilation) => new[] { "Rect3D" },
_ when symbol.IsRace(compilation) => new[] { "Race" },
_ when symbol.IsMap(compilation) => new[] { "Map" },
_ when symbol.IsBitArray(compilation) => new[] { "BitArray" },
_ => null
};

View file

@ -47,6 +47,8 @@ namespace SerializationGenerator
public const string SERIALIZABLE_FIELD_SAVE_FLAG_ATTRIBUTE = "Server.SerializableFieldSaveFlagAttribute";
public const string SERIALIZABLE_FIELD_DEFAULT_ATTRIBUTE = "Server.SerializableFieldDefaultAttribute";
public const string RAW_SERIALIZABLE_INTERFACE = "Server.IRawSerializable";
// ModernUO modified BitArray
public const string SERVER_BITARRAY_CLASS = "Server.Collections.BitArray";
public static bool IsTimerDrift(this AttributeData attr, Compilation compilation) =>
attr?.IsAttribute(compilation.GetTypeByMetadataName(TIMER_DRIFT_ATTRIBUTE)) == true;
@ -184,6 +186,12 @@ namespace SerializationGenerator
SymbolEqualityComparer.Default
);
public static bool IsBitArray(this ISymbol symbol, Compilation compilation) =>
symbol.Equals(
compilation.GetTypeByMetadataName(SERVER_BITARRAY_CLASS),
SymbolEqualityComparer.Default
);
public static AttributeData? GetAttribute(this ISymbol symbol, ISymbol attrSymbol) =>
symbol
.GetAttributes()

File diff suppressed because it is too large Load diff

View file

@ -13,33 +13,43 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
namespace Server.Collections
namespace Server.Collections;
public static class CollectionThrowStrings
{
public static class CollectionThrowStrings
{
public const string ArgumentOutOfRange_Index =
"Index was out of range. Must be non-negative and less than the size of the collection.";
public const string ArgumentOutOfRange_Index =
"Index was out of range. Must be non-negative and less than the size of the collection.";
public const string ArgumentOutOfRange_NeedNonNegNum = "Non-negative number required.";
public const string ArgumentOutOfRange_NeedNonNegNum = "Non-negative number required.";
public const string Argument_InvalidOffLen =
"Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.";
public const string Argument_InvalidOffLen =
"Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.";
public const string Argument_AddingDuplicate = "An item with the same value has already been added. Value: {0}";
public const string Argument_AddingDuplicate = "An item with the same value has already been added. Value: {0}";
public const string Arg_ArrayPlusOffTooSmall =
"Destination array is not long enough to copy all the items in the collection. Check array index and length.";
public const string Arg_ArrayPlusOffTooSmall =
"Destination array is not long enough to copy all the items in the collection. Check array index and length.";
public const string InvalidOperation_ConcurrentOperationsNotSupported =
"Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.";
public const string InvalidOperation_ConcurrentOperationsNotSupported =
"Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.";
public const string InvalidOperation_EnumFailedVersion =
"Collection was modified after the enumerator was instantiated.";
public const string InvalidOperation_EnumFailedVersion =
"Collection was modified after the enumerator was instantiated.";
public const string InvalidOperation_EmptyQueue = "Queue empty.";
public const string InvalidOperation_EmptyQueue = "Queue empty.";
public const string InvalidOperation_EnumNotStarted = "Enumeration has not started. Call MoveNext.";
public const string InvalidOperation_EnumNotStarted = "Enumeration has not started. Call MoveNext.";
public const string InvalidOperation_EnumEnded = "Enumeration already finished.";
}
public const string InvalidOperation_EnumEnded = "Enumeration already finished.";
public const string Argument_ArrayTooLarge =
"The input array length must not exceed Int32.MaxValue / {0}. Otherwise BitArray.Length would exceed Int32.MaxValue.";
public const string Arg_ArrayLengthsDiffer = "Array lengths must be the same.";
public const string Arg_RankMultiDimNotSupported =
"Only single dimensional arrays are supported for the requested action.";
public const string Arg_BitArrayTypeUnsupported =
"Only supported array types for CopyTo on BitArrays are Boolean[], Int32[] and Byte[].";
}

View file

@ -16,6 +16,7 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
using Server.Collections;
namespace Server
{
@ -78,6 +79,15 @@ namespace Server
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Read(Span<byte> buffer) => _reader.Read(buffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BitArray ReadBitArray()
{
var length = ((IGenericReader)this).ReadEncodedInt();
// BinaryReader doesn't expose a Span slice of the buffer, so we use a custom ctor
return new BitArray(_reader, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public long Seek(long offset, SeekOrigin origin) => _reader.BaseStream.Seek(offset, origin);

View file

@ -19,6 +19,7 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using Server.Collections;
using Server.Text;
namespace Server
@ -156,6 +157,19 @@ namespace Server
return length;
}
public BitArray ReadBitArray()
{
var length = ((IGenericReader)this).ReadEncodedInt();
if (length > _buffer.Length - _position)
{
throw new OutOfMemoryException();
}
var bitArray = new BitArray(_buffer.AsSpan(_position, length));
_position += length;
return bitArray;
}
public virtual long Seek(long offset, SeekOrigin origin)
{
Debug.Assert(

View file

@ -18,6 +18,7 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using Server.Collections;
using Server.Text;
namespace Server
@ -134,6 +135,16 @@ namespace Server
}
}
public void Write(BitArray bitArray)
{
var byteLength = BitArray.GetByteArrayLengthFromBitLength(bitArray.Length);
FlushIfNeeded(byteLength + 4);
((IGenericWriter)this).WriteEncodedInt(byteLength);
bitArray.CopyTo(_buffer.AsSpan((int)Index, byteLength));
Index += byteLength;
}
public virtual long Seek(long offset, SeekOrigin origin)
{
Debug.Assert(

View file

@ -16,6 +16,7 @@
using System;
using System.IO;
using System.Net;
using Server.Collections;
namespace Server
{
@ -116,6 +117,8 @@ namespace Server
return new Guid(bytes);
}
BitArray ReadBitArray();
long Seek(long offset, SeekOrigin origin);
}
}

View file

@ -16,6 +16,7 @@
using System;
using System.IO;
using System.Net;
using Server.Collections;
namespace Server
{
@ -160,6 +161,8 @@ namespace Server
Write(stack);
}
void Write(BitArray bitArray);
long Seek(long offset, SeekOrigin origin);
}
}