Refactor deserialization property cache construction
Move CacheMap building to dedicated method for efficiency. Remove incremental cache logic and SourceHashes field. Simplify property population and update documentation. Improves performance and code clarity.
This commit is contained in:
parent
cd3d65b5f4
commit
097c1e8efe
|
|
@ -57,10 +57,8 @@ public static partial class AcBinaryDeserializer
|
|||
|
||||
/// <summary>
|
||||
/// Unified property populate for both UseMetadata and non-UseMetadata modes.
|
||||
/// UseMetadata=false: properties[i] gives the setter directly (same-type, index-based).
|
||||
/// UseMetadata=true: cacheMap[i] gives the setter. If null (first object of this type),
|
||||
/// fast path checks props[index+1], fallback searches from props[index+2].
|
||||
/// index tracks last matched target property index (starts at -1).
|
||||
/// UseMetadata=true: cacheMap[i] gives the setter (null → skip).
|
||||
/// UseMetadata=false: properties[i] gives the setter directly.
|
||||
/// </summary>
|
||||
private static void PopulateObjectPropertiesIndexed(
|
||||
ref BinaryDeserializationContext context,
|
||||
|
|
@ -78,51 +76,10 @@ public static partial class AcBinaryDeserializer
|
|||
// UseMetadata: cacheMap.Length a source property-k száma
|
||||
// Non-UseMetadata: properties.Length a target property-k száma (source == target)
|
||||
var propCount = cacheMap?.Length ?? properties.Length;
|
||||
var sourceHashes = wrapper.SourceHashes; // only non-null when cacheMap != null
|
||||
var index = -1; // last matched target property index (for incremental CacheMap building)
|
||||
|
||||
for (int i = 0; i < propCount; i++)
|
||||
{
|
||||
BinaryPropertySetterBase? propInfo;
|
||||
|
||||
if (cacheMap != null)
|
||||
{
|
||||
// UseMetadata mode
|
||||
propInfo = cacheMap[i];
|
||||
if (propInfo == null && sourceHashes != null)
|
||||
{
|
||||
// First object of this type — inkrementális CacheMap felépítés
|
||||
var hash = sourceHashes[i];
|
||||
|
||||
// Fast path: props[index+1] (same-type → next property in order)
|
||||
var nextIdx = index + 1;
|
||||
if (nextIdx < properties.Length && properties[nextIdx].PropertyNameHash == hash)
|
||||
{
|
||||
propInfo = properties[nextIdx];
|
||||
index = nextIdx;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: search from index+2 (cross-type, alphabetical order → forward only)
|
||||
for (var j = nextIdx + 1; j < properties.Length; j++)
|
||||
{
|
||||
if (properties[j].PropertyNameHash == hash)
|
||||
{
|
||||
propInfo = properties[j];
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cacheMap[i] = propInfo; // null marad ha nincs match → skip next time too
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-UseMetadata: direct index-based
|
||||
propInfo = properties[i];
|
||||
}
|
||||
var propInfo = cacheMap != null ? cacheMap[i] : properties[i];
|
||||
|
||||
var peekCode = context.PeekByte();
|
||||
|
||||
|
|
@ -224,10 +181,6 @@ public static partial class AcBinaryDeserializer
|
|||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
// CacheMap kész — sourceHashes null-ra, hogy a következő objektumnál ne keressen újra
|
||||
if (sourceHashes != null)
|
||||
wrapper.SourceHashes = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1058,12 +1058,9 @@ public static partial class AcBinaryDeserializer
|
|||
context.RegisterInternedValue(instance, streamPosition);
|
||||
}
|
||||
|
||||
// CacheMap + SourceHashes a wrapper-en (per-context, futásonként változhat)
|
||||
// CacheMap felépítése ha még nincs (1x per target type × source type kombináció)
|
||||
if (wrapper.CacheMap == null)
|
||||
{
|
||||
wrapper.CacheMap = new BinaryPropertySetterBase?[sourceHashes.Length];
|
||||
wrapper.SourceHashes = sourceHashes;
|
||||
}
|
||||
BuildCacheMap(wrapper, sourceHashes);
|
||||
|
||||
PopulateObject(ref context, instance, wrapper, depth, skipDefaultWrite: true);
|
||||
|
||||
|
|
@ -1108,10 +1105,41 @@ public static partial class AcBinaryDeserializer
|
|||
|
||||
var wrapper = context.ContextClass.GetWrapper(targetType);
|
||||
if (wrapper.CacheMap == null)
|
||||
BuildCacheMap(wrapper, sourceHashes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CacheMap felépítése: source property hash-ek → target PropertySetter mapping.
|
||||
/// Fast path: same-type esetén props[index+1] egyezik. Cross-type: keresés index+1-től.
|
||||
/// </summary>
|
||||
private static void BuildCacheMap(TypeMetadataWrapper<BinaryDeserializeTypeMetadata> wrapper, int[] sourceHashes)
|
||||
{
|
||||
var properties = wrapper.Metadata.PropertiesArray;
|
||||
var cacheMap = new BinaryPropertySetterBase?[sourceHashes.Length];
|
||||
var index = -1;
|
||||
for (var i = 0; i < sourceHashes.Length; i++)
|
||||
{
|
||||
wrapper.CacheMap = new BinaryPropertySetterBase?[sourceHashes.Length];
|
||||
wrapper.SourceHashes = sourceHashes;
|
||||
var hash = sourceHashes[i];
|
||||
var nextIdx = index + 1;
|
||||
if (nextIdx < properties.Length && properties[nextIdx].PropertyNameHash == hash)
|
||||
{
|
||||
cacheMap[i] = properties[nextIdx];
|
||||
index = nextIdx;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var j = nextIdx; j < properties.Length; j++)
|
||||
{
|
||||
if (properties[j].PropertyNameHash == hash)
|
||||
{
|
||||
cacheMap[i] = properties[j];
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
wrapper.CacheMap = cacheMap;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -46,16 +46,10 @@ public sealed class TypeMetadataWrapper<TMetadata> where TMetadata : TypeMetadat
|
|||
/// <summary>
|
||||
/// UseMetadata cachemap: source property index → target PropertySetter.
|
||||
/// Per-context (wrapper-szintű), mert futásonként eltérő source type-pal találkozhat.
|
||||
/// Inkrementálisan épül a PopulateObjectPropertiesIndexed-ben.
|
||||
/// Felépül a ReadObjectWithMetadata-ban, első előforduláskor.
|
||||
/// </summary>
|
||||
internal BinaryPropertySetterBase?[]? CacheMap;
|
||||
|
||||
/// <summary>
|
||||
/// Source property hash-ek a CacheMap-hez — az inline metadata-ból olvasva.
|
||||
/// Per-context, mert eltérő source type-pal más hash-ek jönnek.
|
||||
/// </summary>
|
||||
internal int[]? SourceHashes;
|
||||
|
||||
#region Typed IdentityMaps - No generic type checks in hot path!
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -133,7 +127,6 @@ public sealed class TypeMetadataWrapper<TMetadata> where TMetadata : TypeMetadat
|
|||
{
|
||||
MetadataFooterIndex = -1;
|
||||
CacheMap = null;
|
||||
SourceHashes = null;
|
||||
|
||||
if (SmallIdBitmap != null)
|
||||
Array.Clear(SmallIdBitmap);
|
||||
|
|
|
|||
Loading…
Reference in New Issue