diff --git a/DBCD.IO/Common/IPrimitiveSetter.cs b/DBCD.IO/Common/IPrimitiveSetter.cs new file mode 100644 index 0000000..df488ae --- /dev/null +++ b/DBCD.IO/Common/IPrimitiveSetter.cs @@ -0,0 +1,36 @@ +using System; +using System.Runtime.CompilerServices; + +namespace DBCD.IO.Common; + +public interface IPrimitiveSetter +{ + // Value type setter for value type objects + void SetValue(T refObject, TValue value) where TValue : struct; + + // Fallback setter for value type assignments + void SetObject(T target, object value); +} + +public class PrimitiveSetter : IPrimitiveSetter +{ + private readonly Action _setter; + + public PrimitiveSetter(Action setter) + { + _setter = setter; + } + + public void SetValue(T target, TValue value) where TValue : struct + { + if (typeof(TValue) == typeof(TField)) + _setter(target, Unsafe.As(ref value)); + else + _setter(target, (TField)Convert.ChangeType(value, typeof(TField))); + } + + public void SetObject(T target, object value) + { + _setter(target, (TField)value); + } +} \ No newline at end of file diff --git a/DBCD.IO/Extensions.cs b/DBCD.IO/Extensions.cs index b7661ed..026f916 100644 --- a/DBCD.IO/Extensions.cs +++ b/DBCD.IO/Extensions.cs @@ -9,20 +9,29 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using DBCD.IO.Common; namespace DBCD.IO { static class Extensions { - public static Action GetSetter(this FieldInfo fieldInfo) + public static IPrimitiveSetter GetSetter(this FieldInfo fieldInfo) { - var paramExpression = Expression.Parameter(typeof(T)); - var propertyExpression = Expression.Field(paramExpression, fieldInfo); - var valueExpression = Expression.Parameter(typeof(object)); - var convertExpression = Expression.Convert(valueExpression, fieldInfo.FieldType); - var assignExpression = Expression.Assign(propertyExpression, convertExpression); + Type fieldType = fieldInfo.FieldType; + + var target = Expression.Parameter(typeof(T), "target"); + var value = Expression.Parameter(fieldType, "value"); + var field = Expression.Field(target, fieldInfo); + var assign = Expression.Assign(field, value); + + // Compile to exact Action + var actionType = typeof(Action<,>).MakeGenericType(typeof(T), fieldType); + var lambda = Expression.Lambda(actionType, assign, target, value); + object compiledDelegate = lambda.Compile(); - return Expression.Lambda>(assignExpression, paramExpression, valueExpression).Compile(); + var closedSetterType = typeof(PrimitiveSetter<,>).MakeGenericType(typeof(T), fieldType); + var ctor = closedSetterType.GetConstructor(new[] { actionType }); + return (IPrimitiveSetter)ctor?.Invoke(new[] { compiledDelegate }); } public static Func GetGetter(this FieldInfo fieldInfo) diff --git a/DBCD.IO/FieldCache.cs b/DBCD.IO/FieldCache.cs index f8a08dd..e48d880 100644 --- a/DBCD.IO/FieldCache.cs +++ b/DBCD.IO/FieldCache.cs @@ -1,6 +1,7 @@ using DBCD.IO.Attributes; using System; using System.Reflection; +using DBCD.IO.Common; namespace DBCD.IO { @@ -9,7 +10,7 @@ class FieldCache public readonly FieldInfo Field; public readonly bool IsArray = false; public readonly bool IsLocalisedString = false; - public readonly Action Setter; + public readonly IPrimitiveSetter Setter; public readonly Func Getter; public readonly LocaleAttribute LocaleInfo; diff --git a/DBCD.IO/Readers/HTFXReader.cs b/DBCD.IO/Readers/HTFXReader.cs index de7f3de..8e74bd1 100644 --- a/DBCD.IO/Readers/HTFXReader.cs +++ b/DBCD.IO/Readers/HTFXReader.cs @@ -31,19 +31,22 @@ public HTFXRow(BitReader data, IHotfixEntry hotfixEntry) Id = hotfixEntry.RecordId; } - private static Dictionary> simpleReaders = new Dictionary> + private static class SingleReaderCache { - [typeof(ulong)] = (data) => GetFieldValue(data), - [typeof(long)] = (data) => GetFieldValue(data), - [typeof(float)] = (data) => GetFieldValue(data), - [typeof(int)] = (data) => GetFieldValue(data), - [typeof(uint)] = (data) => GetFieldValue(data), - [typeof(short)] = (data) => GetFieldValue(data), - [typeof(ushort)] = (data) => GetFieldValue(data), - [typeof(sbyte)] = (data) => GetFieldValue(data), - [typeof(byte)] = (data) => GetFieldValue(data), - [typeof(string)] = (data) => data.ReadCString(), - }; + public static readonly Dictionary, BitReader>> Readers = new() + { + { typeof(long), (record, info, data) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(ulong), (record, info, data) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(float), (record, info, data) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(uint), (record, info, data) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(int), (record, info, data) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(ushort), (record, info, data) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(short), (record, info, data) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(byte), (record, info, data) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(sbyte), (record, info, data) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(string), (record, info, data) => info.Setter.SetObject(record, data.ReadCString()) } + }; + } private static Dictionary> arrayReaders = new Dictionary> { @@ -68,36 +71,36 @@ public void GetFields(FieldCache[] fields, T entry) FieldCache info = fields[i]; if (info.IndexMapField) { - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - - object value = null; - + if (info.IsArray) { if (arrayReaders.TryGetValue(info.MetaDataFieldType, out var reader)) - value = reader(m_data, info.Cardinality); + info.Setter.SetObject(entry, reader(m_data, info.Cardinality)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } else { - if (simpleReaders.TryGetValue(info.MetaDataFieldType, out var reader)) - value = reader(m_data); + if (SingleReaderCache.Readers.TryGetValue(info.MetaDataFieldType, out var reader)) + reader(entry, info, m_data); else throw new Exception("Unhandled field type: " + typeof(T).Name); } + /* + The strongly typed Setter does take care of converting mismatching types already if (info.IsNonInlineRelation) { - var casted = Convert.ChangeType(value, info.FieldType); - info.Setter(entry, casted); - } - else - { - info.Setter(entry, value); + var casted = Convert.ChangeType(info.Getter(entry), info.FieldType); + info.Setter.SetObject(entry, casted); } + */ } } @@ -114,8 +117,7 @@ private static T[] GetFieldValueArray(BitReader r, int cardinality) where T : return array; } - - + #region Interface Methods public IDBRow Clone() diff --git a/DBCD.IO/Readers/WDB2Reader.cs b/DBCD.IO/Readers/WDB2Reader.cs index ce6e446..e0a95c9 100644 --- a/DBCD.IO/Readers/WDB2Reader.cs +++ b/DBCD.IO/Readers/WDB2Reader.cs @@ -25,19 +25,23 @@ public WDB2Row(BaseReader reader, BitReader data, int recordIndex) Id = m_recordIndex = recordIndex + 1; } - private static Dictionary, BaseReader, object>> simpleReaders = new Dictionary, BaseReader, object>> + private static class SingleReaderCache { - [typeof(long)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(float)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(int)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(uint)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(short)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(ushort)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(sbyte)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(byte)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(string)] = (data, stringTable, header) => stringTable[GetFieldValue(data)], - }; - + public static readonly Dictionary, BitReader, Dictionary>> Readers = new() + { + { typeof(ulong), (record, info, data, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(long), (record, info, data, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(float), (record, info, data, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(uint), (record, info, data, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(int), (record, info, data, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(ushort), (record, info, data, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(short), (record, info, data, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(byte), (record, info, data, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(sbyte), (record, info, data, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(string), (record, info, data, stringTable) => info.Setter.SetObject(record, stringTable[GetFieldValue(data)]) } + }; + } + private static Dictionary, int, object>> arrayReaders = new Dictionary, int, object>> { [typeof(ulong[])] = (data, stringTable, cardinality) => GetFieldValueArray(data, cardinality), @@ -60,34 +64,31 @@ public void GetFields(FieldCache[] fields, T entry) if (info.IndexMapField) { Id = GetFieldValue(Data); - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + + if (info.FieldType == typeof(T)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; - if (info.IsArray) { if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_reader.StringTable, info.Cardinality); + info.Setter.SetObject(entry, reader(Data, m_reader.StringTable, info.Cardinality)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } else if (info.IsLocalisedString) { Data.Position += 32 * info.LocaleInfo.Locale; - value = simpleReaders[typeof(string)](Data, m_reader.StringTable, m_reader); + info.Setter.SetObject(entry, m_reader.StringTable[GetFieldValue(Data)]); Data.Position += 32 * (info.LocaleInfo.LocaleCount - info.LocaleInfo.Locale); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Data, m_reader.StringTable); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } @@ -104,7 +105,7 @@ private static T[] GetFieldValueArray(BitReader r, int cardinality) where T : return array; } - + public IDBRow Clone() { return (IDBRow)MemberwiseClone(); diff --git a/DBCD.IO/Readers/WDB3Reader.cs b/DBCD.IO/Readers/WDB3Reader.cs index 2184096..468579c 100644 --- a/DBCD.IO/Readers/WDB3Reader.cs +++ b/DBCD.IO/Readers/WDB3Reader.cs @@ -30,19 +30,29 @@ public WDB3Row(BaseReader reader, BitReader data, int id, int recordIndex) m_dataPosition = Data.Position; } - private static Dictionary, BaseReader, object>> simpleReaders = new Dictionary, BaseReader, object>> + private static class SingleReaderCache { - [typeof(long)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(float)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(int)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(uint)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(short)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(ushort)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(sbyte)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(byte)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(string)] = (data, stringTable, header) => header.Flags.HasFlagExt(DB2Flags.Sparse) ? data.ReadCString() : stringTable[GetFieldValue(data)], - }; - + public static readonly Dictionary, BitReader, Dictionary, BaseReader>> Readers = new() + { + { typeof(ulong), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(long), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(float), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(uint), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(int), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(ushort), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(short), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(byte), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(sbyte), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(string), (record, info, data, stringTable, header) => + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : stringTable[GetFieldValue(data)]; + info.Setter.SetObject(record, stringValue); + } + } + }; + } + private static Dictionary, int, object>> arrayReaders = new Dictionary, int, object>> { [typeof(ulong[])] = (data, stringTable, cardinality) => GetFieldValueArray(data, cardinality), @@ -74,36 +84,33 @@ public void GetFields(FieldCache[] fields, T entry) else Id = GetFieldValue(Data); - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; int fieldIndex = i - indexFieldOffSet; // 0x2 SecondaryKey if (fieldIndex >= m_reader.FieldsCount) { - info.Setter(entry, Convert.ChangeType(m_reader.ForeignKeyData[Id - m_reader.MinIndex], info.FieldType)); + info.Setter.SetObject(entry, Convert.ChangeType(m_reader.ForeignKeyData[Id - m_reader.MinIndex], info.FieldType)); continue; } if (info.IsArray) { if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_reader.StringTable, info.Cardinality); + info.Setter.SetObject(entry, reader(Data, m_reader.StringTable, info.Cardinality)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Data, m_reader.StringTable, m_reader); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } @@ -120,7 +127,7 @@ private static T[] GetFieldValueArray(BitReader r, int cardinality) where T : return array; } - + public IDBRow Clone() { return (IDBRow)MemberwiseClone(); diff --git a/DBCD.IO/Readers/WDB4Reader.cs b/DBCD.IO/Readers/WDB4Reader.cs index 361c91d..4cd63c8 100644 --- a/DBCD.IO/Readers/WDB4Reader.cs +++ b/DBCD.IO/Readers/WDB4Reader.cs @@ -30,19 +30,29 @@ public WDB4Row(BaseReader reader, BitReader data, int id, int recordIndex) m_dataPosition = Data.Position; } - private static Dictionary, BaseReader, object>> simpleReaders = new Dictionary, BaseReader, object>> + private static class SingleReaderCache { - [typeof(long)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(float)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(int)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(uint)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(short)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(ushort)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(sbyte)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(byte)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(string)] = (data, stringTable, header) => header.Flags.HasFlagExt(DB2Flags.Sparse) ? data.ReadCString() : stringTable[GetFieldValue(data)], - }; - + public static readonly Dictionary, BitReader, Dictionary, BaseReader>> Reader = new() + { + { typeof(ulong), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(long), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(float), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(uint), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(int), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(ushort), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(short), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(byte), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(sbyte), (record, info, data, _, _) => info.Setter.SetValue(record, GetFieldValue(data)) }, + { typeof(string), (record, info, data, stringTable, header) => + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : stringTable[GetFieldValue(data)]; + info.Setter.SetObject(record, stringValue); + } + } + }; + } + private static Dictionary, int, object>> arrayReaders = new Dictionary, int, object>> { [typeof(ulong[])] = (data, stringTable, cardinality) => GetFieldValueArray(data, cardinality), @@ -74,36 +84,33 @@ public void GetFields(FieldCache[] fields, T entry) else Id = GetFieldValue(Data); - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; int fieldIndex = i - indexFieldOffSet; // 0x2 SecondaryKey if (fieldIndex >= m_reader.FieldsCount) { - info.Setter(entry, Convert.ChangeType(m_reader.ForeignKeyData[Id - m_reader.MinIndex], info.FieldType)); + info.Setter.SetObject(entry, Convert.ChangeType(m_reader.ForeignKeyData[Id - m_reader.MinIndex], info.FieldType)); continue; } if (info.IsArray) { if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_reader.StringTable, info.Cardinality); + info.Setter.SetObject(entry, reader(Data, m_reader.StringTable, info.Cardinality)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } + else if (SingleReaderCache.Reader.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Data, m_reader.StringTable, m_reader); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } diff --git a/DBCD.IO/Readers/WDB5Reader.cs b/DBCD.IO/Readers/WDB5Reader.cs index ed2e65d..8ce17c5 100644 --- a/DBCD.IO/Readers/WDB5Reader.cs +++ b/DBCD.IO/Readers/WDB5Reader.cs @@ -32,19 +32,29 @@ public WDB5Row(BaseReader reader, BitReader data, int id, int recordIndex) m_fieldMeta = reader.Meta; } - private static Dictionary, BaseReader, object>> simpleReaders = new Dictionary, BaseReader, object>> + private static class SingleReaderCache { - [typeof(long)] = (data, fieldMeta, stringTable, header) => GetFieldValue(data, fieldMeta), - [typeof(float)] = (data, fieldMeta, stringTable, header) => GetFieldValue(data, fieldMeta), - [typeof(int)] = (data, fieldMeta, stringTable, header) => GetFieldValue(data, fieldMeta), - [typeof(uint)] = (data, fieldMeta, stringTable, header) => GetFieldValue(data, fieldMeta), - [typeof(short)] = (data, fieldMeta, stringTable, header) => GetFieldValue(data, fieldMeta), - [typeof(ushort)] = (data, fieldMeta, stringTable, header) => GetFieldValue(data, fieldMeta), - [typeof(sbyte)] = (data, fieldMeta, stringTable, header) => GetFieldValue(data, fieldMeta), - [typeof(byte)] = (data, fieldMeta, stringTable, header) => GetFieldValue(data, fieldMeta), - [typeof(string)] = (data, fieldMeta, stringTable, header) => header.Flags.HasFlagExt(DB2Flags.Sparse) ? data.ReadCString() : stringTable[GetFieldValue(data, fieldMeta)], - }; - + public static readonly Dictionary, BitReader, FieldMetaData , Dictionary, BaseReader>> Readers = new() + { + { typeof(ulong), (record, info, data, fieldMeta, _, _) => info.Setter.SetValue(record, GetFieldValue(data, fieldMeta)) }, + { typeof(long), (record, info, data, fieldMeta, _, _) => info.Setter.SetValue(record, GetFieldValue(data, fieldMeta)) }, + { typeof(float), (record, info, data, fieldMeta, _, _) => info.Setter.SetValue(record, GetFieldValue(data, fieldMeta)) }, + { typeof(uint), (record, info, data, fieldMeta, _, _) => info.Setter.SetValue(record, GetFieldValue(data, fieldMeta)) }, + { typeof(int), (record, info, data, fieldMeta, _, _) => info.Setter.SetValue(record, GetFieldValue(data, fieldMeta)) }, + { typeof(ushort), (record, info, data, fieldMeta, _, _) => info.Setter.SetValue(record, GetFieldValue(data, fieldMeta)) }, + { typeof(short), (record, info, data, fieldMeta, _, _) => info.Setter.SetValue(record, GetFieldValue(data, fieldMeta)) }, + { typeof(byte), (record, info, data, fieldMeta, _, _) => info.Setter.SetValue(record, GetFieldValue(data, fieldMeta)) }, + { typeof(sbyte), (record, info, data, fieldMeta, _, _) => info.Setter.SetValue(record, GetFieldValue(data, fieldMeta)) }, + { typeof(string), (record, info, data, fieldMeta, stringTable, header) => + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : stringTable[GetFieldValue(data, fieldMeta)]; + info.Setter.SetObject(record, stringValue); + } + } + }; + } + private static Dictionary, int, object>> arrayReaders = new Dictionary, int, object>> { [typeof(ulong[])] = (data, fieldMeta, stringTable, cardinality) => GetFieldValueArray(data, fieldMeta, cardinality), @@ -81,17 +91,19 @@ public void GetFields(FieldCache[] fields, T entry) else Id = GetFieldValue(Data, m_fieldMeta[i]); - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; int fieldIndex = i - indexFieldOffSet; // 0x2 SecondaryKey if (fieldIndex >= m_reader.Meta.Length) { - info.Setter(entry, Convert.ChangeType(m_reader.ForeignKeyData[Id - m_reader.MinIndex], info.FieldType)); + info.Setter.SetObject(entry, Convert.ChangeType(m_reader.ForeignKeyData[Id - m_reader.MinIndex], info.FieldType)); continue; } @@ -101,19 +113,14 @@ public void GetFields(FieldCache[] fields, T entry) SetCardinality(info, fieldIndex); if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_fieldMeta[fieldIndex], m_reader.StringTable, info.Cardinality); + info.Setter.SetObject(entry, reader(Data, m_fieldMeta[fieldIndex], m_reader.StringTable, info.Cardinality)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Data, m_fieldMeta[fieldIndex], m_reader.StringTable, m_reader); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_fieldMeta[fieldIndex], m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } @@ -152,7 +159,7 @@ private static T[] GetFieldValueArray(BitReader r, FieldMetaData fieldMeta, i return array; } - + public IDBRow Clone() { return (IDBRow)MemberwiseClone(); diff --git a/DBCD.IO/Readers/WDB6Reader.cs b/DBCD.IO/Readers/WDB6Reader.cs index 0d4dea4..b0f5d80 100644 --- a/DBCD.IO/Readers/WDB6Reader.cs +++ b/DBCD.IO/Readers/WDB6Reader.cs @@ -36,18 +36,29 @@ public WDB6Row(BaseReader reader, BitReader data, int id, int recordIndex) Id = id; } - private static Dictionary, Dictionary, BaseReader, object>> simpleReaders = new Dictionary, Dictionary, BaseReader, object>> + private static class SingleReaderCache { - [typeof(long)] = (id, data, fieldMeta, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, commonData), - [typeof(float)] = (id, data, fieldMeta, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, commonData), - [typeof(int)] = (id, data, fieldMeta, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, commonData), - [typeof(uint)] = (id, data, fieldMeta, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, commonData), - [typeof(short)] = (id, data, fieldMeta, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, commonData), - [typeof(ushort)] = (id, data, fieldMeta, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, commonData), - [typeof(sbyte)] = (id, data, fieldMeta, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, commonData), - [typeof(byte)] = (id, data, fieldMeta, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, commonData), - [typeof(string)] = (id, data, fieldMeta, commonData, stringTable, header) => header.Flags.HasFlagExt(DB2Flags.Sparse) ? data.ReadCString() : stringTable[GetFieldValue(id, data, fieldMeta, commonData)], - }; + public static readonly Dictionary, int, BitReader, FieldMetaData, Dictionary, Dictionary, BaseReader>> Readers = new() + { + { typeof(ulong), (record, info, id, data, fieldMeta, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)) }, + { typeof(long), (record, info, id, data, fieldMeta, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)) }, + { typeof(float), (record, info, id, data, fieldMeta, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)) }, + { typeof(uint), (record, info, id, data, fieldMeta, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)) }, + { typeof(int), (record, info, id, data, fieldMeta, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)) }, + { typeof(ushort), (record, info, id, data, fieldMeta, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)) }, + { typeof(short), (record, info, id, data, fieldMeta, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)) }, + { typeof(byte), (record, info, id, data, fieldMeta, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)) }, + { typeof(sbyte), (record, info, id, data, fieldMeta, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)) }, + { typeof(string), (record, info, id, data, fieldMeta, commonData, stringTable, header) => + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : stringTable[GetFieldValue(id, data, fieldMeta, commonData)]; + info.Setter.SetObject(record, stringValue); + } + + } + }; + } private static Dictionary, Dictionary, int, object>> arrayReaders = new Dictionary, Dictionary, int, object>> { @@ -79,18 +90,20 @@ public void GetFields(FieldCache[] fields, T entry) indexFieldOffSet++; else Id = GetFieldValue(0, Data, m_fieldMeta[i], CommonData?[i]); - - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; int fieldIndex = i - indexFieldOffSet; // 0x2 SecondaryKey if (fieldIndex >= m_reader.Meta.Length) { - info.Setter(entry, Convert.ChangeType(m_reader.ForeignKeyData[Id - m_reader.MinIndex], info.FieldType)); + info.Setter.SetObject(entry, Convert.ChangeType(m_reader.ForeignKeyData[Id - m_reader.MinIndex], info.FieldType)); continue; } @@ -100,19 +113,14 @@ public void GetFields(FieldCache[] fields, T entry) SetCardinality(info, fieldIndex); if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Id, Data, m_fieldMeta[fieldIndex], CommonData?[fieldIndex], m_reader.StringTable, info.Cardinality); + info.Setter.SetObject(entry, reader(Id, Data, m_fieldMeta[fieldIndex], CommonData?[fieldIndex], m_reader.StringTable, info.Cardinality)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Id, Data, m_fieldMeta[fieldIndex], CommonData?[fieldIndex], m_reader.StringTable, m_reader); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Id, Data, m_fieldMeta[fieldIndex], CommonData?[fieldIndex], m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } @@ -160,6 +168,37 @@ private static T[] GetFieldValueArray(int Id, BitReader r, FieldMetaData fiel return array; } + private static void ReadStronglyTyped(T record, FieldCache info, int id, BitReader data, FieldMetaData fieldMeta, Dictionary commonData, Dictionary stringTable, BaseReader header) + { + // This is not very pretty, but it is required to avoid boxing the read values + if (info.FieldType == typeof(ulong)) + info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)); + else if (info.FieldType == typeof(long)) + info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)); + else if (info.FieldType == typeof(float)) + info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)); + else if (info.FieldType == typeof(uint)) + info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)); + else if (info.FieldType == typeof(int)) + info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)); + else if (info.FieldType == typeof(ushort)) + info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)); + else if (info.FieldType == typeof(short)) + info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)); + else if (info.FieldType == typeof(byte)) + info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)); + else if (info.FieldType == typeof(sbyte)) + info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, commonData)); + else if (info.FieldType == typeof(string)) + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : stringTable[GetFieldValue(id, data, fieldMeta, commonData)]; + info.Setter.SetObject(record, stringValue); + } + else + throw new Exception("Unhandled field type: " + typeof(T).Name); + } + public IDBRow Clone() { return (IDBRow)MemberwiseClone(); diff --git a/DBCD.IO/Readers/WDBCReader.cs b/DBCD.IO/Readers/WDBCReader.cs index 0f3d6e9..9a36f94 100644 --- a/DBCD.IO/Readers/WDBCReader.cs +++ b/DBCD.IO/Readers/WDBCReader.cs @@ -25,19 +25,23 @@ public WDBCRow(BaseReader reader, BitReader data, int recordIndex) Id = m_recordIndex = recordIndex + 1; } - private static Dictionary, BaseReader, object>> simpleReaders = new Dictionary, BaseReader, object>> + private static class SingleReaderCache { - [typeof(long)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(float)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(int)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(uint)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(short)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(ushort)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(sbyte)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(byte)] = (data, stringTable, header) => GetFieldValue(data), - [typeof(string)] = (data, stringTable, header) => stringTable[GetFieldValue(data)], - }; - + public static readonly Dictionary, BitReader, Dictionary>> Readers = new() + { + { typeof(long), (entry, info, data, _) => info.Setter.SetValue(entry, GetFieldValue(data)) }, + { typeof(ulong), (entry, info, data, _) => info.Setter.SetValue(entry, GetFieldValue(data)) }, + { typeof(float), (entry, info, data, _) => info.Setter.SetValue(entry, GetFieldValue(data)) }, + { typeof(uint), (entry, info, data, _) => info.Setter.SetValue(entry, GetFieldValue(data)) }, + { typeof(int), (entry, info, data, _) => info.Setter.SetValue(entry, GetFieldValue(data)) }, + { typeof(ushort), (entry, info, data, _) => info.Setter.SetValue(entry, GetFieldValue(data)) }, + { typeof(short), (entry, info, data, _) => info.Setter.SetValue(entry, GetFieldValue(data)) }, + { typeof(byte), (entry, info, data, _) => info.Setter.SetValue(entry, GetFieldValue(data)) }, + { typeof(sbyte), (entry, info, data, _) => info.Setter.SetValue(entry, GetFieldValue(data)) }, + { typeof(string), (entry, info, data, stringTable) => info.Setter.SetObject(entry, stringTable[GetFieldValue(data)]) } + }; + } + private static Dictionary, int, object>> arrayReaders = new Dictionary, int, object>> { [typeof(ulong[])] = (data, stringTable, cardinality) => GetFieldValueArray(data, cardinality), @@ -61,34 +65,30 @@ public void GetFields(FieldCache[] fields, T entry) if (info.IndexMapField) { Id = GetFieldValue(Data); - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; - if (info.IsArray) { if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_reader.StringTable, info.Cardinality); + info.Setter.SetObject(entry, reader(Data, m_reader.StringTable, info.Cardinality)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } else if (info.IsLocalisedString) { Data.Position += 32 * info.LocaleInfo.Locale; - value = simpleReaders[typeof(string)](Data, m_reader.StringTable, m_reader); + info.Setter.SetObject(entry, m_reader.StringTable[GetFieldValue(Data)]); Data.Position += 32 * (info.LocaleInfo.LocaleCount - info.LocaleInfo.Locale); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader.Invoke(entry, info, Data, m_reader.StringTable); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } diff --git a/DBCD.IO/Readers/WDC1Reader.cs b/DBCD.IO/Readers/WDC1Reader.cs index 673f7ab..fc030f4 100644 --- a/DBCD.IO/Readers/WDC1Reader.cs +++ b/DBCD.IO/Readers/WDC1Reader.cs @@ -42,18 +42,28 @@ public WDC1Row(BaseReader reader, BitReader data, int id, int refID, int recordI Id = id; } - private static Dictionary, Dictionary, BaseReader, object>> simpleReaders = new Dictionary, Dictionary, BaseReader, object>> + private static class SingleReaderCache { - [typeof(long)] = (id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(float)] = (id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(int)] = (id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(uint)] = (id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(short)] = (id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(ushort)] = (id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(sbyte)] = (id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(byte)] = (id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(string)] = (id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => header.Flags.HasFlagExt(DB2Flags.Sparse) ? data.ReadCString() : stringTable[GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)], - }; + public static readonly Dictionary, int, BitReader, FieldMetaData, ColumnMetaData, Value32[], Dictionary, Dictionary, BaseReader>> Readers = new() + { + { typeof(ulong), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(long), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(float), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(uint), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(int), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(ushort), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(short), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(byte), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(sbyte), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(string), (record, info, id, data, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : stringTable[GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)]; + info.Setter.SetObject(record, stringValue); + } + } + }; + } private static Dictionary, Dictionary, object>> arrayReaders = new Dictionary, Dictionary, object>> { @@ -86,35 +96,32 @@ public void GetFields(FieldCache[] fields, T entry) else Id = GetFieldValue(0, Data, m_fieldMeta[i], ColumnMeta[i], PalletData[i], CommonData[i]); - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; int fieldIndex = i - indexFieldOffSet; if (fieldIndex >= m_reader.Meta.Length) { - info.Setter(entry, Convert.ChangeType(m_refID, info.FieldType)); + info.Setter.SetObject(entry, Convert.ChangeType(m_refID, info.FieldType)); continue; } if (info.IsArray) { if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable); + info.Setter.SetObject(entry, reader(Data, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Id, Data, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Id, Data, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } @@ -195,7 +202,7 @@ private static T[] GetFieldValueArray(BitReader r, FieldMetaData fieldMeta, C throw new Exception(string.Format("Unexpected compression type {0}", columnMeta.CompressionType)); } - + public IDBRow Clone() { return (IDBRow)MemberwiseClone(); diff --git a/DBCD.IO/Readers/WDC2Reader.cs b/DBCD.IO/Readers/WDC2Reader.cs index fefd853..6b13364 100644 --- a/DBCD.IO/Readers/WDC2Reader.cs +++ b/DBCD.IO/Readers/WDC2Reader.cs @@ -44,30 +44,38 @@ public WDC2Row(BaseReader reader, BitReader data, int recordsOffset, int id, int Id = id; } - private static Dictionary, Dictionary, BaseReader, object>> simpleReaders = new Dictionary, Dictionary, BaseReader, object>> + private static class SingleReaderCache { - [typeof(ulong)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(long)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(float)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(int)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(uint)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(short)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(ushort)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(sbyte)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(byte)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(string)] = (id, data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => header.Flags.HasFlagExt(DB2Flags.Sparse) ? data.ReadCString() : - stringTable[(recordsOffset + data.Offset + (data.Position >> 3)) + GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)], - }; + public static readonly Dictionary, int, BitReader, int, FieldMetaData, ColumnMetaData, Value32[], Dictionary, Dictionary, BaseReader>> Readers = new() + { + { typeof(ulong), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(long), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(float), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(uint), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(int), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(ushort), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(short), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(byte), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(sbyte), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(string), (record, info, id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : stringTable[(recordOffset + data.Offset + (data.Position >> 3)) + GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)]; + info.Setter.SetObject(record, stringValue); + } + } + }; + } private static Dictionary, Dictionary, object>> arrayReaders = new Dictionary, Dictionary, object>> { [typeof(ulong[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), [typeof(long[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), [typeof(float[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), - [typeof(int[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), [typeof(uint[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), - [typeof(short[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), + [typeof(int[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), [typeof(ushort[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), + [typeof(short[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), [typeof(byte[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), [typeof(sbyte[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), [typeof(string[])] = (data, recordsOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueStringArray(data, fieldMeta, columnMeta, recordsOffset, stringTable), @@ -100,16 +108,18 @@ public void GetFields(FieldCache[] fields, T entry) Id = GetFieldValue(0, Data, m_fieldMeta[i], ColumnMeta[i], PalletData[i], CommonData[i]); } - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; int fieldIndex = i - indexFieldOffSet; if (fieldIndex >= m_reader.Meta.Length) { - info.Setter(entry, Convert.ChangeType(m_refID, info.FieldType)); + info.Setter.SetObject(entry, Convert.ChangeType(m_refID, info.FieldType)); continue; } @@ -122,19 +132,14 @@ public void GetFields(FieldCache[] fields, T entry) if (info.IsArray) { if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_recordsOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable); + info.Setter.SetObject(entry, reader(Data, m_recordsOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Id, Data, m_recordsOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Id, Data, m_recordsOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } @@ -236,7 +241,7 @@ private static string[] GetFieldValueStringArray(BitReader r, FieldMetaData fiel } throw new Exception(string.Format("Unexpected compression type {0}", columnMeta.CompressionType)); } - + public IDBRow Clone() { return (IDBRow)MemberwiseClone(); diff --git a/DBCD.IO/Readers/WDC3Reader.cs b/DBCD.IO/Readers/WDC3Reader.cs index e09d1ab..426a76b 100644 --- a/DBCD.IO/Readers/WDC3Reader.cs +++ b/DBCD.IO/Readers/WDC3Reader.cs @@ -44,21 +44,6 @@ public WDC3Row(BaseReader reader, BitReader data, int id, int refID, int recordI Id = id; } - private static Dictionary, Dictionary, BaseReader, object>> simpleReaders = new Dictionary, Dictionary, BaseReader, object>> - { - [typeof(ulong)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(long)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(float)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(int)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(uint)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(short)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(ushort)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(sbyte)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(byte)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(string)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => header.Flags.HasFlagExt(DB2Flags.Sparse) ? data.ReadCString() : - getStringTableRecord(stringTable, recordOffset, id, data, fieldMeta, columnMeta, palletData, commonData), - }; - private static string getStringTableRecord(Dictionary stringTable, int recordOffset, int id, BitReader data, FieldMetaData fieldMeta, ColumnMetaData columnMeta, Value32[] palletData, Dictionary commonData) { var index = recordOffset + (data.Position >> 3) + GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData); @@ -70,6 +55,29 @@ private static string getStringTableRecord(Dictionary stringTable, return stringTable[index]; } + private static class SingleReaderCache + { + public static readonly Dictionary, int, BitReader, int, FieldMetaData, ColumnMetaData, Value32[], Dictionary, Dictionary, BaseReader>> Readers = new() + { + { typeof(ulong), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(long), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(float), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(uint), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(int), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(ushort), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(short), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(byte), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(sbyte), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(string), (record, info, id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : getStringTableRecord(stringTable, recordOffset, id, data, fieldMeta, columnMeta, palletData, commonData); + info.Setter.SetObject(record, stringValue); + } + } + }; + } + private static Dictionary, Dictionary, object>> arrayReaders = new Dictionary, Dictionary, object>> { [typeof(ulong[])] = (data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), @@ -101,35 +109,32 @@ public void GetFields(FieldCache[] fields, T entry) else Id = GetFieldValue(0, Data, m_fieldMeta[i], ColumnMeta[i], PalletData[i], CommonData[i]); - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - - object value = null; + int fieldIndex = i - indexFieldOffSet; if (fieldIndex >= m_reader.Meta.Length) { - info.Setter(entry, Convert.ChangeType(m_refID, info.FieldType)); + info.Setter.SetObject(entry, Convert.ChangeType(m_refID, info.FieldType)); continue; } if (info.IsArray) { if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable); + info.Setter.SetObject(entry, reader(Data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Id, Data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Id, Data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } @@ -236,7 +241,7 @@ private static string[] GetFieldValueStringArray(BitReader r, FieldMetaData fiel throw new Exception(string.Format("Unexpected compression type {0}", columnMeta.CompressionType)); } - + public IDBRow Clone() { return (IDBRow)MemberwiseClone(); diff --git a/DBCD.IO/Readers/WDC4Reader.cs b/DBCD.IO/Readers/WDC4Reader.cs index 3fa0a4f..1d5916e 100644 --- a/DBCD.IO/Readers/WDC4Reader.cs +++ b/DBCD.IO/Readers/WDC4Reader.cs @@ -44,21 +44,6 @@ public WDC4Row(BaseReader reader, BitReader data, int id, int refID, int recordI Id = id; } - private static Dictionary, Dictionary, BaseReader, object>> simpleReaders = new Dictionary, Dictionary, BaseReader, object>> - { - [typeof(ulong)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(long)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(float)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(int)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(uint)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(short)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(ushort)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(sbyte)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(byte)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(string)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => header.Flags.HasFlagExt(DB2Flags.Sparse) ? data.ReadCString() : - getStringTableRecord(stringTable, recordOffset, id, data, fieldMeta, columnMeta, palletData, commonData), - }; - private static string getStringTableRecord(Dictionary stringTable, int recordOffset, int id, BitReader data, FieldMetaData fieldMeta, ColumnMetaData columnMeta, Value32[] palletData, Dictionary commonData) { var index = recordOffset + (data.Position >> 3) + GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData); @@ -70,6 +55,29 @@ private static string getStringTableRecord(Dictionary stringTable, return stringTable[index]; } + private static class SingleReaderCache + { + public static readonly Dictionary, int, BitReader, int, FieldMetaData, ColumnMetaData, Value32[], Dictionary, Dictionary, BaseReader>> Readers = new() + { + { typeof(ulong), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(long), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(float), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(uint), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(int), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(ushort), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(short), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(byte), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(sbyte), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(string), (record, info, id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : getStringTableRecord(stringTable, recordOffset, id, data, fieldMeta, columnMeta, palletData, commonData); + info.Setter.SetObject(record, stringValue); + } + } + }; + } + private static Dictionary, Dictionary, object>> arrayReaders = new Dictionary, Dictionary, object>> { [typeof(ulong[])] = (data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), @@ -101,35 +109,32 @@ public void GetFields(FieldCache[] fields, T entry) else Id = GetFieldValue(0, Data, m_fieldMeta[i], ColumnMeta[i], PalletData[i], CommonData[i]); - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; int fieldIndex = i - indexFieldOffSet; if (fieldIndex >= m_reader.Meta.Length) { - info.Setter(entry, Convert.ChangeType(m_refID, info.FieldType)); + info.Setter.SetObject(entry, Convert.ChangeType(m_refID, info.FieldType)); continue; } if (info.IsArray) { if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable); + info.Setter.SetObject(entry, reader(Data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Id, Data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Id, Data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } @@ -236,7 +241,7 @@ private static string[] GetFieldValueStringArray(BitReader r, FieldMetaData fiel throw new Exception(string.Format("Unexpected compression type {0}", columnMeta.CompressionType)); } - + public IDBRow Clone() { return (IDBRow)MemberwiseClone(); diff --git a/DBCD.IO/Readers/WDC5Reader.cs b/DBCD.IO/Readers/WDC5Reader.cs index 5039071..235cf76 100644 --- a/DBCD.IO/Readers/WDC5Reader.cs +++ b/DBCD.IO/Readers/WDC5Reader.cs @@ -44,22 +44,7 @@ public WDC5Row(BaseReader reader, BitReader data, int id, int refID, int recordI Id = id; } - - private static Dictionary, Dictionary, BaseReader, object>> simpleReaders = new Dictionary, Dictionary, BaseReader, object>> - { - [typeof(ulong)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(long)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(float)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(int)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(uint)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(short)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(ushort)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(sbyte)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(byte)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData), - [typeof(string)] = (id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => header.Flags.HasFlagExt(DB2Flags.Sparse) ? data.ReadCString() : - getStringTableRecord(stringTable, recordOffset, id, data, fieldMeta, columnMeta, palletData, commonData), - }; - + private static string getStringTableRecord(Dictionary stringTable, int recordOffset, int id, BitReader data, FieldMetaData fieldMeta, ColumnMetaData columnMeta, Value32[] palletData, Dictionary commonData) { var index = recordOffset + (data.Position >> 3) + GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData); @@ -71,6 +56,29 @@ private static string getStringTableRecord(Dictionary stringTable, return stringTable[index]; } + private static class SingleReaderCache + { + public static readonly Dictionary, int, BitReader, int, FieldMetaData, ColumnMetaData, Value32[], Dictionary, Dictionary, BaseReader>> Readers = new() + { + { typeof(ulong), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(long), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(float), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(uint), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(int), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(ushort), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(short), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(byte), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(sbyte), (record, info, id, data, _, fieldMeta, columnMeta, palletData, commonData, _, _) => info.Setter.SetValue(record, GetFieldValue(id, data, fieldMeta, columnMeta, palletData, commonData)) }, + { typeof(string), (record, info, id, data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable, header) => + { + string stringValue = header.Flags.HasFlagExt(DB2Flags.Sparse) ? + data.ReadCString() : getStringTableRecord(stringTable, recordOffset, id, data, fieldMeta, columnMeta, palletData, commonData); + info.Setter.SetObject(record, stringValue); + } + } + }; + } + private static Dictionary, Dictionary, object>> arrayReaders = new Dictionary, Dictionary, object>> { [typeof(ulong[])] = (data, recordOffset, fieldMeta, columnMeta, palletData, commonData, stringTable) => GetFieldValueArray(data, fieldMeta, columnMeta, palletData, commonData), @@ -102,35 +110,32 @@ public void GetFields(FieldCache[] fields, T entry) else Id = GetFieldValue(0, m_data, m_fieldMeta[i], ColumnMeta[i], PalletData[i], CommonData[i]); - info.Setter(entry, Convert.ChangeType(Id, info.FieldType)); + if (info.FieldType == typeof(int)) + info.Setter.SetValue(entry, Id); + else + info.Setter.SetObject(entry, Convert.ChangeType(Id, info.FieldType)); continue; } - object value = null; int fieldIndex = i - indexFieldOffSet; if (fieldIndex >= m_reader.Meta.Length) { - info.Setter(entry, Convert.ChangeType(m_refID, info.FieldType)); + info.Setter.SetObject(entry, Convert.ChangeType(m_refID, info.FieldType)); continue; } if (info.IsArray) { if (arrayReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(m_data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable); + info.Setter.SetObject(entry, reader(m_data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable)); else throw new Exception("Unhandled array type: " + typeof(T).Name); } + else if (SingleReaderCache.Readers.TryGetValue(info.FieldType, out var reader)) + reader(entry, info, Id, m_data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); else - { - if (simpleReaders.TryGetValue(info.FieldType, out var reader)) - value = reader(Id, m_data, m_recordOffset, m_fieldMeta[fieldIndex], ColumnMeta[fieldIndex], PalletData[fieldIndex], CommonData[fieldIndex], m_reader.StringTable, m_reader); - else - throw new Exception("Unhandled field type: " + typeof(T).Name); - } - - info.Setter(entry, value); + throw new Exception("Unhandled field type: " + typeof(T).Name); } } @@ -237,7 +242,7 @@ private static string[] GetFieldValueStringArray(BitReader r, FieldMetaData fiel throw new Exception(string.Format("Unexpected compression type {0}", columnMeta.CompressionType)); } - + public IDBRow Clone() { return (IDBRow)MemberwiseClone();