diff --git a/Assets/UniGLTF/Runtime/Extensions/StringExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/StringExtensions.cs index 92dbdbb7e..62e3b7170 100644 --- a/Assets/UniGLTF/Runtime/Extensions/StringExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/StringExtensions.cs @@ -35,13 +35,13 @@ namespace UniGLTF public static bool StartsWithUnityAssetPath(this string path) { - return path.Replace("\\", "/").StartsWith(UnityBasePath + "/Assets"); + return path.Replace("\\", "/").FastStartsWith(UnityBasePath + "/Assets"); } public static string ToUnityRelativePath(this string path) { path = path.Replace("\\", "/"); - if (path.StartsWith(UnityBasePath)) + if (path.FastStartsWith(UnityBasePath)) { return path.Substring(UnityBasePath.Length + 1); } @@ -72,5 +72,42 @@ namespace UniGLTF } return path; } + + // https://docs.unity3d.com/Manual/BestPracticeUnderstandingPerformanceInUnity5.html + public static bool FastStartsWith(this string a, string b) + { + var aLen = a.Length; + var bLen = b.Length; + if (aLen < bLen) + { + return false; + } + + var p = 0; + while (p < bLen && a[p] == b[p]) + { + ++p; + } + + return p == bLen; + } + + public static bool FastEndsWith(this string a, string b) + { + var aLen = a.Length; + var bLen = b.Length; + if (aLen < bLen) + { + return false; + } + + var p = 1; + while (p <= bLen && a[aLen - p] == b[bLen - p]) + { + ++p; + } + + return p - 1 == bLen; + } } } diff --git a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs index 526706773..e93568cd3 100644 --- a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs @@ -368,7 +368,7 @@ namespace UniGLTF } else { - if (image.uri.StartsWith("data:")) + if (image.uri.FastStartsWith("data:")) { textureName = !string.IsNullOrEmpty(image.name) ? image.name : string.Format("{0:00}#Base64Embedded", imageIndex); } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs b/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs index 20d3a8be2..b04b2549c 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs @@ -58,11 +58,11 @@ namespace UniGLTF return ".jpg"; default: - if (uri.StartsWith("data:image/jpeg;")) + if (uri.FastStartsWith("data:image/jpeg;")) { return ".jpg"; } - else if (uri.StartsWith("data:image/png;")) + else if (uri.FastStartsWith("data:image/png;")) { return ".png"; } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationExporter.cs index d30c21378..4a55e5d64 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationExporter.cs @@ -65,23 +65,23 @@ namespace UniGLTF public static glTFAnimationTarget.AnimationProperties PropertyToTarget(string property) { - if (property.StartsWith("m_LocalPosition.")) + if (property.FastStartsWith("m_LocalPosition.")) { return glTFAnimationTarget.AnimationProperties.Translation; } - else if (property.StartsWith("localEulerAnglesRaw.")) + else if (property.FastStartsWith("localEulerAnglesRaw.")) { return glTFAnimationTarget.AnimationProperties.EulerRotation; } - else if (property.StartsWith("m_LocalRotation.")) + else if (property.FastStartsWith("m_LocalRotation.")) { return glTFAnimationTarget.AnimationProperties.Rotation; } - else if (property.StartsWith("m_LocalScale.")) + else if (property.FastStartsWith("m_LocalScale.")) { return glTFAnimationTarget.AnimationProperties.Scale; } - else if (property.StartsWith("blendShape.")) + else if (property.FastStartsWith("blendShape.")) { return glTFAnimationTarget.AnimationProperties.BlendShape; } @@ -97,7 +97,7 @@ namespace UniGLTF { return 0; } - if (property.EndsWith(".y") || property.StartsWith("blendShape.")) + if (property.EndsWith(".y") || property.FastStartsWith("blendShape.")) { return 1; } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/FileSystemStorage.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/FileSystemStorage.cs index c2c07932b..99961fea8 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/FileSystemStorage.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/FileSystemStorage.cs @@ -39,7 +39,7 @@ namespace UniGLTF public ArraySegment Get(string url) { var bytes = - (url.StartsWith("data:")) + (url.FastStartsWith("data:")) ? UriByteBuffer.ReadEmbedded(url) : File.ReadAllBytes(Path.Combine(m_root, url)) ; @@ -48,7 +48,7 @@ namespace UniGLTF public string GetPath(string url) { - if (url.StartsWith("data:")) + if (url.FastStartsWith("data:")) { return null; } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 906cdeba6..d32b9af49 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -165,7 +165,7 @@ namespace UniGLTF { if (string.IsNullOrEmpty(generatorVersion)) return false; if (generatorVersion == "UniGLTF") return true; - if (!generatorVersion.StartsWith("UniGLTF-")) return false; + if (!generatorVersion.FastStartsWith("UniGLTF-")) return false; try { @@ -475,7 +475,7 @@ namespace UniGLTF var image = GLTF.GetImageFromTextureIndex(i); if (imageBaseDir.IsUnderAssetsFolder && !string.IsNullOrEmpty(image.uri) - && !image.uri.StartsWith("data:") + && !image.uri.FastStartsWith("data:") ) { /// diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs index 9a4cebe0d..11cccb200 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs @@ -40,7 +40,7 @@ namespace UniGLTF { return false; } - return Value == "Assets" || Value.StartsWith("Assets/"); + return Value == "Assets" || Value.FastStartsWith("Assets/"); } } @@ -53,7 +53,7 @@ namespace UniGLTF return false; } - return FullPath.StartsWith(Application.streamingAssetsPath + "/"); + return FullPath.FastStartsWith(Application.streamingAssetsPath + "/"); } } @@ -276,7 +276,7 @@ namespace UniGLTF Value = "" }; } - else if (fullPath.StartsWith(BaseFullPath + "/")) + else if (fullPath.FastStartsWith(BaseFullPath + "/")) { return new UnityPath(fullPath.Substring(BaseFullPath.Length + 1)); } @@ -288,7 +288,7 @@ namespace UniGLTF public static bool IsUnderAssetFolder(string fullPath) { - return fullPath.Replace("\\", "/").StartsWith(AssetFullPath); + return fullPath.Replace("\\", "/").FastStartsWith(AssetFullPath); } #endregion diff --git a/Assets/VRM/Runtime/IO/VRMImporterContext.cs b/Assets/VRM/Runtime/IO/VRMImporterContext.cs index 5c018092f..4bb9f6c6c 100644 --- a/Assets/VRM/Runtime/IO/VRMImporterContext.cs +++ b/Assets/VRM/Runtime/IO/VRMImporterContext.cs @@ -150,7 +150,7 @@ namespace VRM var asset = ScriptableObject.CreateInstance(); var groupName = group.name; var prefix = "BlendShape."; - while (groupName.StartsWith(prefix)) + while (groupName.FastStartsWith(prefix)) { groupName = groupName.Substring(prefix.Length); } @@ -195,8 +195,8 @@ namespace VRM var material = GetMaterials().FirstOrDefault(y => y.name == x.materialName); var propertyName = x.propertyName; - if (x.propertyName.EndsWith("_ST_S") - || x.propertyName.EndsWith("_ST_T")) + if (x.propertyName.FastEndsWith("_ST_S") + || x.propertyName.FastEndsWith("_ST_T")) { propertyName = x.propertyName.Substring(0, x.propertyName.Length - 2); }