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.Linq;
using System.Runtime.InteropServices;
using UniJSON;
using Unity.Collections;
namespace UniGLTF
@ -32,7 +33,7 @@ namespace UniGLTF
/// JSON chunk ToString
/// > This chunk MUST be the very first chunk of Binary glTF asset
/// </summary>
public string Json { get; }
public string Json => _jsonString ??= _utf8JsonString.ToString();
/// <summary>
/// GLTF parsed from JSON chunk
@ -72,10 +73,39 @@ namespace UniGLTF
/// <returns></returns>
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)
{
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;
Chunks = chunks;
_storage = storage;
@ -441,4 +471,4 @@ namespace UniGLTF
return false;
}
}
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UniJSON;
@ -33,7 +32,7 @@ namespace UniGLTF
var jsonBytes = chunks[0].Bytes;
return ParseGltf(
_path,
Encoding.UTF8.GetString(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count),
new Utf8String(new ArraySegment<byte>(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count)),
chunks,
default,
new MigrationFlags()
@ -73,14 +72,20 @@ namespace UniGLTF
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")
{
throw new UniGLTFException("unknown gltf version {0}", GLTF.asset.version);
}
// Version Compatibility
RestoreOlderVersionValues(json, GLTF);
RestoreOlderVersionValues(parsedJson, GLTF);
FixMeshNameUnique(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)
{
if (string.IsNullOrEmpty(GLTF.images[i].name))

View File

@ -395,6 +395,28 @@ namespace UniJSON
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)
{
var sb = new StringBuilder();
@ -430,18 +452,9 @@ namespace UniJSON
public static Utf8String Unquote(Utf8String src)
{
var count = Unquote(src, null);
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);
}
return Unescape(src.Subbytes(1, src.ByteLength - 2));
}
#endregion
}
}
}

View File

@ -101,7 +101,7 @@ namespace UniJSON
public UInt64 GetUInt64() { return Segment.ToUInt64(); }
public Single GetSingle() { return Segment.ToSingle(); }
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); }
}
}
}

View File

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

View File

@ -1,5 +1,7 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@ -320,11 +322,46 @@ namespace UniJSON
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)
{
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)