Merge pull request #2744 from Akeit0/optimize-parser

Optimize Glb parser
This commit is contained in:
ousttrue 2025-11-21 16:02:05 +09:00 committed by GitHub
commit 82e4f707f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 112 additions and 26 deletions

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UniJSON;
using Unity.Collections; using Unity.Collections;
namespace UniGLTF namespace UniGLTF
@ -32,7 +33,7 @@ namespace UniGLTF
/// JSON chunk ToString /// JSON chunk ToString
/// > This chunk MUST be the very first chunk of Binary glTF asset /// > This chunk MUST be the very first chunk of Binary glTF asset
/// </summary> /// </summary>
public string Json { get; } public string Json => _jsonString ??= _utf8JsonString.ToString();
/// <summary> /// <summary>
/// GLTF parsed from JSON chunk /// GLTF parsed from JSON chunk
@ -72,10 +73,39 @@ namespace UniGLTF
/// <returns></returns> /// <returns></returns>
Dictionary<string, NativeArray<byte>> _UriCache = new Dictionary<string, NativeArray<byte>>(); Dictionary<string, NativeArray<byte>> _UriCache = new Dictionary<string, NativeArray<byte>>();
/// <summary>
/// json string in utf8
/// </summary>
Utf8String _utf8JsonString;
/// <summary>
/// json string cache
/// </summary>
string _jsonString;
public GltfData(string targetPath, string json, glTF gltf, IReadOnlyList<GlbChunk> chunks, IStorage storage, MigrationFlags migrationFlags) public GltfData(string targetPath, string json, glTF gltf, IReadOnlyList<GlbChunk> chunks, IStorage storage, MigrationFlags migrationFlags)
{ {
TargetPath = targetPath; TargetPath = targetPath;
Json = json; _jsonString = json;
GLTF = gltf;
Chunks = chunks;
_storage = storage;
MigrationFlags = migrationFlags;
// init
if (Chunks != null)
{
if (Chunks.Count >= 2)
{
Bin = NativeArrayManager.CreateNativeArray(Chunks[1].Bytes);
}
}
}
internal GltfData(string targetPath, Utf8String jsonString, glTF gltf, IReadOnlyList<GlbChunk> chunks, IStorage storage, MigrationFlags migrationFlags)
{
TargetPath = targetPath;
_utf8JsonString = jsonString;
GLTF = gltf; GLTF = gltf;
Chunks = chunks; Chunks = chunks;
_storage = storage; _storage = storage;
@ -441,4 +471,4 @@ namespace UniGLTF
return false; return false;
} }
} }
} }

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using UniJSON; using UniJSON;
@ -33,7 +32,7 @@ namespace UniGLTF
var jsonBytes = chunks[0].Bytes; var jsonBytes = chunks[0].Bytes;
return ParseGltf( return ParseGltf(
_path, _path,
Encoding.UTF8.GetString(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count), new Utf8String(new ArraySegment<byte>(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count)),
chunks, chunks,
default, default,
new MigrationFlags() new MigrationFlags()
@ -73,14 +72,20 @@ namespace UniGLTF
public static GltfData ParseGltf(string path, string json, IReadOnlyList<GlbChunk> chunks, IStorage storage, MigrationFlags migrationFlags) public static GltfData ParseGltf(string path, string json, IReadOnlyList<GlbChunk> chunks, IStorage storage, MigrationFlags migrationFlags)
{ {
var GLTF = GltfDeserializer.Deserialize(json.ParseAsJson()); return ParseGltf(path, Utf8String.From(json), chunks, storage, migrationFlags);
}
internal static GltfData ParseGltf(string path, Utf8String json, IReadOnlyList<GlbChunk> chunks, IStorage storage, MigrationFlags migrationFlags)
{
var parsedJson = json.ParseAsJson();
var GLTF = GltfDeserializer.Deserialize(parsedJson);
if (GLTF.asset.version != "2.0") if (GLTF.asset.version != "2.0")
{ {
throw new UniGLTFException("unknown gltf version {0}", GLTF.asset.version); throw new UniGLTFException("unknown gltf version {0}", GLTF.asset.version);
} }
// Version Compatibility // Version Compatibility
RestoreOlderVersionValues(json, GLTF); RestoreOlderVersionValues(parsedJson, GLTF);
FixMeshNameUnique(GLTF); FixMeshNameUnique(GLTF);
FixBlendShapeNameUnique(GLTF); FixBlendShapeNameUnique(GLTF);
@ -298,9 +303,8 @@ namespace UniGLTF
} }
} }
private static void RestoreOlderVersionValues(string Json, glTF GLTF) private static void RestoreOlderVersionValues(JsonNode parsed, glTF GLTF)
{ {
var parsed = UniJSON.JsonParser.Parse(Json);
for (int i = 0; i < GLTF.images.Count; ++i) for (int i = 0; i < GLTF.images.Count; ++i)
{ {
if (string.IsNullOrEmpty(GLTF.images[i].name)) if (string.IsNullOrEmpty(GLTF.images[i].name))

View File

@ -395,6 +395,28 @@ namespace UniJSON
return writeCount; return writeCount;
} }
private static Utf8String Unescape(Utf8String s)
{
var span = s.AsSpan();
var escapeIndex = span.IndexOf((byte)'\\');
// escape not found
if (escapeIndex == -1)
{
return s;
}
var sb = new BytesStore(s.ByteLength);
foreach (var b in span[..escapeIndex])
{
sb.Write(b);
}
Unescape(s.Subbytes(escapeIndex), sb);
return new Utf8String(sb.Bytes);
}
public static string Unescape(string src) public static string Unescape(string src)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
@ -430,18 +452,9 @@ namespace UniJSON
public static Utf8String Unquote(Utf8String src) public static Utf8String Unquote(Utf8String src)
{ {
var count = Unquote(src, null); return Unescape(src.Subbytes(1, src.ByteLength - 2));
if (count == src.ByteLength - 2)
{
return src.Subbytes(1, src.ByteLength - 2);
}
else
{
var sb = new BytesStore(count);
Unquote(src, sb);
return new Utf8String(sb.Bytes);
}
} }
#endregion #endregion
} }
} }

View File

@ -101,7 +101,7 @@ namespace UniJSON
public UInt64 GetUInt64() { return Segment.ToUInt64(); } public UInt64 GetUInt64() { return Segment.ToUInt64(); }
public Single GetSingle() { return Segment.ToSingle(); } public Single GetSingle() { return Segment.ToSingle(); }
public Double GetDouble() { return Segment.ToDouble(); } public Double GetDouble() { return Segment.ToDouble(); }
public String GetString() { return JsonString.Unquote(Segment.ToString()); } public String GetString() { return JsonString.Unquote(Segment).ToString(); }
public Utf8String GetUtf8String() { return JsonString.Unquote(Segment); } public Utf8String GetUtf8String() { return JsonString.Unquote(Segment); }
} }
} }

View File

@ -110,6 +110,8 @@ namespace UniJSON
return new Utf8String(bytes); return new Utf8String(bytes);
} }
public ReadOnlySpan<byte> AsSpan() => Bytes.AsSpan();
public override string ToString() public override string ToString()
{ {
if (ByteLength == 0) return ""; if (ByteLength == 0) return "";
@ -324,4 +326,4 @@ namespace UniJSON
} }
} }
} }
} }

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
@ -320,11 +322,46 @@ namespace UniJSON
public static float ToSingle(this Utf8String src) public static float ToSingle(this Utf8String src)
{ {
return Single.Parse(src.ToAscii(), System.Globalization.CultureInfo.InvariantCulture); char[] arrayToReturn = null;
try
{
var srcBytes = src.AsSpan();
Span<char> chars = srcBytes.Length < 64
? stackalloc char[srcBytes.Length]
: arrayToReturn = ArrayPool<char>.Shared.Rent(srcBytes.Length);
var count = System.Text.Encoding.ASCII.GetChars(srcBytes, chars);
return Single.Parse(chars[..count], NumberStyles.Float | NumberStyles.AllowThousands,
System.Globalization.CultureInfo.InvariantCulture);
}
finally
{
if (arrayToReturn != null)
{
ArrayPool<char>.Shared.Return(arrayToReturn);
}
}
} }
public static double ToDouble(this Utf8String src) public static double ToDouble(this Utf8String src)
{ {
return Double.Parse(src.ToAscii(), System.Globalization.CultureInfo.InvariantCulture); char[] arrayToReturn = null;
try
{
var srcBytes = src.AsSpan();
Span<char> chars = srcBytes.Length < 64
? stackalloc char[srcBytes.Length]
: arrayToReturn = ArrayPool<char>.Shared.Rent(srcBytes.Length);
var count = System.Text.Encoding.ASCII.GetChars(srcBytes, chars);
return Double.Parse(chars[..count], NumberStyles.Float | NumberStyles.AllowThousands,
System.Globalization.CultureInfo.InvariantCulture);
}
finally
{
if (arrayToReturn != null)
{
ArrayPool<char>.Shared.Return(arrayToReturn);
}
}
} }
public static Utf8String GetLine(this Utf8String src) public static Utf8String GetLine(this Utf8String src)